[border-router] introduce LinkLayerAddress in InfraIf (#12819)

This commit introduces the `LinkLayerAddress` class as a nested type
within `InfraIf`. The new class inherits from the
`otPlatInfraIfLinkLayerAddress`  and provides utility methods to
simplify address manipulation and logging.

Specifically, the following capabilities are added:
- `ConvertToIid()` converts the link-layer address into an IPv6
  `InterfaceIdentifier`.
- `ToString()` formats the address into a human-readable string.
- Getters like `GetLength()` and `GetBytes()` for accessing the
  underlying address data.

The `nexus` platform tests are updated to leverage the newly added
`LinkLayerAddress` methods, simplifying the handling of MAC addresses
and the derivation of IPv6 interface identifiers.
This commit is contained in:
Abtin Keshavarzian
2026-04-04 01:16:37 -05:00
committed by GitHub
parent 3c406866fa
commit aec6b5d795
8 changed files with 145 additions and 55 deletions
+65
View File
@@ -236,6 +236,71 @@ InfraIf::InfoString InfraIf::ToString(void) const
return string;
}
//---------------------------------------------------------------------------------------------------------------------
// InfraIf::LinkLayerAddress
Error InfraIf::LinkLayerAddress::ConvertToIid(Ip6::InterfaceIdentifier &aIid) const
{
Error error = kErrorNone;
Mac::ExtAddress extAddress;
switch (mLength)
{
case 5:
// EUI-40 - [AA BB] + [FF FF FE] + [CC DD EE]
extAddress.m8[0] = mAddress[0];
extAddress.m8[1] = mAddress[1];
extAddress.m8[2] = 0xff;
extAddress.m8[3] = 0xff;
extAddress.m8[4] = 0xfe;
extAddress.m8[5] = mAddress[2];
extAddress.m8[6] = mAddress[3];
extAddress.m8[7] = mAddress[4];
break;
case 6:
// EUI-48 - [AA BB CC] + [FF FE] + [DD EE FF]
extAddress.m8[0] = mAddress[0];
extAddress.m8[1] = mAddress[1];
extAddress.m8[2] = mAddress[2];
extAddress.m8[3] = 0xff;
extAddress.m8[4] = 0xfe;
extAddress.m8[5] = mAddress[3];
extAddress.m8[6] = mAddress[4];
extAddress.m8[7] = mAddress[5];
break;
case 8:
extAddress.Set(mAddress);
break;
default:
ExitNow(error = kErrorNotCapable);
}
aIid.SetFromExtAddress(extAddress);
exit:
return error;
}
InfraIf::LinkLayerAddress::InfoString InfraIf::LinkLayerAddress::ToString(void) const
{
InfoString string;
for (uint8_t i = 0; i < GetLength(); i++)
{
if (i > 0)
{
string.Append(":");
}
string.Append("%02x", mAddress[i]);
}
return string;
}
//---------------------------------------------------------------------------------------------------------------------
extern "C" void otPlatInfraIfRecvIcmp6Nd(otInstance *aInstance,
+54 -3
View File
@@ -40,6 +40,7 @@
#include <openthread/platform/infra_if.h>
#include "common/as_core_type.hpp"
#include "common/data.hpp"
#include "common/error.hpp"
#include "common/locator.hpp"
@@ -87,9 +88,56 @@ class InfraIf : public InstanceLocator
public:
static constexpr uint16_t kInfoStringSize = 20; ///< Max chars for the info string (`ToString()`).
typedef String<kInfoStringSize> InfoString; ///< String type returned from `ToString()`.
typedef Data<kWithUint16Length> Icmp6Packet; ///< An IMCPv6 packet (data containing the IP payload)
typedef otPlatInfraIfLinkLayerAddress LinkLayerAddress; ///< A link-layer address
typedef String<kInfoStringSize> InfoString; ///< String type returned from `ToString()`.
typedef Data<kWithUint16Length> Icmp6Packet; ///< An IMCPv6 packet (data containing the IP payload)
/**
* Represents a link-layer address.
*/
class LinkLayerAddress : public otPlatInfraIfLinkLayerAddress, public Clearable<LinkLayerAddress>
{
public:
static constexpr uint8_t kMaxLength = OT_PLAT_INFRA_IF_MAX_LINK_LAYER_ADDR_LENGTH; ///< Max length
static constexpr uint16_t kInfoStringSize = 50; ///< `InfoString` size
typedef String<kInfoStringSize> InfoString; //< String type returned from `ToString()`.
/**
* Gets the link-layer address's length (number of bytes).
*
* @return The link-layer address's length (in bytes).
*/
uint8_t GetLength(void) const { return mLength; }
/**
* Gets the address bytes (as a pointer to a byte array).
*
* @returns A pointer to a byte array containing the link layer address
*/
const uint8_t *GetBytes(void) const { return mAddress; };
/**
* Converts the link-layer address to an IPv6 Interface Identifier (IID).
*
* Currently supports link-layer addresses of length 5 (40-bit), 6 (48-bit), and 8 (64-bit) bytes.
*
* @param[out] aIid A reference to an `InterfaceIdentifier` to output the converted IID.
*
* @retval kErrorNone Successfully converted to an IID and updated @p aIid.
* @retval kErrorNotCapable The link-layer address length is not supported for conversion.
*/
Error ConvertToIid(Ip6::InterfaceIdentifier &aIid) const;
/**
* Converts the link-layer address to a human-readable string.
*
* The address is represented as a sequence of hex digits (lower case) separated by `:`, e.g., `01:ab:7c:d2:38`.
*
* @returns The string representation of the link-layer address.
*/
InfoString ToString(void) const;
};
/**
* Initializes the `InfraIf`.
@@ -238,6 +286,9 @@ private:
};
} // namespace BorderRouter
DefineCoreType(otPlatInfraIfLinkLayerAddress, BorderRouter::InfraIf::LinkLayerAddress);
} // namespace ot
#endif // OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
+2 -8
View File
@@ -195,14 +195,8 @@ void Core::SaveTestInfo(const char *aFilename, Node *aLeaderNode)
InfraIf::LinkLayerAddress mac;
node.mInfraIf.GetLinkLayerAddress(mac);
fprintf(file, " \"%u\": \"", node.GetInstance().GetId());
for (uint8_t i = 0; i < mac.mLength; i++)
{
fprintf(file, "%02x%s", mac.mAddress[i], (i + 1 == mac.mLength) ? "" : ":");
}
fprintf(file, "\"%s\n", (&node == tail) ? "" : ",");
fprintf(file, " \"%u\": \"%s\"%s\n", node.GetInstance().GetId(), mac.ToString().AsCString(),
(&node == tail) ? "" : ",");
}
fprintf(file, " },\n");
+4 -20
View File
@@ -54,15 +54,7 @@ void InfraIf::Init(Node &aNode)
mNodeId = aNode.GetId();
GetLinkLayerAddress(mac);
iid.mFields.m8[0] = mac.mAddress[0] ^ 0x02;
iid.mFields.m8[1] = mac.mAddress[1];
iid.mFields.m8[2] = mac.mAddress[2];
iid.mFields.m8[3] = 0xff;
iid.mFields.m8[4] = 0xfe;
iid.mFields.m8[5] = mac.mAddress[3];
iid.mFields.m8[6] = mac.mAddress[4];
iid.mFields.m8[7] = mac.mAddress[5];
SuccessOrQuit(mac.ConvertToIid(iid));
address.SetToLinkLocalAddress(iid);
@@ -270,15 +262,7 @@ void InfraIf::HandlePrefixInfoOption(const Ip6::Nd::PrefixInfoOption &aPio)
address = AsCoreType(&prefix.mPrefix);
GetLinkLayerAddress(mac);
address.mFields.m8[8] = mac.mAddress[0] ^ 0x02;
address.mFields.m8[9] = mac.mAddress[1];
address.mFields.m8[10] = mac.mAddress[2];
address.mFields.m8[11] = 0xff;
address.mFields.m8[12] = 0xfe;
address.mFields.m8[13] = mac.mAddress[3];
address.mFields.m8[14] = mac.mAddress[4];
address.mFields.m8[15] = mac.mAddress[5];
SuccessOrQuit(mac.ConvertToIid(address.GetIid()));
if (aPio.GetValidLifetime() == 0)
{
@@ -586,7 +570,7 @@ void InfraIf::GetLinkLayerAddress(LinkLayerAddress &aLinkLayerAddress) const
ClearAllBytes(aLinkLayerAddress);
aLinkLayerAddress.mLength = 6;
aLinkLayerAddress.mAddress[0] = 0x02;
aLinkLayerAddress.mAddress[5] = static_cast<uint8_t>(mNodeId);
BigEndian::WriteUint32(mNodeId, &aLinkLayerAddress.mAddress[2]);
}
Node &InfraIf::GetNode(void)
@@ -637,7 +621,7 @@ otError otPlatGetInfraIfLinkLayerAddress(otInstance *aInstanc
{
OT_UNUSED_VARIABLE(aInfraIfIndex);
AsNode(aInstance).mInfraIf.GetLinkLayerAddress(*aLinkLayerAddress);
AsNode(aInstance).mInfraIf.GetLinkLayerAddress(AsCoreType(aLinkLayerAddress));
return OT_ERROR_NONE;
}
+1 -1
View File
@@ -39,7 +39,7 @@ class Node;
class InfraIf
{
public:
typedef otPlatInfraIfLinkLayerAddress LinkLayerAddress;
using LinkLayerAddress = BorderRouter::InfraIf::LinkLayerAddress;
explicit InfraIf(Instance &aInstance);
+10 -9
View File
@@ -202,11 +202,11 @@ exit:
return;
}
void Pcap::WritePacket(const otPlatInfraIfLinkLayerAddress &aSrcAddr,
const otPlatInfraIfLinkLayerAddress &aDstAddr,
const uint8_t *aBuffer,
uint16_t aLength,
uint64_t aTimeUs)
void Pcap::WritePacket(const InfraIf::LinkLayerAddress &aSrcAddr,
const InfraIf::LinkLayerAddress &aDstAddr,
const uint8_t *aBuffer,
uint16_t aLength,
uint64_t aTimeUs)
{
Epb epb;
@@ -227,10 +227,11 @@ void Pcap::WritePacket(const otPlatInfraIfLinkLayerAddress &aSrcAddr,
VerifyOrExit(mFile != nullptr);
ClearAllBytes(ethHeader);
VerifyOrQuit(aDstAddr.mLength >= sizeof(ethHeader.mDst), "Destination MAC address length is less than expected");
memcpy(ethHeader.mDst, aDstAddr.mAddress, sizeof(ethHeader.mDst));
VerifyOrQuit(aSrcAddr.mLength >= sizeof(ethHeader.mSrc), "Source MAC address length is less than expected");
memcpy(ethHeader.mSrc, aSrcAddr.mAddress, sizeof(ethHeader.mSrc));
VerifyOrQuit(aDstAddr.GetLength() >= sizeof(ethHeader.mDst),
"Destination MAC address length is less than expected");
memcpy(ethHeader.mDst, aDstAddr.GetBytes(), sizeof(ethHeader.mDst));
VerifyOrQuit(aSrcAddr.GetLength() >= sizeof(ethHeader.mSrc), "Source MAC address length is less than expected");
memcpy(ethHeader.mSrc, aSrcAddr.GetBytes(), sizeof(ethHeader.mSrc));
ethHeader.mType = BigEndian::HostSwap16(kEtherTypeIPv6);
packetLen = sizeof(ethHeader) + aLength;
+7 -7
View File
@@ -32,8 +32,8 @@
#include <cstdint>
#include <cstdio>
#include <openthread/platform/infra_if.h>
#include <openthread/platform/radio.h>
#include "nexus_infra_if.hpp"
#include "nexus_radio.hpp"
namespace ot {
namespace Nexus {
@@ -73,11 +73,11 @@ public:
* @param[in] aLength The packet length.
* @param[in] aTimeUs The timestamp in microseconds.
*/
void WritePacket(const otPlatInfraIfLinkLayerAddress &aSrcAddr,
const otPlatInfraIfLinkLayerAddress &aDstAddr,
const uint8_t *aBuffer,
uint16_t aLength,
uint64_t aTimeUs);
void WritePacket(const InfraIf::LinkLayerAddress &aSrcAddr,
const InfraIf::LinkLayerAddress &aDstAddr,
const uint8_t *aBuffer,
uint16_t aLength,
uint64_t aTimeUs);
private:
static constexpr uint32_t kPcapngShbType = 0x0a0d0d0a;
+2 -7
View File
@@ -252,18 +252,13 @@ void Test_1_3_DBR_TC_6(void)
nexus.AdvanceTime(kPingResponseTime);
{
char macStr[18];
InfraIf::LinkLayerAddress addr;
br1.mInfraIf.GetLinkLayerAddress(addr);
snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x", addr.mAddress[0], addr.mAddress[1],
addr.mAddress[2], addr.mAddress[3], addr.mAddress[4], addr.mAddress[5]);
nexus.AddTestVar("BR1_ETH", macStr);
nexus.AddTestVar("BR1_ETH", addr.ToString().AsCString());
eth1.mInfraIf.GetLinkLayerAddress(addr);
snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x", addr.mAddress[0], addr.mAddress[1],
addr.mAddress[2], addr.mAddress[3], addr.mAddress[4], addr.mAddress[5]);
nexus.AddTestVar("ETH1_ETH", macStr);
nexus.AddTestVar("ETH1_ETH", addr.ToString().AsCString());
}
nexus.AddTestVar("BR1", br1.Get<Mac::Mac>().GetExtAddress().ToString().AsCString());