1 /*
2  *  Copyright (c) 2024, 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 #include <stdarg.h>
30 #include <stdio.h>
31 #include <string.h>
32 
33 #include "platform/nexus_core.hpp"
34 #include "platform/nexus_node.hpp"
35 
36 namespace ot {
37 namespace Nexus {
38 
39 static constexpr uint16_t kNumberOfRoles = (Mle::kRoleLeader + 1);
40 
41 typedef uint16_t RoleStats[kNumberOfRoles];
42 
CaculateRoleStats(Core & aNexus,RoleStats & aRoleStats)43 static void CaculateRoleStats(Core &aNexus, RoleStats &aRoleStats)
44 {
45     ClearAllBytes(aRoleStats);
46 
47     for (Node &node : aNexus.GetNodes())
48     {
49         aRoleStats[node.Get<Mle::Mle>().GetRole()]++;
50     }
51 }
52 
CheckRoleStats(const RoleStats & aRoleStats)53 static bool CheckRoleStats(const RoleStats &aRoleStats)
54 {
55     return (aRoleStats[Mle::kRoleLeader] == 1) && (aRoleStats[Mle::kRoleDetached] == 0) &&
56            (aRoleStats[Mle::kRoleDisabled] == 0);
57 }
58 
Test(void)59 void Test(void)
60 {
61     static constexpr uint16_t kNumNodes = 200;
62 
63     // All times in msec
64     static constexpr uint32_t kMaxWaitTime            = 20 * Time::kOneMinuteInMsec;
65     static constexpr uint32_t kStatCollectionInterval = 125;
66     static constexpr uint32_t kExtraSimulTimAfterPass = 5 * Time::kOneSecondInMsec;
67 
68     Core      nexus;
69     Node     *leader;
70     RoleStats roleStats;
71 
72     for (uint16_t i = 0; i < kNumNodes; i++)
73     {
74         nexus.CreateNode();
75     }
76 
77     nexus.AdvanceTime(0);
78 
79     Log("Starting %u nodes simultaneously", kNumNodes);
80 
81     leader = nexus.GetNodes().GetHead();
82     leader->Form();
83 
84     for (Node &node : nexus.GetNodes())
85     {
86         if (&node == leader)
87         {
88             continue;
89         }
90 
91         node.Join(*leader);
92     }
93 
94     for (uint32_t step = 0; step < kMaxWaitTime / kStatCollectionInterval; step++)
95     {
96         if ((step % 20) == 0)
97         {
98             Log("+----------+----------+----------+----------+----------+");
99             Log("| Leader   | Router   | Child    | Detached | Disabled |");
100             Log("+----------+----------+----------+----------+----------+");
101         }
102 
103         CaculateRoleStats(nexus, roleStats);
104 
105         Log("| %8u | %8u | %8u | %8u | %8u |", roleStats[Mle::kRoleLeader], roleStats[Mle::kRoleRouter],
106             roleStats[Mle::kRoleChild], roleStats[Mle::kRoleDetached], roleStats[Mle::kRoleDisabled]);
107 
108         nexus.AdvanceTime(kStatCollectionInterval);
109 
110         if (CheckRoleStats(roleStats))
111         {
112             break;
113         }
114     }
115 
116     VerifyOrQuit(CheckRoleStats(roleStats));
117 
118     Log("=========================================================");
119     Log("All nodes are now part of the same partition");
120     Log("Network stabilized after %u sec", nexus.GetNow().GetValue() / Time::kOneSecondInMsec);
121     Log("Continue simulation for another %u sec", kExtraSimulTimAfterPass / Time::kOneSecondInMsec);
122     Log("=========================================================");
123 
124     for (uint32_t step = 0; step < kExtraSimulTimAfterPass / kStatCollectionInterval; step++)
125     {
126         if ((step % 20) == 0)
127         {
128             Log("+----------+----------+----------+----------+----------+");
129             Log("| Leader   | Router   | Child    | Detached | Disabled |");
130             Log("+----------+----------+----------+----------+----------+");
131         }
132 
133         CaculateRoleStats(nexus, roleStats);
134 
135         Log("| %8u | %8u | %8u | %8u | %8u |", roleStats[Mle::kRoleLeader], roleStats[Mle::kRoleRouter],
136             roleStats[Mle::kRoleChild], roleStats[Mle::kRoleDetached], roleStats[Mle::kRoleDisabled]);
137 
138         nexus.AdvanceTime(kStatCollectionInterval);
139     }
140 }
141 
142 } // namespace Nexus
143 } // namespace ot
144 
main(void)145 int main(void)
146 {
147     ot::Nexus::Test();
148     printf("All tests passed\n");
149     return 0;
150 }
151