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: 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* 45* int set_mac_addr(const mac_addr_t& mac) override 46* { 47* mac_addr = mac; 48* 49* return 0; 50* } 51* 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: 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* 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: 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: 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* 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* 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* 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* 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* 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* 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*