[netdata] new API to get lowpan context IDs (#8870)

This commit adds `otNetDataGetNextLowpanContextInfo()` to iterate
through the list of LoWPAN Context entries in Thread Network Data
providing info about the prefix, its LoWPAN Context ID and Compress
flag (relating to `ContextTlv` sub-TLVs of `PrefixTlv`s in Network
Data).

This commit also updates CLI command `netdata show` to list the
context IDs in addition to prefixes, routes, and services.
This commit is contained in:
Abtin Keshavarzian
2023-03-17 21:39:59 -07:00
committed by GitHub
parent 89d5799d76
commit af031f3b50
14 changed files with 263 additions and 11 deletions
+1 -1
View File
@@ -53,7 +53,7 @@ extern "C" {
* @note This number versions both OpenThread platform and user APIs.
*
*/
#define OPENTHREAD_API_VERSION (301)
#define OPENTHREAD_API_VERSION (302)
/**
* @addtogroup api-instance
+27
View File
@@ -71,6 +71,17 @@ typedef struct otBorderRouterConfig
uint16_t mRloc16; ///< The border router's RLOC16 (value ignored on config add).
} otBorderRouterConfig;
/**
* This structure represents 6LoWPAN Context ID information associated with a prefix in Network Data.
*
*/
typedef struct otLowpanContextInfo
{
uint8_t mContextId; ///< The 6LoWPAN Context ID.
bool mCompressFlag; ///< The compress flag.
otIp6Prefix mPrefix; ///< The associated IPv6 prefix.
} otLowpanContextInfo;
/**
* This structure represents an External Route configuration.
*
@@ -214,6 +225,22 @@ otError otNetDataGetNextRoute(otInstance *aInstance, otNetworkDataIterator *aIte
*/
otError otNetDataGetNextService(otInstance *aInstance, otNetworkDataIterator *aIterator, otServiceConfig *aConfig);
/**
* Get the next 6LoWPAN Context ID info in the partition's Network Data.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in,out] aIterator A pointer to the Network Data iterator. To get the first service entry
it should be set to OT_NETWORK_DATA_ITERATOR_INIT.
* @param[out] aContextInfo A pointer to where the retrieved 6LoWPAN Context ID information will be placed.
*
* @retval OT_ERROR_NONE Successfully found the next 6LoWPAN Context ID info.
* @retval OT_ERROR_NOT_FOUND No subsequent 6LoWPAN Context info exists in the partition's Network Data.
*
*/
otError otNetDataGetNextLowpanContextInfo(otInstance *aInstance,
otNetworkDataIterator *aIterator,
otLowpanContextInfo *aContextInfo);
/**
* Get the Network Data Version.
*
+48 -1
View File
@@ -284,14 +284,61 @@ Done
Usage: `netdata show [local] [-x]`
Print entries in Network Data, on-mesh prefixes, external routes, services, and 6LoWPAN context information.
On-mesh prefixes are listed under `Prefixes` header:
- The on-mesh prefix
- Flags
- p: Preferred flag
- a: Stateless IPv6 Address Autoconfiguration flag
- d: DHCPv6 IPv6 Address Configuration flag
- c: DHCPv6 Other Configuration flag
- r: Default Route flag
- o: On Mesh flag
- s: Stable flag
- n: Nd Dns flag
- D: Domain Prefix flag (only available for Thread 1.2).
- Preference `high`, `med`, or `low`
- RLOC16 of device which added the on-mesh prefix
External Routes are listed under `Routes` header:
- The route prefix
- Flags
- s: Stable flag
- n: NAT64 flag
- Preference `high`, `med`, or `low`
- RLOC16 of device which added the route prefix
Service entries are listed under `Services` header:
- Enterprise number
- Service data (as hex bytes)
- Server data (as hex bytes)
- Flags
- s: Stable flag
- RLOC16 of devices which added the service entry
6LoWPAN Context IDs are listed under `Contexts` header:
- The prefix
- Context ID
- Compress flag (`c` if marked or `-` otherwise).
Print Network Data received from the Leader.
```bash
> netdata show
Prefixes:
fd00:dead:beef:cafe::/64 paros med dc00
fd00:dead:beef:cafe::/64 paros med a000
Routes:
fd00:1234:0:0::/64 s med a000
fd00:4567:0:0::/64 s med 8000
Services:
44970 5d fddead00beef00007bad0069ce45948504d2 s a000
Contexts:
fd00:dead:beef:cafe::/64 1 c
Done
```
+59 -1
View File
@@ -606,6 +606,25 @@ void NetworkData::OutputServices(bool aLocal)
}
}
void NetworkData::OutputLowpanContexts(bool aLocal)
{
otNetworkDataIterator iterator = OT_NETWORK_DATA_ITERATOR_INIT;
otLowpanContextInfo info;
VerifyOrExit(!aLocal);
OutputLine("Contexts:");
while (otNetDataGetNextLowpanContextInfo(GetInstancePtr(), &iterator, &info) == OT_ERROR_NONE)
{
OutputIp6Prefix(info.mPrefix);
OutputLine(" %u %c", info.mContextId, info.mCompressFlag ? 'c' : '-');
}
exit:
return;
}
otError NetworkData::OutputBinary(bool aLocal)
{
otError error;
@@ -643,6 +662,8 @@ exit:
* Services:
* 44970 5d c000 s 4000
* 44970 01 9a04b000000e10 s 4000
* Contexts:
* fd00:dead:beef:cafe::/64 1 c
* Done
* @endcode
* @code
@@ -655,7 +676,43 @@ exit:
* @par
* `netdata show` from OT CLI gets full Network Data received from the Leader. This command uses several
* API functions to combine prefixes, routes, and services, including #otNetDataGetNextOnMeshPrefix,
* #otNetDataGetNextRoute, and #otNetDataGetNextService.
* #otNetDataGetNextRoute, #otNetDataGetNextService and #otNetDataGetNextLowpanContextInfo.
* @par
* On-mesh prefixes are listed under `Prefixes` header:
* * The on-mesh prefix
* * Flags
* * p: Preferred flag
* * a: Stateless IPv6 Address Autoconfiguration flag
* * d: DHCPv6 IPv6 Address Configuration flag
* * c: DHCPv6 Other Configuration flag
* * r: Default Route flag
* * o: On Mesh flag
* * s: Stable flag
* * n: Nd Dns flag
* * D: Domain Prefix flag (only available for Thread 1.2).
* * Preference `high`, `med`, or `low`
* * RLOC16 of device which added the on-mesh prefix
* @par
* External Routes are listed under `Routes` header:
* * The route prefix
* * Flags
* * s: Stable flag
* * n: NAT64 flag
* * Preference `high`, `med`, or `low`
* * RLOC16 of device which added the route prefix
* @par
* Service entries are listed under `Services` header:
* * Enterprise number
* * Service data (as hex bytes)
* * Server data (as hex bytes)
* * Flags
* * s: Stable flag
* * RLOC16 of devices which added the service entry
* @par
* 6LoWPAN Context IDs are listed under `Contexts` header:
* * The prefix
* * Context ID
* * Compress flag (`c` if marked or `-` otherwise).
* @par
* @moreinfo{@netdata}.
* @csa{br omrprefix}
@@ -714,6 +771,7 @@ template <> otError NetworkData::Process<Cmd("show")>(Arg aArgs[])
OutputPrefixes(local);
OutputRoutes(local);
OutputServices(local);
OutputLowpanContexts(local);
error = OT_ERROR_NONE;
}
+1
View File
@@ -139,6 +139,7 @@ private:
void OutputPrefixes(bool aLocal);
void OutputRoutes(bool aLocal);
void OutputServices(bool aLocal);
void OutputLowpanContexts(bool aLocal);
};
} // namespace Cli
+10
View File
@@ -94,6 +94,16 @@ otError otNetDataGetNextService(otInstance *aInstance, otNetworkDataIterator *aI
return AsCoreType(aInstance).Get<NetworkData::Leader>().GetNextService(*aIterator, AsCoreType(aConfig));
}
otError otNetDataGetNextLowpanContextInfo(otInstance *aInstance,
otNetworkDataIterator *aIterator,
otLowpanContextInfo *aContextInfo)
{
AssertPointerIsNotNull(aIterator);
return AsCoreType(aInstance).Get<NetworkData::Leader>().GetNextLowpanContextInfo(*aIterator,
AsCoreType(aContextInfo));
}
uint8_t otNetDataGetVersion(otInstance *aInstance)
{
return AsCoreType(aInstance).Get<Mle::MleRouter>().GetLeaderData().GetDataVersion(NetworkData::kFullSet);
+47 -3
View File
@@ -92,6 +92,7 @@ Error NetworkData::GetNextOnMeshPrefix(Iterator &aIterator, uint16_t aRloc16, On
config.mOnMeshPrefix = &aConfig;
config.mExternalRoute = nullptr;
config.mService = nullptr;
config.mLowpanContext = nullptr;
return Iterate(aIterator, aRloc16, config);
}
@@ -108,6 +109,7 @@ Error NetworkData::GetNextExternalRoute(Iterator &aIterator, uint16_t aRloc16, E
config.mOnMeshPrefix = nullptr;
config.mExternalRoute = &aConfig;
config.mService = nullptr;
config.mLowpanContext = nullptr;
return Iterate(aIterator, aRloc16, config);
}
@@ -124,10 +126,23 @@ Error NetworkData::GetNextService(Iterator &aIterator, uint16_t aRloc16, Service
config.mOnMeshPrefix = nullptr;
config.mExternalRoute = nullptr;
config.mService = &aConfig;
config.mLowpanContext = nullptr;
return Iterate(aIterator, aRloc16, config);
}
Error NetworkData::GetNextLowpanContextInfo(Iterator &aIterator, LowpanContextInfo &aContextInfo) const
{
Config config;
config.mOnMeshPrefix = nullptr;
config.mExternalRoute = nullptr;
config.mService = nullptr;
config.mLowpanContext = &aContextInfo;
return Iterate(aIterator, Mac::kShortAddrBroadcast, config);
}
Error NetworkData::Iterate(Iterator &aIterator, uint16_t aRloc16, Config &aConfig) const
{
// Iterate to the next entry in Network Data matching `aRloc16`
@@ -152,7 +167,8 @@ Error NetworkData::Iterate(Iterator &aIterator, uint16_t aRloc16, Config &aConfi
switch (cur->GetType())
{
case NetworkDataTlv::kTypePrefix:
if ((aConfig.mOnMeshPrefix != nullptr) || (aConfig.mExternalRoute != nullptr))
if ((aConfig.mOnMeshPrefix != nullptr) || (aConfig.mExternalRoute != nullptr) ||
(aConfig.mLowpanContext != nullptr))
{
subTlvs = As<PrefixTlv>(cur)->GetSubTlvs();
}
@@ -199,6 +215,7 @@ Error NetworkData::Iterate(Iterator &aIterator, uint16_t aRloc16, Config &aConfi
aConfig.mExternalRoute = nullptr;
aConfig.mService = nullptr;
aConfig.mLowpanContext = nullptr;
aConfig.mOnMeshPrefix->SetFrom(*prefixTlv, *borderRouter, *borderRouterEntry);
ExitNow(error = kErrorNone);
@@ -223,8 +240,9 @@ Error NetworkData::Iterate(Iterator &aIterator, uint16_t aRloc16, Config &aConfi
{
const HasRouteEntry *hasRouteEntry = hasRoute->GetEntry(index);
aConfig.mOnMeshPrefix = nullptr;
aConfig.mService = nullptr;
aConfig.mOnMeshPrefix = nullptr;
aConfig.mService = nullptr;
aConfig.mLowpanContext = nullptr;
aConfig.mExternalRoute->SetFrom(GetInstance(), *prefixTlv, *hasRoute, *hasRouteEntry);
ExitNow(error = kErrorNone);
@@ -234,6 +252,29 @@ Error NetworkData::Iterate(Iterator &aIterator, uint16_t aRloc16, Config &aConfi
break;
}
case NetworkDataTlv::kTypeContext:
{
const ContextTlv *contextTlv = As<ContextTlv>(subCur);
if (aConfig.mLowpanContext == nullptr)
{
continue;
}
if (iterator.IsNewEntry())
{
aConfig.mOnMeshPrefix = nullptr;
aConfig.mExternalRoute = nullptr;
aConfig.mService = nullptr;
aConfig.mLowpanContext->SetFrom(*prefixTlv, *contextTlv);
iterator.MarkEntryAsNotNew();
ExitNow(error = kErrorNone);
}
break;
}
default:
break;
}
@@ -260,6 +301,7 @@ Error NetworkData::Iterate(Iterator &aIterator, uint16_t aRloc16, Config &aConfi
{
aConfig.mOnMeshPrefix = nullptr;
aConfig.mExternalRoute = nullptr;
aConfig.mLowpanContext = nullptr;
aConfig.mService->SetFrom(*service, *server);
iterator.MarkEntryAsNotNew();
@@ -344,6 +386,7 @@ bool NetworkData::ContainsEntriesFrom(const NetworkData &aCompare, uint16_t aRlo
config.mOnMeshPrefix = &prefix;
config.mExternalRoute = &route;
config.mService = &service;
config.mLowpanContext = nullptr;
SuccessOrExit(aCompare.Iterate(iterator, aRloc16, config));
@@ -643,6 +686,7 @@ Error NetworkData::GetNextServer(Iterator &aIterator, uint16_t &aRloc16) const
config.mOnMeshPrefix = &prefixConfig;
config.mExternalRoute = &routeConfig;
config.mService = &serviceConfig;
config.mLowpanContext = nullptr;
SuccessOrExit(error = Iterate(aIterator, Mac::kShortAddrBroadcast, config));
+13
View File
@@ -266,6 +266,18 @@ public:
*/
Error GetNextService(Iterator &aIterator, uint16_t aRloc16, ServiceConfig &aConfig) const;
/**
* This method gets the next 6LoWPAN Context ID info in the Thread Network Data.
*
* @param[in,out] aIterator A reference to the Network Data iterator.
* @param[out] aContextInfo A reference to where the retrieved 6LoWPAN Context ID information will be placed.
*
* @retval kErrorNone Successfully found the next 6LoWPAN Context ID info.
* @retval kErrorNotFound No subsequent 6LoWPAN Context info exists in the partition's Network Data.
*
*/
Error GetNextLowpanContextInfo(Iterator &aIterator, LowpanContextInfo &aContextInfo) const;
/**
* This method indicates whether or not the Thread Network Data contains a given on mesh prefix entry.
*
@@ -557,6 +569,7 @@ private:
OnMeshPrefixConfig *mOnMeshPrefix;
ExternalRouteConfig *mExternalRoute;
ServiceConfig *mService;
LowpanContextInfo *mLowpanContext;
};
Error Iterate(Iterator &aIterator, uint16_t aRloc16, Config &aConfig) const;
+8
View File
@@ -268,5 +268,13 @@ void ServiceConfig::SetFrom(const ServiceTlv &aServiceTlv, const ServerTlv &aSer
GetServerConfig().SetFrom(aServerTlv);
}
void LowpanContextInfo::SetFrom(const PrefixTlv &aPrefixTlv, const ContextTlv &aContextTlv)
{
mContextId = aContextTlv.GetContextId();
mCompressFlag = aContextTlv.IsCompress();
aPrefixTlv.CopyPrefixTo(GetPrefix());
GetPrefix().SetLength(aContextTlv.GetContextLength());
}
} // namespace NetworkData
} // namespace ot
+24
View File
@@ -67,6 +67,7 @@ class HasRouteTlv;
class HasRouteEntry;
class ServiceTlv;
class ServerTlv;
class ContextTlv;
/**
* This enumeration represents the Network Data type.
@@ -292,6 +293,28 @@ private:
void SetFromTlvFlags(uint8_t aFlags);
};
/**
* This class represents 6LoWPAN Context ID information associated with a prefix in Network Data.
*
*/
class LowpanContextInfo : public otLowpanContextInfo, public Clearable<LowpanContextInfo>
{
friend class NetworkData;
public:
/**
* This method gets the prefix.
*
* @return The prefix.
*
*/
const Ip6::Prefix &GetPrefix(void) const { return AsCoreType(&mPrefix); }
private:
Ip6::Prefix &GetPrefix(void) { return AsCoreType(&mPrefix); }
void SetFrom(const PrefixTlv &aPrefixTlv, const ContextTlv &aContextTlv);
};
/**
* This class represents a Service Data.
*
@@ -392,6 +415,7 @@ private:
DefineCoreType(otBorderRouterConfig, NetworkData::OnMeshPrefixConfig);
DefineCoreType(otExternalRouteConfig, NetworkData::ExternalRouteConfig);
DefineCoreType(otLowpanContextInfo, NetworkData::LowpanContextInfo);
DefineCoreType(otServiceConfig, NetworkData::ServiceConfig);
DefineCoreType(otServerConfig, NetworkData::ServiceConfig::ServerConfig);
+4 -2
View File
@@ -2300,6 +2300,8 @@ class NodeImpl:
for line in netdata:
if line.startswith('Services:'):
services_section = True
elif line.startswith('Contexts'):
services_section = False
elif services_section:
services.append(line.strip().split(' '))
return services
@@ -2310,8 +2312,8 @@ class NodeImpl:
def get_netdata(self):
raw_netdata = self.netdata_show()
netdata = {'Prefixes': [], 'Routes': [], 'Services': []}
key_list = ['Prefixes', 'Routes', 'Services']
netdata = {'Prefixes': [], 'Routes': [], 'Services': [], 'Contexts': []}
key_list = ['Prefixes', 'Routes', 'Services', 'Contexts']
key = None
for i in range(0, len(raw_netdata)):
+7 -1
View File
@@ -359,10 +359,13 @@ class Node(object):
outputs = [line.strip() for line in outputs]
routes_index = outputs.index('Routes:')
services_index = outputs.index('Services:')
contexts_index = outputs.index('Contexts:')
result = {}
result['prefixes'] = outputs[1:routes_index]
result['routes'] = outputs[routes_index + 1:services_index]
result['services'] = outputs[services_index + 1:]
result['services'] = outputs[services_index + 1:contexts_index]
result['contexts'] = outputs[contexts_index + 1:]
return result
def get_netdata_prefixes(self):
@@ -374,6 +377,9 @@ class Node(object):
def get_netdata_services(self):
return self.get_netdata()['services']
def get_netdata_contexts(self):
return self.get_netdata()['contexts']
def get_netdata_versions(self):
leaderdata = Node.parse_list(self.cli('leaderdata'))
return (int(leaderdata['Data Version']), int(leaderdata['Stable Data Version']))
+4 -1
View File
@@ -1694,7 +1694,7 @@ class OpenThreadTHCI(object):
@watched
def getNetworkData(self):
lines = self.__executeCommand('netdata show')
prefixes, routes, services = [], [], []
prefixes, routes, services, contexts = [], [], [], []
classify = None
for line in lines:
@@ -1704,6 +1704,8 @@ class OpenThreadTHCI(object):
classify = routes
elif line == 'Services:':
classify = services
elif line == 'Contexts:':
classify = contexts
elif line == 'Done':
classify = None
else:
@@ -1713,6 +1715,7 @@ class OpenThreadTHCI(object):
'Prefixes': prefixes,
'Routes': routes,
'Services': services,
'Contexts': contexts,
}
@API
+10 -1
View File
@@ -1570,7 +1570,16 @@ class OTCI(object):
routes_output.append(line)
netdata['routes'] = self.__parse_routes(routes_output)
netdata['services'] = self.__parse_services(output)
services_output = []
while True:
line = output.pop(0)
if line == 'Contexts:':
break
else:
services_output.append(line)
netdata['services'] = self.__parse_services(services_output)
return netdata