Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ICD] Implement the support of the ICD Check-In BackOff #34482

Merged
merged 10 commits into from
Jul 26, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -1796,6 +1796,7 @@ endpoint 0 {
ram attribute userActiveModeTriggerHint default = 0x111D;
ram attribute userActiveModeTriggerInstruction default = "Restart the application";
ram attribute operatingMode default = 0;
callback attribute maximumCheckInBackOff;
callback attribute generatedCommandList;
callback attribute acceptedCommandList;
callback attribute eventList;
Expand Down
30 changes: 23 additions & 7 deletions examples/lit-icd-app/lit-icd-common/lit-icd-server-app.zap
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,20 @@
}
],
"package": [
{
"pathRelativity": "relativeToZap",
"path": "../../../src/app/zap-templates/app-templates.json",
"type": "gen-templates-json",
"category": "matter",
"version": "chip-v1"
},
{
"pathRelativity": "relativeToZap",
"path": "../../../src/app/zap-templates/zcl/zcl.json",
"type": "zcl-properties",
"category": "matter",
"version": 1,
"description": "Matter SDK ZCL data"
},
{
"pathRelativity": "relativeToZap",
"path": "../../../src/app/zap-templates/app-templates.json",
"type": "gen-templates-json",
"category": "matter",
"version": "chip-v1"
}
],
"endpointTypes": [
Expand Down Expand Up @@ -3552,6 +3552,22 @@
"maxInterval": 65534,
"reportableChange": 0
},
{
"name": "MaximumCheckInBackOff",
"code": 9,
"mfgCode": null,
"side": "server",
"type": "int32u",
"included": 1,
"storageOption": "External",
"singleton": 0,
"bounded": 0,
"defaultValue": "",
"reportable": 1,
"minInterval": 1,
"maxInterval": 65534,
"reportableChange": 0
},
{
"name": "GeneratedCommandList",
"code": 65528,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ class IcdManagementAttributeAccess : public AttributeAccessInterface
CHIP_ERROR ReadRegisteredClients(EndpointId endpoint, AttributeValueEncoder & encoder);
CHIP_ERROR ReadICDCounter(EndpointId endpoint, AttributeValueEncoder & encoder);
CHIP_ERROR ReadClientsSupportedPerFabric(EndpointId endpoint, AttributeValueEncoder & encoder);
CHIP_ERROR ReadMaximumCheckInBackOff(EndpointId endpoint, AttributeValueEncoder & encoder);

PersistentStorageDelegate * mStorage = nullptr;
Crypto::SymmetricKeystore * mSymmetricKeystore = nullptr;
Expand Down Expand Up @@ -102,6 +103,9 @@ CHIP_ERROR IcdManagementAttributeAccess::Read(const ConcreteReadAttributePath &

case IcdManagement::Attributes::ClientsSupportedPerFabric::Id:
return ReadClientsSupportedPerFabric(aPath.mEndpointId, aEncoder);

case IcdManagement::Attributes::MaximumCheckInBackOff::Id:
return ReadMaximumCheckInBackOff(aPath.mEndpointId, aEncoder);
#endif // CHIP_CONFIG_ENABLE_ICD_CIP
}

Expand Down Expand Up @@ -221,6 +225,11 @@ CHIP_ERROR IcdManagementAttributeAccess::ReadClientsSupportedPerFabric(EndpointI
return encoder.Encode(mICDConfigurationData->GetClientsSupportedPerFabric());
}

CHIP_ERROR IcdManagementAttributeAccess::ReadMaximumCheckInBackOff(EndpointId endpoint, AttributeValueEncoder & encoder)
{
return encoder.Encode(mICDConfigurationData->GetMaximumCheckInBackoff().count());
}

/**
* @brief Function checks if the client has admin permissions to the cluster in the commandPath
*
Expand Down
17 changes: 17 additions & 0 deletions src/app/icd/server/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,22 @@ source_set("notifier") {
]
}

source_set("check-in-back-off") {
sources = [ "ICDCheckInBackOffStrategy.h" ]

public_deps = [
":monitoring-table",
"${chip_root}/src/lib/core",
"${chip_root}/src/lib/support",
]
}

source_set("default-check-in-back-off") {
sources = [ "DefaultICDCheckInBackOffStrategy.h" ]

public_deps = [ ":check-in-back-off" ]
}

# ICD Manager source-set is broken out of the main source-set to enable unit tests
# All sources and configurations used by the ICDManager need to go in this source-set
source_set("manager") {
Expand All @@ -77,6 +93,7 @@ source_set("manager") {
deps = [ ":icd-server-config" ]

public_deps = [
":check-in-back-off",
":configuration-data",
":notifier",
":observer",
Expand Down
63 changes: 63 additions & 0 deletions src/app/icd/server/DefaultICDCheckInBackOffStrategy.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
*
* Copyright (c) 2024 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#pragma once

#include <app/icd/server/ICDCheckInBackOffStrategy.h>
#include <lib/core/ClusterEnums.h>

namespace chip {
namespace app {

/**
* @brief Default ICD Check-In BackOff Strategy.
* The default strategy is based on the two types of controllers
* - kPermanent : Always send a Check-In message
* - kEphemeral : Never send a Check-In message
*
* This implementation represents a no back off strategy.
*/
class DefaultICDCheckInBackOffStrategy : public ICDCheckInBackOffStrategy
{
public:
DefaultICDCheckInBackOffStrategy() = default;
~DefaultICDCheckInBackOffStrategy() = default;

/**
* @brief Function checks if the entry is a permanent or ephemeral client.
* If the client is permanent, we should send a Check-In message.
* If the cliet is ephemerakl, we should not send a Check-In message.
mkardous-silabs marked this conversation as resolved.
Show resolved Hide resolved
mkardous-silabs marked this conversation as resolved.
Show resolved Hide resolved
*
* @param entry Entry for which we are deciding if we need to send a Check-In message or not.
mkardous-silabs marked this conversation as resolved.
Show resolved Hide resolved
* @return true If the client is permanent, return true.
* @return false If the client is not permanent, ephemeral or invalid, return false.
*/
bool ShouldSendCheckInMessage(const ICDMonitoringEntry & entry)
mkardous-silabs marked this conversation as resolved.
Show resolved Hide resolved
{
return (entry.clientType == Clusters::IcdManagement::ClientTypeEnum::kPermanent);
}

/**
* @brief The default Check-In BackOff fundamentally implements a no back off strategy.
* As such, we don't need to execute anything to force the maximum Check-In BackOff.
*
*/
CHIP_ERROR ForceMaximumCheckInBackoff() { return CHIP_NO_ERROR; }
mkardous-silabs marked this conversation as resolved.
Show resolved Hide resolved
};

} // namespace app
} // namespace chip
62 changes: 62 additions & 0 deletions src/app/icd/server/ICDCheckInBackOffStrategy.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
*
* Copyright (c) 2024 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once

