1 #include "config_parser.hpp" 2 #include "ipaddress.hpp" 3 #include "mock_network_manager.hpp" 4 #include "mock_syscall.hpp" 5 #include "system_queries.hpp" 6 #include "util.hpp" 7 8 #include <arpa/inet.h> 9 #include <net/if.h> 10 #include <netinet/in.h> 11 #include <stdlib.h> 12 13 #include <charconv> 14 #include <exception> 15 #include <sdbusplus/bus.hpp> 16 #include <stdplus/gtest/tmp.hpp> 17 #include <string_view> 18 #include <xyz/openbmc_project/Common/error.hpp> 19 20 #include <gmock/gmock.h> 21 #include <gtest/gtest.h> 22 23 namespace phosphor 24 { 25 namespace network 26 { 27 28 using std::literals::string_view_literals::operator""sv; 29 using testing::Key; 30 using testing::UnorderedElementsAre; 31 32 class TestEthernetInterface : public stdplus::gtest::TestWithTmp 33 { 34 public: 35 sdbusplus::bus_t bus; 36 std::string confDir; 37 MockManager manager; 38 MockEthernetInterface interface; 39 TestEthernetInterface() : 40 bus(sdbusplus::bus::new_default()), confDir(CaseTmpDir()), 41 manager(bus, "/xyz/openbmc_test/network", confDir), 42 interface(makeInterface(bus, manager)) 43 44 { 45 } 46 47 static MockEthernetInterface makeInterface(sdbusplus::bus_t& bus, 48 MockManager& manager) 49 { 50 system::mock_clear(); 51 InterfaceInfo info{.idx = 1, .flags = 0, .name = "test0"}; 52 system::mock_addIF(info); 53 return {bus, manager, info, "/xyz/openbmc_test/network"sv, 54 config::Parser()}; 55 } 56 57 auto createIPObject(IP::Protocol addressType, const std::string& ipaddress, 58 uint8_t subnetMask) 59 { 60 return interface.ip(addressType, ipaddress, subnetMask, ""); 61 } 62 63 void setNtpServers() 64 { 65 ServerList ntpServers = {"10.1.1.1", "10.2.2.2", "10.3.3.3"}; 66 interface.EthernetInterfaceIntf::ntpServers(ntpServers); 67 } 68 69 ServerList getNtpServers() 70 { 71 return interface.EthernetInterfaceIntf::ntpServers(); 72 } 73 }; 74 75 TEST_F(TestEthernetInterface, Fields) 76 { 77 EXPECT_EQ(0, interface.mtu()); 78 EXPECT_EQ("", interface.macAddress()); 79 EXPECT_FALSE(interface.linkUp()); 80 81 constexpr ether_addr mac{0x11, 0x22, 0x33, 0x44, 0x55, 0x66}; 82 constexpr unsigned mtu = 150; 83 84 InterfaceInfo info{.idx = 2, 85 .flags = IFF_RUNNING, 86 .name = "test1", 87 .mac = mac, 88 .mtu = mtu}; 89 system::mock_addIF(info); 90 MockEthernetInterface intf(bus, manager, info, 91 "/xyz/openbmc_test/network"sv, config::Parser()); 92 93 EXPECT_EQ(mtu, intf.mtu()); 94 EXPECT_EQ(std::to_string(mac), intf.macAddress()); 95 EXPECT_TRUE(intf.linkUp()); 96 } 97 98 TEST_F(TestEthernetInterface, NoIPaddress) 99 { 100 EXPECT_TRUE(interface.addrs.empty()); 101 } 102 103 TEST_F(TestEthernetInterface, AddIPAddress) 104 { 105 createIPObject(IP::Protocol::IPv4, "10.10.10.10", 16); 106 EXPECT_THAT(interface.addrs, UnorderedElementsAre(Key( 107 IfAddr(in_addr{htonl(0x0a0a0a0a)}, 16)))); 108 } 109 110 TEST_F(TestEthernetInterface, AddMultipleAddress) 111 { 112 createIPObject(IP::Protocol::IPv4, "10.10.10.10", 16); 113 createIPObject(IP::Protocol::IPv4, "20.20.20.20", 16); 114 EXPECT_THAT( 115 interface.addrs, 116 UnorderedElementsAre(Key(IfAddr(in_addr{htonl(0x0a0a0a0a)}, 16)), 117 Key(IfAddr(in_addr{htonl(0x14141414)}, 16)))); 118 } 119 120 TEST_F(TestEthernetInterface, DeleteIPAddress) 121 { 122 createIPObject(IP::Protocol::IPv4, "10.10.10.10", 16); 123 createIPObject(IP::Protocol::IPv4, "20.20.20.20", 16); 124 interface.addrs.at(IfAddr(in_addr{htonl(0x0a0a0a0a)}, 16))->delete_(); 125 EXPECT_THAT(interface.addrs, UnorderedElementsAre(Key( 126 IfAddr(in_addr{htonl(0x14141414)}, 16)))); 127 } 128 129 TEST_F(TestEthernetInterface, CheckObjectPath) 130 { 131 auto path = createIPObject(IP::Protocol::IPv4, "10.10.10.10", 16); 132 EXPECT_EQ(path.parent_path(), "/xyz/openbmc_test/network/test0"); 133 EXPECT_EQ(path.filename(), "10.10.10.10/16"); 134 } 135 136 TEST_F(TestEthernetInterface, addStaticNameServers) 137 { 138 ServerList servers = {"9.1.1.1", "9.2.2.2", "9.3.3.3"}; 139 EXPECT_CALL(manager, reloadConfigsNoRefresh()); 140 interface.staticNameServers(servers); 141 fs::path filePath = confDir; 142 filePath /= "00-bmc-test0.network"; 143 config::Parser parser(filePath.string()); 144 EXPECT_EQ(servers, parser.map.getValueStrings("Network", "DNS")); 145 } 146 147 TEST_F(TestEthernetInterface, getDynamicNameServers) 148 { 149 ServerList servers = {"9.1.1.1", "9.2.2.2", "9.3.3.3"}; 150 EXPECT_CALL(interface, getNameServerFromResolvd()) 151 .WillRepeatedly(testing::Return(servers)); 152 EXPECT_EQ(interface.getNameServerFromResolvd(), servers); 153 } 154 155 TEST_F(TestEthernetInterface, addStaticNTPServers) 156 { 157 ServerList servers = {"10.1.1.1", "10.2.2.2", "10.3.3.3"}; 158 EXPECT_CALL(manager, reloadConfigsNoRefresh()); 159 interface.staticNTPServers(servers); 160 fs::path filePath = confDir; 161 filePath /= "00-bmc-test0.network"; 162 config::Parser parser(filePath.string()); 163 EXPECT_EQ(servers, parser.map.getValueStrings("Network", "NTP")); 164 } 165 166 TEST_F(TestEthernetInterface, addNTPServers) 167 { 168 using namespace sdbusplus::xyz::openbmc_project::Common::Error; 169 ServerList servers = {"10.1.1.1", "10.2.2.2", "10.3.3.3"}; 170 EXPECT_THROW(interface.ntpServers(servers), NotAllowed); 171 } 172 173 TEST_F(TestEthernetInterface, getNTPServers) 174 { 175 ServerList servers = {"10.1.1.1", "10.2.2.2", "10.3.3.3"}; 176 setNtpServers(); 177 EXPECT_EQ(getNtpServers(), servers); 178 } 179 180 TEST_F(TestEthernetInterface, addGateway) 181 { 182 std::string gateway = "10.3.3.3"; 183 interface.defaultGateway(gateway); 184 EXPECT_EQ(interface.defaultGateway(), gateway); 185 interface.defaultGateway(""); 186 EXPECT_EQ(interface.defaultGateway(), ""); 187 } 188 189 TEST_F(TestEthernetInterface, addGateway6) 190 { 191 std::string gateway6 = "ffff:ffff:ffff:fe80::1"; 192 interface.defaultGateway6(gateway6); 193 EXPECT_EQ(interface.defaultGateway6(), gateway6); 194 interface.defaultGateway6(""); 195 EXPECT_EQ(interface.defaultGateway6(), ""); 196 } 197 198 TEST_F(TestEthernetInterface, DHCPEnabled) 199 { 200 EXPECT_CALL(manager, reloadConfigs()).WillRepeatedly(testing::Return()); 201 202 using DHCPConf = EthernetInterfaceIntf::DHCPConf; 203 auto test = [&](DHCPConf conf, bool dhcp4, bool dhcp6, bool ra) { 204 EXPECT_EQ(conf, interface.dhcpEnabled()); 205 EXPECT_EQ(dhcp4, interface.dhcp4()); 206 EXPECT_EQ(dhcp6, interface.dhcp6()); 207 EXPECT_EQ(ra, interface.ipv6AcceptRA()); 208 }; 209 test(DHCPConf::both, /*dhcp4=*/true, /*dhcp6=*/true, /*ra=*/true); 210 211 auto set_test = [&](DHCPConf conf, bool dhcp4, bool dhcp6, bool ra) { 212 EXPECT_EQ(conf, interface.dhcpEnabled(conf)); 213 test(conf, dhcp4, dhcp6, ra); 214 }; 215 set_test(DHCPConf::none, /*dhcp4=*/false, /*dhcp6=*/false, /*ra=*/false); 216 set_test(DHCPConf::v4, /*dhcp4=*/true, /*dhcp6=*/false, /*ra=*/false); 217 set_test(DHCPConf::v6stateless, /*dhcp4=*/false, /*dhcp6=*/false, 218 /*ra=*/true); 219 set_test(DHCPConf::v6, /*dhcp4=*/false, /*dhcp6=*/true, /*ra=*/true); 220 set_test(DHCPConf::v4v6stateless, /*dhcp4=*/true, /*dhcp6=*/false, 221 /*ra=*/true); 222 set_test(DHCPConf::both, /*dhcp4=*/true, /*dhcp6=*/true, /*ra=*/true); 223 224 auto ind_test = [&](DHCPConf conf, bool dhcp4, bool dhcp6, bool ra) { 225 EXPECT_EQ(dhcp4, interface.dhcp4(dhcp4)); 226 EXPECT_EQ(dhcp6, interface.dhcp6(dhcp6)); 227 EXPECT_EQ(ra, interface.ipv6AcceptRA(ra)); 228 test(conf, dhcp4, dhcp6, ra); 229 }; 230 ind_test(DHCPConf::none, /*dhcp4=*/false, /*dhcp6=*/false, /*ra=*/false); 231 ind_test(DHCPConf::v4, /*dhcp4=*/true, /*dhcp6=*/false, /*ra=*/false); 232 ind_test(DHCPConf::v6stateless, /*dhcp4=*/false, /*dhcp6=*/false, 233 /*ra=*/true); 234 ind_test(DHCPConf::v6, /*dhcp4=*/false, /*dhcp6=*/true, /*ra=*/false); 235 set_test(DHCPConf::v6, /*dhcp4=*/false, /*dhcp6=*/true, /*ra=*/true); 236 ind_test(DHCPConf::v4v6stateless, /*dhcp4=*/true, /*dhcp6=*/false, 237 /*ra=*/true); 238 ind_test(DHCPConf::both, /*dhcp4=*/true, /*dhcp6=*/true, /*ra=*/false); 239 set_test(DHCPConf::both, /*dhcp4=*/true, /*dhcp6=*/true, /*ra=*/true); 240 } 241 242 } // namespace network 243 } // namespace phosphor 244