xref: /openbmc/google-misc/subprojects/ncsid/test/ncsi_test.cpp (revision dab96f131fb3a46d93f1093feccc9095d8589ece)
1* // Copyright 2021 Google LLC
2* //
3* // Licensed under the Apache License, Version 2.0 (the "License");
4* // you may not use this file except in compliance with the License.
5* // You may obtain a copy of the License at
6* //
7* //      http://www.apache.org/licenses/LICENSE-2.0
8* //
9* // Unless required by applicable law or agreed to in writing, software
10* // distributed under the License is distributed on an "AS IS" BASIS,
11* // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12* // See the License for the specific language governing permissions and
13* // limitations under the License.
14* 
15* #include "net_iface_mock.h"
16* #include "nic_mock.h"
17* #include "platforms/nemora/portable/default_addresses.h"
18* #include "platforms/nemora/portable/ncsi.h"
19* #include "platforms/nemora/portable/ncsi_fsm.h"
20* #include "platforms/nemora/portable/net_types.h"
21* 
22* #include <ncsi_state_machine.h>
23* #include <net_config.h>
24* #include <net_sockio.h>
25* #include <netinet/ether.h>
26* #include <netinet/in.h>
27* 
28* #include <gmock/gmock.h>
29* 
30* namespace
31* {
32* 
33* constexpr uint32_t ETHER_NCSI = 0x88f8;
34* 
35* class MockConfig : public net::ConfigBase
36* {
37*   public:
get_mac_addr(mac_addr_t * mac)38*     int get_mac_addr(mac_addr_t* mac) override
39*     {
40*         std::memcpy(mac, &mac_addr, sizeof(mac_addr_t));
41* 
42*         return 0;
43*     }
44* 
set_mac_addr(const mac_addr_t & mac)45*     int set_mac_addr(const mac_addr_t& mac) override
46*     {
47*         mac_addr = mac;
48* 
49*         return 0;
50*     }
51* 
set_nic_hostless(bool is_hostless)52*     int set_nic_hostless(bool is_hostless) override
53*     {
54*         is_nic_hostless = is_hostless;
55* 
56*         return 0;
57*     }
58* 
59*     mac_addr_t mac_addr;
60*     bool is_nic_hostless = true;
61* };
62* 
63* class NICConnection : public net::SockIO
64* {
65*   public:
write(const void * buf,size_t len)66*     int write(const void* buf, size_t len) override
67*     {
68*         conseq_reads = 0;
69*         ++n_writes;
70*         std::memcpy(last_write.data, buf, len);
71*         last_write.len = len;
72*         const auto* hdr = reinterpret_cast<const struct ether_header*>(buf);
73*         if (ETHER_NCSI == ntohs(hdr->ether_type))
74*         {
75*             ++n_handles;
76*             next_read.len = nic_mock.handle_request(last_write, &next_read);
77*         }
78* 
79*         return len;
80*     }
81* 
recv(void * buf,size_t maxlen)82*     int recv(void* buf, size_t maxlen) override
83*     {
84*         ++n_reads;
85*         ++conseq_reads;
86* 
87*         if (read_timeout > 0)
88*         {
89*             if (conseq_reads > read_timeout)
90*             {
91*                 return 0;
92*             }
93*         }
94* 
95*         if (maxlen < next_read.len)
96*         {
97*             ++n_read_errs;
98*             return 0;
99*         }
100* 
101*         std::memcpy(buf, next_read.data, next_read.len);
102* 
103*         return next_read.len;
104*     }
105* 
106*     mock::NIC nic_mock{false, 2};
107*     int n_writes = 0;
108*     int n_reads = 0;
109*     int n_handles = 0;
110*     int n_read_errs = 0;
111* 
112*     // Max number of consequitive reads without writes.
113*     int read_timeout = -1;
114*     int conseq_reads = 0;
115* 
116*     ncsi_buf_t last_write = {};
117*     ncsi_buf_t next_read = {};
118* };
119* 
120* } // namespace
121* 
122* class TestNcsi : public testing::Test
123* {
124*   public:
SetUp()125*     void SetUp() override
126*     {
127*         ncsi_sm.set_sockio(&ncsi_sock);
128*         ncsi_sm.set_net_config(&net_config_mock);
129*         ncsi_sm.set_retest_delay(0);
130*         ncsi_sock.nic_mock.set_mac(nic_mac);
131*         ncsi_sock.nic_mock.set_hostless(true);
132*         ncsi_sock.read_timeout = 10;
133*     }
134* 
135*   protected:
ExpectFiltersNotConfigured()136*     void ExpectFiltersNotConfigured()
137*     {
138*         for (uint8_t i = 0; i < ncsi_sock.nic_mock.get_channel_count(); ++i)
139*         {
140*             EXPECT_FALSE(ncsi_sock.nic_mock.is_filter_configured(i));
141*         }
142*     }
143* 
ExpectFiltersConfigured()144*     void ExpectFiltersConfigured()
145*     {
146*         // Check that filters are configured on all channels.
147*         for (uint8_t i = 0; i < ncsi_sock.nic_mock.get_channel_count(); ++i)
148*         {
149*             EXPECT_TRUE(ncsi_sock.nic_mock.is_filter_configured(i));
150*             const ncsi_oem_filter_t& ch_filter =
151*                 ncsi_sock.nic_mock.get_filter(i);
152* 
153*             for (unsigned i = 0; i < sizeof(nic_mac.octet); ++i)
154*             {
155*                 EXPECT_EQ(nic_mac.octet[i], ch_filter.mac[i]);
156*             }
157* 
158*             EXPECT_EQ(ch_filter.ip, 0);
159*             const uint16_t filter_port = ntohs(ch_filter.port);
160*             EXPECT_EQ(filter_port, DEFAULT_ADDRESSES_RX_PORT);
161*         }
162*     }
163* 
164*     MockConfig net_config_mock;
165*     NICConnection ncsi_sock;
166*     ncsi::StateMachine ncsi_sm;
167*     const mac_addr_t nic_mac = {{0xde, 0xca, 0xfb, 0xad, 0x01, 0x02}};
168* 
169*     // Number of states in each state machine
170*     static constexpr int l2_num_states = 26;
171*     static constexpr int l3l4_num_states = 2;
172*     static constexpr int test_num_states = 9;
173* 
174*     // Total number of states in all three state machines.
175*     static constexpr int total_num_states =
176*         l2_num_states + l3l4_num_states + test_num_states;
177* };
178* 
TEST_F(TestNcsi,TestMACAddrPropagation)179* TEST_F(TestNcsi, TestMACAddrPropagation)
180* {
181*     ncsi_sm.run(total_num_states);
182*     EXPECT_EQ(ncsi_sock.n_read_errs, 0);
183*     EXPECT_EQ(ncsi_sock.n_handles, ncsi_sock.n_writes);
184*     EXPECT_EQ(0, std::memcmp(nic_mac.octet, net_config_mock.mac_addr.octet,
185*                              sizeof(nic_mac.octet)));
186* 
187*     // Since network is not configured, the filters should not be configured
188*     // either.
189*     ExpectFiltersNotConfigured();
190* }
191* 
TEST_F(TestNcsi,TestFilterConfiguration)192* TEST_F(TestNcsi, TestFilterConfiguration)
193* {
194*     ncsi_sm.run(total_num_states);
195*     EXPECT_EQ(ncsi_sock.n_read_errs, 0);
196*     EXPECT_EQ(ncsi_sock.n_handles, ncsi_sock.n_writes);
197* 
198*     ExpectFiltersConfigured();
199* }
200* 
TEST_F(TestNcsi,TestFilterReset)201* TEST_F(TestNcsi, TestFilterReset)
202* {
203*     ncsi_sm.run(total_num_states);
204*     EXPECT_EQ(ncsi_sock.n_read_errs, 0);
205*     EXPECT_EQ(ncsi_sock.n_handles, ncsi_sock.n_writes);
206* 
207*     // Since network is not configured, the filters should not be configured
208*     // either.
209*     ExpectFiltersNotConfigured();
210* 
211*     ncsi_sm.run(total_num_states);
212* 
213*     ExpectFiltersConfigured();
214* }
215* 
TEST_F(TestNcsi,TestRetest)216* TEST_F(TestNcsi, TestRetest)
217* {
218*     ncsi_sm.run(total_num_states + test_num_states);
219* 
220*     // Verify that the test state machine was stepped through twice,
221*     // by counting how many times the last command of the state machine
222*     // has been executed.
223*     const uint8_t last_test_command = NCSI_GET_LINK_STATUS;
224*     const auto& cmd_log = ncsi_sock.nic_mock.get_command_log();
225*     int num_test_runs = 0;
226*     for (const auto& ncsi_frame : cmd_log)
227*     {
228*         if (ncsi_frame.get_control_packet_type() == last_test_command)
229*         {
230*             ++num_test_runs;
231*         }
232*     }
233* 
234*     EXPECT_EQ(num_test_runs, 2);
235* }
236* 
TEST_F(TestNcsi,TestHostlessSwitch)237* TEST_F(TestNcsi, TestHostlessSwitch)
238* {
239*     // By default the NIC is in hostless mode.
240*     // Verify that net config flag changes after FSM run.
241*     net_config_mock.is_nic_hostless = false;
242*     ncsi_sm.run(total_num_states);
243*     EXPECT_EQ(ncsi_sock.n_read_errs, 0);
244*     EXPECT_EQ(ncsi_sock.n_handles, ncsi_sock.n_writes);
245*     EXPECT_TRUE(net_config_mock.is_nic_hostless);
246* 
247*     // Now disable the hostless mode and verify that net config
248*     // flag changes to false.
249*     ncsi_sock.nic_mock.set_hostless(false);
250*     ncsi_sm.run(total_num_states);
251*     EXPECT_EQ(ncsi_sock.n_read_errs, 0);
252*     EXPECT_EQ(ncsi_sock.n_handles, ncsi_sock.n_writes);
253*     EXPECT_FALSE(net_config_mock.is_nic_hostless);
254* }
255*