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*