From b64fab65cc7696754f14b7c0098feca8f9fd654e Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Thu, 5 Jan 2023 16:44:39 -0800 Subject: [PATCH] [ip6] simplify `SelectSourceAddress()` (#8615) 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. --- src/core/api/ip6_api.cpp | 10 +-- src/core/net/ip6.cpp | 131 ++++++++++++++++++++------------------- src/core/net/ip6.hpp | 21 +++++-- src/core/net/tcp6.cpp | 11 ++-- 4 files changed, 88 insertions(+), 85 deletions(-) diff --git a/src/core/api/ip6_api.cpp b/src/core/api/ip6_api.cpp index c8d98efc2..18769f7d0 100644 --- a/src/core/api/ip6_api.cpp +++ b/src/core/api/ip6_api.cpp @@ -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().SelectSourceAddress(AsCoreType(aMessageInfo)); - VerifyOrExit(netifAddr != nullptr, error = kErrorNotFound); - aMessageInfo->mSockAddr = netifAddr->GetAddress(); - -exit: - return error; + return AsCoreType(aInstance).Get().SelectSourceAddress(AsCoreType(aMessageInfo)); } #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE && OPENTHREAD_CONFIG_COMMISSIONER_ENABLE diff --git a/src/core/net/ip6.cpp b/src/core/net/ip6.cpp index 41ff5d9f7..e28a6efb2 100644 --- a/src/core/net/ip6.cpp +++ b/src/core/net/ip6.cpp @@ -215,25 +215,23 @@ exit: 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(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)); @@ -242,7 +240,7 @@ exit: return error; } -Error Ip6::InsertMplOption(Message &aMessage, Header &aHeader, MessageInfo &aMessageInfo) +Error Ip6::InsertMplOption(Message &aMessage, Header &aHeader) { Error error = kErrorNone; @@ -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: @@ -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 { @@ -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()); @@ -1126,21 +1124,16 @@ exit: 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); @@ -1379,95 +1372,105 @@ bool Ip6::ShouldForwardToThread(const MessageInfo &aMessageInfo, MessageOrigin a return shouldForward; } -const Netif::UnicastAddress *Ip6::SelectSourceAddress(MessageInfo &aMessageInfo) +Error Ip6::SelectSourceAddress(MessageInfo &aMessageInfo) const { - Address *destination = &aMessageInfo.GetPeerAddr(); - uint8_t destinationScope = destination->GetScope(); - const bool destinationIsRoutingLocator = Get().IsRoutingLocator(*destination); - const Netif::UnicastAddress *rvalAddr = nullptr; - uint8_t rvalPrefixMatched = 0; + 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 +{ + uint8_t destScope = aDestination.GetScope(); + bool destIsRloc = Get().IsRoutingLocator(aDestination); + const Netif::UnicastAddress *bestAddr = nullptr; + uint8_t bestMatchLen = 0; for (const Netif::UnicastAddress &addr : Get().GetUnicastAddresses()) { - const Address *candidateAddr = &addr.GetAddress(); - uint8_t candidatePrefixMatched; - uint8_t overrideScope; + uint8_t matchLen; + uint8_t overrideScope; - if (Get().IsAnycastLocator(*candidateAddr)) + if (Get().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().IsRoutingLocator(*candidateAddr))) + else if ((matchLen == bestMatchLen) && (destIsRloc == Get().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 { @@ -1475,14 +1478,14 @@ const Netif::UnicastAddress *Ip6::SelectSourceAddress(MessageInfo &aMessageInfo) } // 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 diff --git a/src/core/net/ip6.hpp b/src/core/net/ip6.hpp index d6230a2e9..04879f3f5 100644 --- a/src/core/net/ip6.hpp +++ b/src/core/net/ip6.hpp @@ -310,14 +310,25 @@ public: 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. @@ -404,8 +415,8 @@ private: 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, diff --git a/src/core/net/tcp6.cpp b/src/core/net/tcp6.cpp index e8b6deb88..47c50278e 100644 --- a/src/core/net/tcp6.cpp +++ b/src/core/net/tcp6.cpp @@ -780,14 +780,11 @@ bool Tcp::AutoBind(const SockAddr &aPeer, SockAddr &aToBind, bool aBindAddress, if (aBindAddress) { - MessageInfo peerInfo; - const Netif::UnicastAddress *netifAddress; + const Address *source; - peerInfo.Clear(); - peerInfo.SetPeerAddr(aPeer.GetAddress()); - netifAddress = Get().SelectSourceAddress(peerInfo); - VerifyOrExit(netifAddress != nullptr, success = false); - aToBind.GetAddress() = netifAddress->GetAddress(); + source = Get().SelectSourceAddress(aPeer.GetAddress()); + VerifyOrExit(source != nullptr, success = false); + aToBind.SetAddress(*source); } if (aBindPort)