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 system::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 std::string getObjectPath(const std::string& ipaddress, uint8_t subnetMask, 58 IP::AddressOrigin origin) 59 { 60 IP::Protocol addressType = IP::Protocol::IPv4; 61 62 return interface.generateObjectPath(addressType, ipaddress, subnetMask, 63 origin); 64 } 65 66 auto createIPObject(IP::Protocol addressType, const std::string& ipaddress, 67 uint8_t subnetMask) 68 { 69 return interface.ip(addressType, ipaddress, subnetMask, ""); 70 } 71 72 void setNtpServers() 73 { 74 ServerList ntpServers = {"10.1.1.1", "10.2.2.2", "10.3.3.3"}; 75 interface.EthernetInterfaceIntf::ntpServers(ntpServers); 76 } 77 78 ServerList getNtpServers() 79 { 80 return interface.EthernetInterfaceIntf::ntpServers(); 81 } 82 }; 83 84 TEST_F(TestEthernetInterface, Fields) 85 { 86 EXPECT_EQ(0, interface.mtu()); 87 EXPECT_EQ("", interface.macAddress()); 88 EXPECT_FALSE(interface.linkUp()); 89 90 constexpr ether_addr mac{0x11, 0x22, 0x33, 0x44, 0x55, 0x66}; 91 constexpr unsigned mtu = 150; 92 93 system::InterfaceInfo info{.idx = 2, 94 .flags = IFF_RUNNING, 95 .name = "test1", 96 .mac = mac, 97 .mtu = mtu}; 98 system::mock_addIF(info); 99 MockEthernetInterface intf(bus, manager, info, 100 "/xyz/openbmc_test/network"sv, config::Parser()); 101 102 EXPECT_EQ(mtu, intf.mtu()); 103 EXPECT_EQ(std::to_string(mac), intf.macAddress()); 104 EXPECT_TRUE(intf.linkUp()); 105 } 106 107 TEST_F(TestEthernetInterface, NoIPaddress) 108 { 109 EXPECT_TRUE(interface.addrs.empty()); 110 } 111 112 TEST_F(TestEthernetInterface, AddIPAddress) 113 { 114 createIPObject(IP::Protocol::IPv4, "10.10.10.10", 16); 115 EXPECT_THAT(interface.addrs, UnorderedElementsAre(Key( 116 IfAddr(in_addr{htonl(0x0a0a0a0a)}, 16)))); 117 } 118 119 TEST_F(TestEthernetInterface, AddMultipleAddress) 120 { 121 createIPObject(IP::Protocol::IPv4, "10.10.10.10", 16); 122 createIPObject(IP::Protocol::IPv4, "20.20.20.20", 16); 123 EXPECT_THAT( 124 interface.addrs, 125 UnorderedElementsAre(Key(IfAddr(in_addr{htonl(0x0a0a0a0a)}, 16)), 126 Key(IfAddr(in_addr{htonl(0x14141414)}, 16)))); 127 } 128 129 TEST_F(TestEthernetInterface, DeleteIPAddress) 130 { 131 createIPObject(IP::Protocol::IPv4, "10.10.10.10", 16); 132 createIPObject(IP::Protocol::IPv4, "20.20.20.20", 16); 133 interface.addrs.at(IfAddr(in_addr{htonl(0x0a0a0a0a)}, 16))->delete_(); 134 EXPECT_THAT(interface.addrs, UnorderedElementsAre(Key( 135 IfAddr(in_addr{htonl(0x14141414)}, 16)))); 136 } 137 138 TEST_F(TestEthernetInterface, CheckObjectPath) 139 { 140 auto path = createIPObject(IP::Protocol::IPv4, "10.10.10.10", 16); 141 EXPECT_EQ(path.parent_path(), "/xyz/openbmc_test/network/test0"); 142 EXPECT_EQ(path.filename(), "10.10.10.10/16"); 143 } 144 145 TEST_F(TestEthernetInterface, addStaticNameServers) 146 { 147 ServerList servers = {"9.1.1.1", "9.2.2.2", "9.3.3.3"}; 148 EXPECT_CALL(manager, reloadConfigs()); 149 interface.staticNameServers(servers); 150 fs::path filePath = confDir; 151 filePath /= "00-bmc-test0.network"; 152 config::Parser parser(filePath.string()); 153 EXPECT_EQ(servers, parser.map.getValueStrings("Network", "DNS")); 154 } 155 156 TEST_F(TestEthernetInterface, getDynamicNameServers) 157 { 158 ServerList servers = {"9.1.1.1", "9.2.2.2", "9.3.3.3"}; 159 EXPECT_CALL(interface, getNameServerFromResolvd()) 160 .WillRepeatedly(testing::Return(servers)); 161 EXPECT_EQ(interface.getNameServerFromResolvd(), servers); 162 } 163 164 TEST_F(TestEthernetInterface, addStaticNTPServers) 165 { 166 ServerList servers = {"10.1.1.1", "10.2.2.2", "10.3.3.3"}; 167 EXPECT_CALL(manager, reloadConfigs()); 168 interface.staticNTPServers(servers); 169 fs::path filePath = confDir; 170 filePath /= "00-bmc-test0.network"; 171 config::Parser parser(filePath.string()); 172 EXPECT_EQ(servers, parser.map.getValueStrings("Network", "NTP")); 173 } 174 175 TEST_F(TestEthernetInterface, addNTPServers) 176 { 177 using namespace sdbusplus::xyz::openbmc_project::Common::Error; 178 ServerList servers = {"10.1.1.1", "10.2.2.2", "10.3.3.3"}; 179 EXPECT_THROW(interface.ntpServers(servers), NotAllowed); 180 } 181 182 TEST_F(TestEthernetInterface, getNTPServers) 183 { 184 ServerList servers = {"10.1.1.1", "10.2.2.2", "10.3.3.3"}; 185 setNtpServers(); 186 EXPECT_EQ(getNtpServers(), servers); 187 } 188 189 TEST_F(TestEthernetInterface, addGateway) 190 { 191 std::string gateway = "10.3.3.3"; 192 interface.defaultGateway(gateway); 193 EXPECT_EQ(interface.defaultGateway(), gateway); 194 interface.defaultGateway(""); 195 EXPECT_EQ(interface.defaultGateway(), ""); 196 } 197 198 TEST_F(TestEthernetInterface, addGateway6) 199 { 200 std::string gateway6 = "ffff:ffff:ffff:fe80::1"; 201 interface.defaultGateway6(gateway6); 202 EXPECT_EQ(interface.defaultGateway6(), gateway6); 203 interface.defaultGateway6(""); 204 EXPECT_EQ(interface.defaultGateway6(), ""); 205 } 206 207 TEST_F(TestEthernetInterface, DHCPEnabled) 208 { 209 EXPECT_CALL(manager, reloadConfigs()).WillRepeatedly(testing::Return()); 210 211 using DHCPConf = EthernetInterfaceIntf::DHCPConf; 212 auto test = [&](DHCPConf conf, bool dhcp4, bool dhcp6, bool ra) { 213 EXPECT_EQ(conf, interface.dhcpEnabled()); 214 EXPECT_EQ(dhcp4, interface.dhcp4()); 215 EXPECT_EQ(dhcp6, interface.dhcp6()); 216 EXPECT_EQ(ra, interface.ipv6AcceptRA()); 217 }; 218 test(DHCPConf::both, /*dhcp4=*/true, /*dhcp6=*/true, /*ra=*/true); 219 220 auto set_test = [&](DHCPConf conf, bool dhcp4, bool dhcp6, bool ra) { 221 EXPECT_EQ(conf, interface.dhcpEnabled(conf)); 222 test(conf, dhcp4, dhcp6, ra); 223 }; 224 set_test(DHCPConf::none, /*dhcp4=*/false, /*dhcp6=*/false, /*ra=*/false); 225 set_test(DHCPConf::v4, /*dhcp4=*/true, /*dhcp6=*/false, /*ra=*/false); 226 set_test(DHCPConf::v6stateless, /*dhcp4=*/false, /*dhcp6=*/false, 227 /*ra=*/true); 228 set_test(DHCPConf::v6, /*dhcp4=*/false, /*dhcp6=*/true, /*ra=*/true); 229 set_test(DHCPConf::v4v6stateless, /*dhcp4=*/true, /*dhcp6=*/false, 230 /*ra=*/true); 231 set_test(DHCPConf::both, /*dhcp4=*/true, /*dhcp6=*/true, /*ra=*/true); 232 233 auto ind_test = [&](DHCPConf conf, bool dhcp4, bool dhcp6, bool ra) { 234 EXPECT_EQ(dhcp4, interface.dhcp4(dhcp4)); 235 EXPECT_EQ(dhcp6, interface.dhcp6(dhcp6)); 236 EXPECT_EQ(ra, interface.ipv6AcceptRA(ra)); 237 test(conf, dhcp4, dhcp6, ra); 238 }; 239 ind_test(DHCPConf::none, /*dhcp4=*/false, /*dhcp6=*/false, /*ra=*/false); 240 ind_test(DHCPConf::v4, /*dhcp4=*/true, /*dhcp6=*/false, /*ra=*/false); 241 ind_test(DHCPConf::v6stateless, /*dhcp4=*/false, /*dhcp6=*/false, 242 /*ra=*/true); 243 ind_test(DHCPConf::v6, /*dhcp4=*/false, /*dhcp6=*/true, /*ra=*/false); 244 set_test(DHCPConf::v6, /*dhcp4=*/false, /*dhcp6=*/true, /*ra=*/true); 245 ind_test(DHCPConf::v4v6stateless, /*dhcp4=*/true, /*dhcp6=*/false, 246 /*ra=*/true); 247 ind_test(DHCPConf::both, /*dhcp4=*/true, /*dhcp6=*/true, /*ra=*/false); 248 set_test(DHCPConf::both, /*dhcp4=*/true, /*dhcp6=*/true, /*ra=*/true); 249 } 250 251 } // namespace network 252 } // namespace phosphor 253