#include <app/icd/server/ICDMonitoringTable.h>
#include <lib/core/CHIPError.h>

namespace chip {
namespace app {

/**
* @brief This class defines the necessary interface a ICD Check-In BackOff strategy needs to implment to be consummed by the
* ICDManager class. The strategy is injected with the init server params when initializing the device Server class.
*/
class ICDCheckInBackOffStrategy
{
public:
virtual ~ICDCheckInBackOffStrategy() = default;

/**
* @brief Function is used by the ICDManager to determine if a Check-In message should be sent to the given entry based on the
* Check-In BackOff strategy.
*
* There are no requirements on how the Check-In BackOff strategy should behave.
mkardous-silabs marked this conversation as resolved.
Show resolved Hide resolved
* The only specified requirement is the maximum time between to Check-In message, MaximumCheckInBackOff.
* All strategies must respect this requirement.
*
* @param entry ICDMonitoringEntry for which we are about to send a Check-In message to.
*
* @return true ICDCheckInBackOffStrategy determines that we SHOULD send a Check-In message to the given entry
* @return falseI CDCheckInBackOffStrategy determines that we SHOULD NOT send a Check-In message to the given entry
mkardous-silabs marked this conversation as resolved.
Show resolved Hide resolved
mkardous-silabs marked this conversation as resolved.
Show resolved Hide resolved
*/
virtual bool ShouldSendCheckInMessage(const ICDMonitoringEntry & entry) = 0;

/**
* @brief Function is used within the test event trigger to force the maximum BackOff state of the ICD Check-In BackOff
* strategy. This enables to validate the strategy and to certify it respects the MaximumCheckInBackOff interval during
* certification.
*
* Function sets the maxmimum BackOff state for all clients registered with the ICD
*
* @return CHIP_ERROR Any error returned during the forcing of the maximum BackOff state
*/
virtual CHIP_ERROR ForceMaximumCheckInBackoff() = 0;
};

} // namespace app
} // namespace chip
8 changes: 8 additions & 0 deletions src/app/icd/server/ICDConfigurationData.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ class ICDConfigurationData

System::Clock::Milliseconds16 GetMinLitActiveModeThreshold() { return kMinLitActiveModeThreshold; }

