diff --git a/include/openthread/instance.h b/include/openthread/instance.h index 8d403ff4d..1ea231f48 100644 --- a/include/openthread/instance.h +++ b/include/openthread/instance.h @@ -53,7 +53,7 @@ extern "C" { * @note This number versions both OpenThread platform and user APIs. * */ -#define OPENTHREAD_API_VERSION (259) +#define OPENTHREAD_API_VERSION (260) /** * @addtogroup api-instance diff --git a/include/openthread/ip6.h b/include/openthread/ip6.h index 73bd59744..39534d880 100644 --- a/include/openthread/ip6.h +++ b/include/openthread/ip6.h @@ -851,6 +851,40 @@ otError otIp6SetMeshLocalIid(otInstance *aInstance, const otIp6InterfaceIdentifi */ const char *otIp6ProtoToString(uint8_t aIpProto); +/** + * This structure represents the counters for packets and bytes. + * + */ +typedef struct otPacketsAndBytes +{ + uint64_t mPackets; ///< The number of packets. + uint64_t mBytes; ///< The number of bytes. +} otPacketsAndBytes; + +/** + * This structure represents the counters of packets forwarded via Border Routing. + * + */ +typedef struct otBorderRoutingCounters +{ + otPacketsAndBytes mInboundUnicast; ///< The counters for inbound unicast. + otPacketsAndBytes mInboundMulticast; ///< The counters for inbound multicast. + otPacketsAndBytes mOutboundUnicast; ///< The counters for outbound unicast. + otPacketsAndBytes mOutboundMulticast; ///< The counters for outbound multicast. +} otBorderRoutingCounters; + +/** + * Gets the Border Routing counters. + * + * This function requires the build-time feature `OPENTHREAD_CONFIG_IP6_BR_COUNTERS_ENABLE` to be enabled. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * + * @returns A pointer to the Border Routing counters. + * + */ +const otBorderRoutingCounters *otIp6GetBorderRoutingCounters(otInstance *aInstance); + /** * @} * diff --git a/src/core/api/ip6_api.cpp b/src/core/api/ip6_api.cpp index 454132b4d..78fb477eb 100644 --- a/src/core/api/ip6_api.cpp +++ b/src/core/api/ip6_api.cpp @@ -294,3 +294,10 @@ const char *otIp6ProtoToString(uint8_t aIpProto) { return Ip6::Ip6::IpProtoToString(aIpProto); } + +#if OPENTHREAD_CONFIG_IP6_BR_COUNTERS_ENABLE +const otBorderRoutingCounters *otIp6GetBorderRoutingCounters(otInstance *aInstance) +{ + return &AsCoreType(aInstance).Get().GetBorderRoutingCounters(); +} +#endif diff --git a/src/core/config/ip6.h b/src/core/config/ip6.h index b84918fec..268a2cd47 100644 --- a/src/core/config/ip6.h +++ b/src/core/config/ip6.h @@ -35,6 +35,8 @@ #ifndef CONFIG_IP6_H_ #define CONFIG_IP6_H_ +#include "config/border_routing.h" + /** * @def OPENTHREAD_CONFIG_IP6_MAX_EXT_UCAST_ADDRS * @@ -180,4 +182,14 @@ #define OPENTHREAD_CONFIG_IP6_ALLOW_LOOP_BACK_HOST_DATAGRAMS 1 #endif +/** + * @def OPENTHREAD_CONFIG_IP6_BR_COUNTERS_ENABLE + * + * Define as 1 to enable IPv6 Border Routing counters. + * + */ +#ifndef OPENTHREAD_CONFIG_IP6_BR_COUNTERS_ENABLE +#define OPENTHREAD_CONFIG_IP6_BR_COUNTERS_ENABLE OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE +#endif + #endif // CONFIG_IP6_H_ diff --git a/src/core/net/ip6.cpp b/src/core/net/ip6.cpp index 752d98d84..74da1e8d6 100644 --- a/src/core/net/ip6.cpp +++ b/src/core/net/ip6.cpp @@ -1019,6 +1019,11 @@ Error Ip6::ProcessReceiveCallback(Message & aMessage, { Error error = kErrorNone; Message *message = &aMessage; +#if OPENTHREAD_CONFIG_IP6_BR_COUNTERS_ENABLE + Header header; + + IgnoreError(header.ParseFrom(aMessage)); +#endif VerifyOrExit(aOrigin != kFromHostDisallowLoopBack, error = kErrorNoRoute); @@ -1103,6 +1108,10 @@ Error Ip6::ProcessReceiveCallback(Message & aMessage, mReceiveIp6DatagramCallback(message, mReceiveIp6DatagramCallbackContext); +#if OPENTHREAD_CONFIG_IP6_BR_COUNTERS_ENABLE + UpdateBorderRoutingCounters(header, aMessage.GetLength(), /* aIsInbound */ false); +#endif + exit: if ((error != kErrorNone) && (aMessageOwnership == Message::kTakeCustody)) @@ -1135,6 +1144,10 @@ Error Ip6::SendRaw(Message &aMessage, bool aAllowLoopBackToHost) error = HandleDatagram(aMessage, aAllowLoopBackToHost ? kFromHostAllowLoopBack : kFromHostDisallowLoopBack); freed = true; +#if OPENTHREAD_CONFIG_IP6_BR_COUNTERS_ENABLE + UpdateBorderRoutingCounters(header, aMessage.GetLength(), /* aIsInbound */ true); +#endif + exit: if (!freed) @@ -1492,6 +1505,55 @@ exit: return rval; } +#if OPENTHREAD_CONFIG_IP6_BR_COUNTERS_ENABLE +void Ip6::UpdateBorderRoutingCounters(const Header &aHeader, uint16_t aMessageLength, bool aIsInbound) +{ + otPacketsAndBytes *counter = nullptr; + + VerifyOrExit(!aHeader.GetSource().IsLinkLocal()); + VerifyOrExit(!aHeader.GetDestination().IsLinkLocal()); + VerifyOrExit(aHeader.GetSource().GetPrefix() != Get().GetMeshLocalPrefix()); + VerifyOrExit(aHeader.GetDestination().GetPrefix() != Get().GetMeshLocalPrefix()); + + if (aIsInbound) + { + VerifyOrExit(!Get().HasUnicastAddress(aHeader.GetSource())); + + if (aHeader.GetDestination().IsMulticast()) + { + VerifyOrExit(aHeader.GetDestination().IsMulticastLargerThanRealmLocal()); + counter = &mBorderRoutingCounters.mInboundMulticast; + } + else + { + counter = &mBorderRoutingCounters.mInboundUnicast; + } + } + else + { + VerifyOrExit(!Get().HasUnicastAddress(aHeader.GetDestination())); + + if (aHeader.GetDestination().IsMulticast()) + { + VerifyOrExit(aHeader.GetDestination().IsMulticastLargerThanRealmLocal()); + counter = &mBorderRoutingCounters.mOutboundMulticast; + } + else + { + counter = &mBorderRoutingCounters.mOutboundUnicast; + } + } + +exit: + + if (counter) + { + counter->mPackets += 1; + counter->mBytes += aMessageLength; + } +} +#endif + // LCOV_EXCL_START const char *Ip6::IpProtoToString(uint8_t aIpProto) diff --git a/src/core/net/ip6.hpp b/src/core/net/ip6.hpp index 037f02f47..1b97dccdc 100644 --- a/src/core/net/ip6.hpp +++ b/src/core/net/ip6.hpp @@ -340,6 +340,16 @@ public: */ static const char *EcnToString(Ecn aEcn); +#if OPENTHREAD_CONFIG_IP6_BR_COUNTERS_ENABLE + /** + * This method returns a reference to the Border Routing counters. + * + * @returns A reference to the Border Routing counters. + * + */ + const otBorderRoutingCounters &GetBorderRoutingCounters(void) const { return mBorderRoutingCounters; } +#endif + private: static constexpr uint8_t kDefaultHopLimit = OPENTHREAD_CONFIG_IP6_HOP_LIMIT_DEFAULT; static constexpr uint8_t kIp6ReassemblyTimeout = OPENTHREAD_CONFIG_IP6_REASSEMBLY_TIMEOUT; @@ -384,6 +394,9 @@ private: Message::Ownership aMessageOwnership); bool ShouldForwardToThread(const MessageInfo &aMessageInfo, MessageOrigin aOrigin) const; bool IsOnLink(const Address &aAddress) const; +#if OPENTHREAD_CONFIG_IP6_BR_COUNTERS_ENABLE + void UpdateBorderRoutingCounters(const Header &aHeader, uint16_t aMessageLength, bool aIsInbound); +#endif using SendQueueTask = TaskletIn; @@ -411,6 +424,10 @@ private: #if OPENTHREAD_CONFIG_IP6_FRAGMENTATION_ENABLE MessageQueue mReassemblyList; #endif + +#if OPENTHREAD_CONFIG_IP6_BR_COUNTERS_ENABLE + otBorderRoutingCounters mBorderRoutingCounters; +#endif }; /**