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