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