System::Clock::Seconds32 GetMaximumCheckInBackoff() { return mMaximumCheckInBackOff; }

/**
* If ICD_ENFORCE_SIT_SLOW_POLL_LIMIT is set to 0, function will always return the configured Slow Polling interval
* (CHIP_DEVICE_CONFIG_ICD_SLOW_POLL_INTERVAL).
Expand Down Expand Up @@ -150,6 +152,12 @@ class ICDConfigurationData
"Spec requires the minimum of supported clients per fabric be equal or greater to 1.");
uint16_t mFabricClientsSupported = CHIP_CONFIG_ICD_CLIENTS_SUPPORTED_PER_FABRIC;

static_assert((CHIP_CONFIG_ICD_MAXIMUM_CHECK_IN_BACKOFF_SEC) <= kMaxIdleModeDuration.count(),
"Spec requires the MaximumCheckInBackOff to be equal or inferior to 64800s");
static_assert((CHIP_CONFIG_ICD_IDLE_MODE_DURATION_SEC) <= (CHIP_CONFIG_ICD_MAXIMUM_CHECK_IN_BACKOFF_SEC),
"Spec requires the MaximumCheckInBackOff to be equal or superior to the IdleModeDuration");
System::Clock::Seconds32 mMaximumCheckInBackOff = System::Clock::Seconds32(CHIP_CONFIG_ICD_MAXIMUM_CHECK_IN_BACKOFF_SEC);

// SIT ICDs should have a SlowPollingThreshold shorter than or equal to 15s (spec 9.16.1.5)
static constexpr System::Clock::Milliseconds32 kSITPollingThreshold = System::Clock::Milliseconds32(15000);
System::Clock::Milliseconds32 mSlowPollingInterval = CHIP_DEVICE_CONFIG_ICD_SLOW_POLL_INTERVAL;
Expand Down
35 changes: 21 additions & 14 deletions src/app/icd/server/ICDManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,11 @@
namespace {
enum class ICDTestEventTriggerEvent : uint64_t
{
kAddActiveModeReq = 0x0046'0000'00000001,
kRemoveActiveModeReq = 0x0046'0000'00000002,
kInvalidateHalfCounterValues = 0x0046'0000'00000003,
kInvalidateAllCounterValues = 0x0046'0000'00000004,
kAddActiveModeReq = 0x0046'0000'00000001,
kRemoveActiveModeReq = 0x0046'0000'00000002,
kInvalidateHalfCounterValues = 0x0046'0000'00000003,
kInvalidateAllCounterValues = 0x0046'0000'00000004,
kForceMaximumCheckInBackOffState = 0x0046'0000'00000005,
};
} // namespace

Expand All @@ -52,14 +53,16 @@ static_assert(UINT8_MAX >= CHIP_CONFIG_MAX_EXCHANGE_CONTEXTS,
"ICDManager::mOpenExchangeContextCount cannot hold count for the max exchange count");

void ICDManager::Init(PersistentStorageDelegate * storage, FabricTable * fabricTable, Crypto::SymmetricKeystore * symmetricKeystore,
Messaging::ExchangeManager * exchangeManager, SubscriptionsInfoProvider * subInfoProvider)
Messaging::ExchangeManager * exchangeManager, SubscriptionsInfoProvider * subInfoProvider,
mkardous-silabs marked this conversation as resolved.
Show resolved Hide resolved
ICDCheckInBackOffStrategy * strategy)
{
#if CHIP_CONFIG_ENABLE_ICD_CIP
VerifyOrDie(storage != nullptr);
VerifyOrDie(fabricTable != nullptr);
VerifyOrDie(symmetricKeystore != nullptr);
VerifyOrDie(exchangeManager != nullptr);
VerifyOrDie(subInfoProvider != nullptr);
VerifyOrDie(strategy != nullptr);
#endif // CHIP_CONFIG_ENABLE_ICD_CIP

#if CHIP_CONFIG_ENABLE_ICD_LIT
Expand All @@ -82,11 +85,12 @@ void ICDManager::Init(PersistentStorageDelegate * storage, FabricTable * fabricT
VerifyOrDie(ICDNotifier::GetInstance().Subscribe(this) == CHIP_NO_ERROR);

#if CHIP_CONFIG_ENABLE_ICD_CIP
mStorage = storage;
mFabricTable = fabricTable;
mSymmetricKeystore = symmetricKeystore;
mExchangeManager = exchangeManager;
mSubInfoProvider = subInfoProvider;
mStorage = storage;
mFabricTable = fabricTable;
mSymmetricKeystore = symmetricKeystore;
mExchangeManager = exchangeManager;
mSubInfoProvider = subInfoProvider;
mICDCheckInBackOffStrategy = strategy;

VerifyOrDie(ICDConfigurationData::GetInstance().GetICDCounter().Init(mStorage, DefaultStorageKeyAllocator::ICDCheckInCounter(),
ICDConfigurationData::kICDCounterPersistenceIncrement) ==
Expand Down Expand Up @@ -188,15 +192,15 @@ void ICDManager::SendCheckInMsgs()
continue;
}

if (entry.clientType == ClientTypeEnum::kEphemeral)
if (!ShouldCheckInMsgsBeSentAtActiveModeFunction(entry.fabricIndex, entry.monitoredSubject))
{
// If the registered client is ephemeral, do not send a Check-In message
// continue to next entry
continue;
}

if (!ShouldCheckInMsgsBeSentAtActiveModeFunction(entry.fabricIndex, entry.monitoredSubject))
// Validate Check-In BackOff strategy if we should send a Check-In message.
mkardous-silabs marked this conversation as resolved.
Show resolved Hide resolved
if (!mICDCheckInBackOffStrategy->ShouldSendCheckInMessage(entry))
{
// continue to next entry
continue;
}

Expand Down Expand Up @@ -689,6 +693,9 @@ CHIP_ERROR ICDManager::HandleEventTrigger(uint64_t eventTrigger)
case ICDTestEventTriggerEvent::kInvalidateAllCounterValues:
err = ICDConfigurationData::GetInstance().GetICDCounter().InvalidateAllCheckInCounterValues();
break;
case ICDTestEventTriggerEvent::kForceMaximumCheckInBackOffState:
err = mICDCheckInBackOffStrategy->ForceMaximumCheckInBackoff();
break;
#endif // CHIP_CONFIG_ENABLE_ICD_CIP
default:
err = CHIP_ERROR_INVALID_ARGUMENT;
Expand Down
15 changes: 9 additions & 6 deletions src/app/icd/server/ICDManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <app/AppConfig.h>
#include <app/SubscriptionsInfoProvider.h>
#include <app/TestEventTriggerDelegate.h>
#include <app/icd/server/ICDCheckInBackOffStrategy.h>
#include <app/icd/server/ICDConfigurationData.h>
#include <app/icd/server/ICDNotifier.h>
#include <app/icd/server/ICDStateObserver.h>
Expand Down Expand Up @@ -115,7 +116,8 @@ class ICDManager : public ICDListener, public TestEventTriggerHandler
~ICDManager() = default;

void Init(PersistentStorageDelegate * storage, FabricTable * fabricTable, Crypto::SymmetricKeystore * symmetricKeyStore,
Messaging::ExchangeManager * exchangeManager, SubscriptionsInfoProvider * subInfoProvider);
Messaging::ExchangeManager * exchangeManager, SubscriptionsInfoProvider * subInfoProvider,
ICDCheckInBackOffStrategy * strategy);
void Shutdown();

/**
Expand Down Expand Up @@ -318,11 +320,12 @@ class ICDManager : public ICDListener, public TestEventTriggerHandler
bool mIsBootUpResumeSubscriptionExecuted = false;
#endif // !CHIP_CONFIG_SUBSCRIPTION_TIMEOUT_RESUMPTION && CHIP_CONFIG_PERSIST_SUBSCRIPTIONS

PersistentStorageDelegate * mStorage = nullptr;
FabricTable * mFabricTable = nullptr;
Messaging::ExchangeManager * mExchangeManager = nullptr;
Crypto::SymmetricKeystore * mSymmetricKeystore = nullptr;
SubscriptionsInfoProvider * mSubInfoProvider = nullptr;
PersistentStorageDelegate * mStorage = nullptr;
FabricTable * mFabricTable = nullptr;
Messaging::ExchangeManager * mExchangeManager = nullptr;
Crypto::SymmetricKeystore * mSymmetricKeystore = nullptr;
SubscriptionsInfoProvider * mSubInfoProvider = nullptr;
ICDCheckInBackOffStrategy * mICDCheckInBackOffStrategy = nullptr;
ObjectPool<ICDCheckInSender, (CHIP_CONFIG_ICD_CLIENTS_SUPPORTED_PER_FABRIC * CHIP_CONFIG_MAX_FABRICS)> mICDSenderPool;
#endif // CHIP_CONFIG_ENABLE_ICD_CIP

Expand Down
Loading
Loading