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