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;
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     static MockEthernetInterface
43         makeInterface(stdplus::PinnedRef<sdbusplus::bus_t> bus,
44                       TestManager& manager)
45     {
46         AllIntfInfo info{InterfaceInfo{
47             .type = ARPHRD_ETHER, .idx = 1, .flags = 0, .name = "test0"}};
48         return {bus, manager, info, "/xyz/openbmc_test/network"sv,
49                 config::Parser()};
50     }
51 
52     auto createIPObject(IP::Protocol addressType, const std::string& ipaddress,
53                         uint8_t subnetMask)
54     {
55         return interface.ip(addressType, ipaddress, subnetMask, "");
56     }
57 
58     void setNtpServers()
59     {
60         ServerList ntpServers = {"10.1.1.1", "10.2.2.2", "10.3.3.3"};
61         interface.EthernetInterfaceIntf::ntpServers(ntpServers);
62     }
63 
64     ServerList getNtpServers()
65     {
66         return interface.EthernetInterfaceIntf::ntpServers();
67     }
68 };
69 
70 TEST_F(TestEthernetInterface, Fields)
71 {
72     EXPECT_EQ(0, interface.mtu());
73     EXPECT_EQ("", interface.macAddress());
74     EXPECT_FALSE(interface.linkUp());
75 
76     constexpr stdplus::EtherAddr mac{0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
77     constexpr unsigned mtu = 150;
78 
79     AllIntfInfo info{InterfaceInfo{.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 
93 TEST_F(TestEthernetInterface, NoIPaddress)
94 {
95     EXPECT_TRUE(interface.addrs.empty());
96 }
97 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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