• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2021, The OpenThread Authors.
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. Neither the name of the copyright holder nor the
13  *     names of its contributors may be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *  POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /**
30  * @file
31  *   This file includes definition of Network Data Publisher.
32  */
33 
34 #ifndef NETWORK_DATA_PUBLISHER_HPP_
35 #define NETWORK_DATA_PUBLISHER_HPP_
36 
37 #include "openthread-core-config.h"
38 
39 #if OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE
40 
41 #if !OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE && !OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
42 #error "OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE requires either OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE"\
43             "or OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE"
44 #endif
45 
46 #if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE && (OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_PREFIX_ENTRIES < \
47                                                 (OPENTHREAD_CONFIG_BORDER_ROUTING_MAX_DISCOVERED_PREFIXES + 4))
48 #error "OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_PREFIX_ENTRIES needs to support more entries when "\
49        "OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE is enabled to accommodate for max on-link prefixes"
50 #endif
51 
52 #include <openthread/netdata_publisher.h>
53 
54 #include "common/clearable.hpp"
55 #include "common/equatable.hpp"
56 #include "common/error.hpp"
57 #include "common/locator.hpp"
58 #include "common/non_copyable.hpp"
59 #include "common/notifier.hpp"
60 #include "common/string.hpp"
61 #include "common/timer.hpp"
62 #include "net/ip6_address.hpp"
63 #include "thread/network_data_types.hpp"
64 
65 namespace ot {
66 namespace NetworkData {
67 
68 /**
69  * This class implements the Network Data Publisher.
70  *
71  * It provides mechanisms to limit the number of similar Service and/or Prefix (on-mesh prefix or external route)
72  * entries in the Thread Network Data by monitoring the Network Data and managing if or when to add or remove entries.
73  *
74  */
75 class Publisher : public InstanceLocator, private NonCopyable
76 {
77     friend class ot::Notifier;
78 
79 public:
80     /**
81      * This enumeration represents the events reported from the Publisher callbacks.
82      *
83      */
84     enum Event : uint8_t
85     {
86         kEventEntryAdded   = OT_NETDATA_PUBLISHER_EVENT_ENTRY_ADDED,   ///< Entry is added to Network Data.
87         kEventEntryRemoved = OT_NETDATA_PUBLISHER_EVENT_ENTRY_REMOVED, ///< Entry is removed from Network Data.
88     };
89 
90     /**
91      * This constructor initializes `Publisher` object.
92      *
93      * @param[in]  aInstance     A reference to the OpenThread instance.
94      *
95      */
96     explicit Publisher(Instance &aInstance);
97 
98 #if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
99 
100     /**
101      * This type represents the callback function pointer used to notify when a "DNS/SRP Service" entry is added to or
102      * removed from the Thread Network Data.
103      *
104      * On remove the callback is invoked independent of whether the entry is removed by `Publisher` (e.g., when there
105      * are too many similar entries already present in the Network Data) or through an explicit call to unpublish the
106      * entry (i.e., a call to `UnpublishDnsSrpService()`).
107      *
108      */
109     typedef otNetDataDnsSrpServicePublisherCallback DnsSrpServiceCallback;
110 
111     /**
112      * This method sets a callback for notifying when a published "DNS/SRP Service" is actually added to or removed
113      * from the Thread Network Data.
114      *
115      * A subsequent call to this method replaces any previously set callback function.
116      *
117      * @param[in] aCallback        The callback function pointer (can be NULL if not needed).
118      * @param[in] aContext         A pointer to application-specific context (used when @p aCallback is invoked).
119      *
120      */
SetDnsSrpServiceCallback(DnsSrpServiceCallback aCallback,void * aContext)121     void SetDnsSrpServiceCallback(DnsSrpServiceCallback aCallback, void *aContext)
122     {
123         mDnsSrpServiceEntry.SetCallback(aCallback, aContext);
124     }
125 
126     /**
127      * This method requests "DNS/SRP Service Anycast Address" to be published in the Thread Network Data.
128      *
129      * A call to this method will remove and replace any previous "DNS/SRP Service" entry that was being published
130      * (from earlier call to any of `PublishDnsSrpService{Type}()` methods).
131      *
132      * @param[in] aSequenceNumber  The sequence number of DNS/SRP Anycast Service.
133      *
134      */
PublishDnsSrpServiceAnycast(uint8_t aSequenceNumber)135     void PublishDnsSrpServiceAnycast(uint8_t aSequenceNumber) { mDnsSrpServiceEntry.PublishAnycast(aSequenceNumber); }
136 
137     /**
138      * This method requests "DNS/SRP Service Unicast Address" to be published in the Thread Network Data.
139      *
140      * A call to this method will remove and replace any previous "DNS/SRP Service" entry that was being published
141      * (from earlier call to any of `PublishDnsSrpService{Type}()` methods).
142      *
143      * This method publishes the "DNS/SRP Service Unicast Address" by including the address and port info in the
144      * Service TLV data.
145      *
146      * @param[in] aAddress   The DNS/SRP server address to publish.
147      * @param[in] aPort      The SRP server port number to publish.
148      *
149      */
PublishDnsSrpServiceUnicast(const Ip6::Address & aAddress,uint16_t aPort)150     void PublishDnsSrpServiceUnicast(const Ip6::Address &aAddress, uint16_t aPort)
151     {
152         mDnsSrpServiceEntry.PublishUnicast(aAddress, aPort);
153     }
154 
155     /**
156      * This method requests "DNS/SRP Service Unicast Address" to be published in the Thread Network Data.
157      *
158      * A call to this method will remove and replace any previous "DNS/SRP Service" entry that was being published
159      * (from earlier call to any of `PublishDnsSrpService{Type}()` methods).
160      *
161      * Unlike the `PublishDnsSrpServiceUnicast(aAddress, aPort)` which requires the published address to be given and
162      * includes the info in the Service TLV data, this method uses the device's mesh-local EID and includes the info
163      * in the Server TLV data.
164      *
165      * @param[in] aPort      The SRP server port number to publish.
166      *
167      */
PublishDnsSrpServiceUnicast(uint16_t aPort)168     void PublishDnsSrpServiceUnicast(uint16_t aPort) { mDnsSrpServiceEntry.PublishUnicast(aPort); }
169 
170     /**
171      * This method indicates whether or not currently the "DNS/SRP Service" entry is added to the Thread Network Data.
172      *
173      * @retval TRUE    The published DNS/SRP Service entry is added to the Thread Network Data.
174      * @retval FALSE   The entry is not added to Thread Network Data or there is no entry to publish.
175      *
176      */
IsDnsSrpServiceAdded(void) const177     bool IsDnsSrpServiceAdded(void) const { return mDnsSrpServiceEntry.IsAdded(); }
178 
179     /**
180      * This method unpublishes any previously added "DNS/SRP (Anycast or Unicast) Service" entry from the Thread
181      * Network Data.
182      *
183      */
UnpublishDnsSrpService(void)184     void UnpublishDnsSrpService(void) { mDnsSrpServiceEntry.Unpublish(); }
185 
186 #endif // OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
187 
188 #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
189     /**
190      * This type represents the callback function pointer used to notify when a prefix (on-mesh or external route)
191      * entry is added to or removed from the Thread Network Data.
192      *
193      * On remove the callback is invoked independent of whether the entry is removed by `Publisher` (e.g., when there
194      * are too many similar entries already present in the Network Data) or through an explicit call to unpublish the
195      * entry.
196      *
197      */
198     typedef otNetDataPrefixPublisherCallback PrefixCallback;
199 
200     /**
201      * This method sets a callback for notifying when a published prefix entry is actually added to or removed from
202      * the Thread Network Data.
203      *
204      * A subsequent call to this method replaces any previously set callback function.
205      *
206      * @param[in] aCallback        The callback function pointer (can be NULL if not needed).
207      * @param[in] aContext         A pointer to application-specific context (used when @p aCallback is invoked).
208      *
209      */
210     void SetPrefixCallback(PrefixCallback aCallback, void *aContext);
211 
212     /**
213      * This method requests an on-mesh prefix to be published in the Thread Network Data.
214      *
215      * Only stable entries can be published (i.e.,`aConfig.mStable` MUST be `true`).
216      *
217      * A subsequent call to this method will replace a previous request for the same prefix. In particular if the
218      * new call only changes the flags (e.g., preference level) and the prefix is already added in the Network Data,
219      * the change to flags is immediately reflected in the Network Data. This ensures that existing entries in the
220      * Network Data are not abruptly removed. Note that a change in the preference level can potentially later cause
221      * the entry to be removed from the Network Data after determining there are other nodes that are publishing the
222      * same prefix with the same or higher preference.
223      *
224      * @param[in] aConfig         The on-mesh prefix config to publish.
225      *
226      * @retval kErrorNone         The on-mesh prefix is published successfully.
227      * @retval kErrorInvalidArgs  The @p aConfig is not valid (bad prefix, invalid flag combinations, or not stable).
228      * @retval kErrorAlready      An entry with the same prefix is already in the published list.
229      * @retval kErrorNoBufs       Could not allocate an entry for the new request. Publisher supports a limited number
230      *                            of entries (shared between on-mesh prefix and external route) determined by config
231      *                            `OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_PREFIX_ENTRIES`.
232      *
233      *
234      */
235     Error PublishOnMeshPrefix(const OnMeshPrefixConfig &aConfig);
236 
237     /**
238      * This method requests an external route prefix to be published in the Thread Network Data.
239      *
240      * Only stable entries can be published (i.e.,`aConfig.mStable` MUST be `true`).
241      *
242      * A subsequent call to this method will replace a previous request for the same prefix. In particular if the
243      * new call only changes the flags (e.g., preference level) and the prefix is already added in the Network Data,
244      * the change to flags is immediately reflected in the Network Data. This ensures that existing entries in the
245      * Network Data are not abruptly removed. Note that a change in the preference level can potentially later cause
246      * the entry to be removed from the Network Data after determining there are other nodes that are publishing the
247      * same prefix with the same or higher preference.
248      *
249      * @param[in] aConfig         The external route config to publish.
250      *
251      * @retval kErrorNone         The external route is published successfully.
252      * @retval kErrorInvalidArgs  The @p aConfig is not valid (bad prefix, invalid flag combinations, or not stable).
253      * @retval kErrorNoBufs       Could not allocate an entry for the new request. Publisher supports a limited number
254      *                            of entries (shared between on-mesh prefix and external route) determined by config
255      *                            `OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_PREFIX_ENTRIES`.
256      *
257      *
258      */
259     Error PublishExternalRoute(const ExternalRouteConfig &aConfig);
260 
261     /**
262      * This method indicates whether or not currently a published prefix entry (on-mesh or external route) is added to
263      * the Thread Network Data.
264      *
265      * @param[in] aPrefix   The prefix to check.
266      *
267      * @retval TRUE    The published prefix entry is added to the Thread Network Data.
268      * @retval FALSE   The entry is not added to Thread Network Data or there is no matching entry to publish.
269      *
270      */
271     bool IsPrefixAdded(const Ip6::Prefix &aPrefix) const;
272 
273     /**
274      * This method unpublishes a previously published prefix (on-mesh or external route).
275      *
276      * @param[in] aPrefix       The prefix to unpublish.
277      *
278      * @retval kErrorNone       The prefix was unpublished successfully.
279      * @retval kErrorNotFound   Could not find the prefix in the published list.
280      *
281      */
282     Error UnpublishPrefix(const Ip6::Prefix &aPrefix);
283 #endif // OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
284 
285 private:
286     class Entry : public InstanceLocatorInit
287     {
288     protected:
289         enum State : uint8_t
290         {
291             kNoEntry,  // Entry is unused (there is no entry).
292             kToAdd,    // Entry is ready to be added, monitoring network data to decide if/when to add it.
293             kAdding,   // Entry is being added in network data (random wait interval before add).
294             kAdded,    // Entry is added in network data, monitoring to determine if/when to remove.
295             kRemoving, // Entry is being removed from network data (random wait interval before remove).
296         };
297 
298         // All intervals are in milliseconds.
299         static constexpr uint32_t kMaxDelayToAdd    = OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_DELAY_TO_ADD;
300         static constexpr uint32_t kMaxDelayToRemove = OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_DELAY_TO_REMOVE;
301         static constexpr uint32_t kExtraDelayToRemovePeferred =
302             OPENTHREAD_CONFIG_NETDATA_PUBLISHER_EXTRA_DELAY_TIME_TO_REMOVE_PREFERRED;
303 
304         static constexpr uint16_t kInfoStringSize = 50;
305 
306         typedef String<kInfoStringSize> InfoString;
307 
Entry(void)308         Entry(void)
309             : mState(kNoEntry)
310         {
311         }
312 
Init(Instance & aInstance)313         void             Init(Instance &aInstance) { InstanceLocatorInit::Init(aInstance); }
GetState(void) const314         State            GetState(void) const { return mState; }
315         void             SetState(State aState);
GetUpdateTime(void) const316         const TimeMilli &GetUpdateTime(void) const { return mUpdateTime; }
317         bool             IsPreferred(uint16_t aRloc16) const;
318         void             UpdateState(uint8_t aNumEntries, uint8_t aNumPreferredEntries, uint8_t aDesiredNumEntries);
319         void             HandleTimer(void);
320         InfoString       ToString(bool aIncludeState = true) const;
321 
322     public:
IsAdded(void) const323         bool IsAdded(void) const { return (mState == kAdded); }
324 
325     private:
326         void               Add(void);
327         void               Remove(State aNextState);
328         void               LogUpdateTime(void) const;
329         static const char *StateToString(State aState);
330 
331         TimeMilli mUpdateTime;
332         State     mState;
333     };
334 
335 #if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
336     class DnsSrpServiceEntry : public Entry, private NonCopyable
337     {
338         friend class Entry;
339 
340     public:
341         explicit DnsSrpServiceEntry(Instance &aInstance);
342         void SetCallback(DnsSrpServiceCallback aCallback, void *aContext);
343         void PublishAnycast(uint8_t aSequenceNumber);
344         void PublishUnicast(const Ip6::Address &aAddress, uint16_t aPort);
345         void PublishUnicast(uint16_t aPort);
346         void Unpublish(void);
HandleTimer(void)347         void HandleTimer(void) { Entry::HandleTimer(); }
348         void HandleNotifierEvents(Events aEvents);
349 
350     private:
351         static constexpr uint8_t kDesiredNumAnycast =
352             OPENTHREAD_CONFIG_NETDATA_PUBLISHER_DESIRED_NUM_ANYCAST_DNS_SRP_SERVICE_ENTRIES;
353 
354         static constexpr uint8_t kDesiredNumUnicast =
355             OPENTHREAD_CONFIG_NETDATA_PUBLISHER_DESIRED_NUM_UNICAST_DNS_SRP_SERVICE_ENTRIES;
356 
357         enum Type : uint8_t
358         {
359             kTypeAnycast,
360             kTypeUnicast,
361             kTypeUnicastMeshLocalEid,
362         };
363 
364         class Info : public Clearable<Info>, public Equatable<Info>
365         {
366         public:
Info(void)367             Info(void) { Clear(); }
GetType(void) const368             Type                GetType(void) const { return mType; }
GetSequenceNumber(void) const369             uint8_t             GetSequenceNumber(void) const { return static_cast<uint8_t>(mPortOrSeqNumber); }
GetPort(void) const370             uint16_t            GetPort(void) const { return mPortOrSeqNumber; }
GetAddress(void) const371             const Ip6::Address &GetAddress(void) const { return mAddress; }
SetAddress(const Ip6::Address & aAddress)372             void                SetAddress(const Ip6::Address &aAddress) { mAddress = aAddress; }
373 
InfoAnycast(uint8_t aSequenceNumber)374             static Info InfoAnycast(uint8_t aSequenceNumber) { return Info(kTypeAnycast, aSequenceNumber); }
InfoUnicast(Type aType,const Ip6::Address & aAddress,uint16_t aPort)375             static Info InfoUnicast(Type aType, const Ip6::Address &aAddress, uint16_t aPort)
376             {
377                 return Info(aType, aPort, &aAddress);
378             }
379 
380         private:
381             Info(Type aType, uint16_t aPortOrSeqNumber, const Ip6::Address *aAddress = nullptr);
382 
383             Ip6::Address mAddress;
384             uint16_t     mPortOrSeqNumber;
385             Type         mType;
386         };
387 
GetType(void) const388         Type GetType(void) const { return mInfo.GetType(); }
389         void Publish(const Info &aInfo);
390         void Add(void);
391         void Remove(State aNextState);
392         void Notify(Event aEvent) const;
393         void Process(void);
394         void CountAnycastEntries(uint8_t &aNumEntries, uint8_t &aNumPreferredEntries) const;
395         void CountUnicastEntries(uint8_t &aNumEntries, uint8_t &aNumPreferredEntries) const;
396 
397         Info                  mInfo;
398         DnsSrpServiceCallback mCallback;
399         void *                mCallbackContext;
400     };
401 #endif // OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
402 
403 #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
404     // Max number of prefix (on-mesh or external route) entries.
405     static constexpr uint16_t kMaxPrefixEntries = OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_PREFIX_ENTRIES;
406 
407     class PrefixEntry : public Entry, private NonCopyable
408     {
409         friend class Entry;
410 
411     public:
Init(Instance & aInstance)412         void Init(Instance &aInstance) { Entry::Init(aInstance); }
IsInUse(void) const413         bool IsInUse(void) const { return GetState() != kNoEntry; }
Matches(const Ip6::Prefix & aPrefix) const414         bool Matches(const Ip6::Prefix &aPrefix) const { return mPrefix == aPrefix; }
415         void Publish(const OnMeshPrefixConfig &aConfig);
416         void Publish(const ExternalRouteConfig &aConfig);
417         void Unpublish(void);
HandleTimer(void)418         void HandleTimer(void) { Entry::HandleTimer(); }
419         void HandleNotifierEvents(Events aEvents);
420 
421     private:
422         static constexpr uint8_t kDesiredNumOnMeshPrefix =
423             OPENTHREAD_CONFIG_NETDATA_PUBLISHER_DESIRED_NUM_ON_MESH_PREFIX_ENTRIES;
424 
425         static constexpr uint8_t kDesiredNumExternalRoute =
426             OPENTHREAD_CONFIG_NETDATA_PUBLISHER_DESIRED_NUM_EXTERNAL_ROUTE_ENTRIES;
427 
428         enum Type : uint8_t
429         {
430             kTypeOnMeshPrefix,
431             kTypeExternalRoute,
432         };
433 
434         void  Publish(const Ip6::Prefix &aPrefix, uint16_t aNewFlags, Type aNewType);
435         void  Add(void);
436         Error AddOnMeshPrefix(void);
437         Error AddExternalRoute(void);
438         void  Remove(State aNextState);
439         void  Process(void);
440         void  CountOnMeshPrefixEntries(uint8_t &aNumEntries, uint8_t &aNumPreferredEntries) const;
441         void  CountExternalRouteEntries(uint8_t &aNumEntries, uint8_t &aNumPreferredEntries) const;
442 
443         Type        mType;
444         Ip6::Prefix mPrefix;
445         uint16_t    mFlags;
446     };
447 #endif // OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
448 
449 #if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
IsADnsSrpServiceEntry(const Entry & aEntry) const450     bool IsADnsSrpServiceEntry(const Entry &aEntry) const { return (&aEntry == &mDnsSrpServiceEntry); }
451 #endif
452 
453 #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
454     PrefixEntry *      FindOrAllocatePrefixEntry(const Ip6::Prefix &aPrefix);
455     PrefixEntry *      FindMatchingPrefixEntry(const Ip6::Prefix &aPrefix);
456     const PrefixEntry *FindMatchingPrefixEntry(const Ip6::Prefix &aPrefix) const;
457     bool               IsAPrefixEntry(const Entry &aEntry) const;
458     void               NotifyPrefixEntryChange(Event aEvent, const Ip6::Prefix &aPrefix) const;
459 #endif
460 
GetTimer(void)461     TimerMilli &GetTimer(void) { return mTimer; }
462     void        HandleNotifierEvents(Events aEvents);
463     static void HandleTimer(Timer &aTimer);
464     void        HandleTimer(void);
465 
466 #if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
467     DnsSrpServiceEntry mDnsSrpServiceEntry;
468 #endif
469 
470 #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
471     PrefixEntry    mPrefixEntries[kMaxPrefixEntries];
472     PrefixCallback mPrefixCallback;
473     void *         mPrefixCallbackContext;
474 #endif
475 
476     TimerMilli mTimer;
477 };
478 
479 } // namespace NetworkData
480 } // namespace ot
481 
482 #endif // OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE
483 
484 #endif // NETWORK_DATA_PUBLISHER_HPP_
485