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 
createStaticGatewayObject(const std::string & gateway,IP::Protocol protocol)57     auto createStaticGatewayObject(const std::string& gateway,
58                                    IP::Protocol protocol)
59     {
60         return interface.staticGateway(gateway, protocol);
61     }
62 
setNtpServers()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 
getNtpServers()69     ServerList getNtpServers()
70     {
71         return interface.EthernetInterfaceIntf::ntpServers();
72     }
73 };
74 
TEST_F(TestEthernetInterface,Fields)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 stdplus::EtherAddr mac{0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
82     constexpr unsigned mtu = 150;
83 
84     AllIntfInfo info{InterfaceInfo{
85         .type = ARPHRD_ETHER,
86         .idx = 2,
87         .flags = IFF_RUNNING,
88         .name = "test1",
89         .mac = mac,
90         .mtu = mtu}};
91     MockEthernetInterface intf(bus, manager, info,
92                                "/xyz/openbmc_test/network"sv, config::Parser());
93 
94     EXPECT_EQ(mtu, intf.mtu());
95     EXPECT_EQ(stdplus::toStr(mac), intf.macAddress());
96     EXPECT_TRUE(intf.linkUp());
97 }
98 
TEST_F(TestEthernetInterface,NoIPaddress)99 TEST_F(TestEthernetInterface, NoIPaddress)
100 {
101     EXPECT_TRUE(interface.addrs.empty());
102 }
103 
TEST_F(TestEthernetInterface,AddIPAddress)104 TEST_F(TestEthernetInterface, AddIPAddress)
105 {
106     EXPECT_THROW(createIPObject(IP::Protocol::IPv4, "127.0.0.1", 16),
107                  InvalidArgument);
108     EXPECT_THROW(createIPObject(IP::Protocol::IPv4, "127.0.0.1", 32),
109                  InvalidArgument);
110     EXPECT_THROW(createIPObject(IP::Protocol::IPv4, "192.168.1.1", 0),
111                  InvalidArgument);
112     EXPECT_THROW(createIPObject(IP::Protocol::IPv6, "::1", 64),
113                  InvalidArgument);
114     EXPECT_THROW(createIPObject(IP::Protocol::IPv6, "::", 128),
115                  InvalidArgument);
116     EXPECT_THROW(createIPObject(IP::Protocol::IPv6, "fe80::1", 0),
117                  InvalidArgument);
118 
119     createIPObject(IP::Protocol::IPv4, "10.10.10.10", 16);
120     EXPECT_THAT(interface.addrs,
121                 UnorderedElementsAre(Key("10.10.10.10/16"_sub)));
122 }
123 
TEST_F(TestEthernetInterface,AddMultipleAddress)124 TEST_F(TestEthernetInterface, AddMultipleAddress)
125 {
126     createIPObject(IP::Protocol::IPv4, "10.10.10.10", 16);
127     createIPObject(IP::Protocol::IPv4, "20.20.20.20", 16);
128     EXPECT_THAT(interface.addrs,
129                 UnorderedElementsAre(Key("10.10.10.10/16"_sub),
130                                      Key("20.20.20.20/16"_sub)));
131 }
132 
TEST_F(TestEthernetInterface,DeleteIPAddress)133 TEST_F(TestEthernetInterface, DeleteIPAddress)
134 {
135     createIPObject(IP::Protocol::IPv4, "10.10.10.10", 16);
136     createIPObject(IP::Protocol::IPv4, "20.20.20.20", 16);
137     interface.addrs.at("10.10.10.10/16"_sub)->delete_();
138     EXPECT_THAT(interface.addrs,
139                 UnorderedElementsAre(Key("20.20.20.20/16"_sub)));
140 }
141 
TEST_F(TestEthernetInterface,CheckObjectPath)142 TEST_F(TestEthernetInterface, CheckObjectPath)
143 {
144     auto path = createIPObject(IP::Protocol::IPv4, "10.10.10.10", 16);
145     EXPECT_EQ(path.parent_path(), "/xyz/openbmc_test/network/test0");
146     EXPECT_EQ(path.filename(), "10.10.10.10/16");
147 }
148 
TEST_F(TestEthernetInterface,addStaticNameServers)149 TEST_F(TestEthernetInterface, addStaticNameServers)
150 {
151     ServerList servers = {"9.1.1.1", "9.2.2.2", "9.3.3.3"};
152     EXPECT_CALL(manager.mockReload, schedule());
153     interface.staticNameServers(servers);
154     config::Parser parser((confDir / "00-bmc-test0.network").native());
155     EXPECT_EQ(servers, parser.map.getValueStrings("Network", "DNS"));
156 }
157 
TEST_F(TestEthernetInterface,getDynamicNameServers)158 TEST_F(TestEthernetInterface, getDynamicNameServers)
159 {
160     ServerList servers = {"9.1.1.1", "9.2.2.2", "9.3.3.3"};
161     EXPECT_CALL(interface, getNameServerFromResolvd())
162         .WillRepeatedly(testing::Return(servers));
163     EXPECT_EQ(interface.getNameServerFromResolvd(), servers);
164 }
165 
TEST_F(TestEthernetInterface,addStaticNTPServers)166 TEST_F(TestEthernetInterface, addStaticNTPServers)
167 {
168     ServerList servers = {"10.1.1.1", "10.2.2.2", "10.3.3.3"};
169     EXPECT_CALL(manager.mockReload, schedule());
170     interface.staticNTPServers(servers);
171     config::Parser parser((confDir / "00-bmc-test0.network").native());
172     EXPECT_EQ(servers, parser.map.getValueStrings("Network", "NTP"));
173 }
174 
TEST_F(TestEthernetInterface,addNTPServers)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 
TEST_F(TestEthernetInterface,getNTPServers)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 
TEST_F(TestEthernetInterface,addGateway)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     EXPECT_THROW(interface.defaultGateway6("127.0.0.10"), InvalidArgument);
195     EXPECT_THROW(interface.defaultGateway6("0.0.0.0"), InvalidArgument);
196     EXPECT_THROW(interface.defaultGateway6("224.1.0.0"), InvalidArgument);
197     EXPECT_EQ(interface.defaultGateway(), gateway);
198     interface.defaultGateway("");
199     EXPECT_EQ(interface.defaultGateway(), "");
200     interface.defaultGateway("0.0.0.0");
201     EXPECT_EQ(interface.defaultGateway(), "");
202 }
203 
TEST_F(TestEthernetInterface,addGateway6)204 TEST_F(TestEthernetInterface, addGateway6)
205 {
206     std::string gateway6 = "fe80::1";
207     interface.defaultGateway6(gateway6);
208     EXPECT_EQ(interface.defaultGateway6(), gateway6);
209     EXPECT_THROW(interface.defaultGateway6("::1"), InvalidArgument);
210     EXPECT_EQ(interface.defaultGateway6(), gateway6);
211     interface.defaultGateway6("");
212     EXPECT_EQ(interface.defaultGateway6(), "");
213     interface.defaultGateway6("::");
214     EXPECT_EQ(interface.defaultGateway6(), "");
215 }
216 
TEST_F(TestEthernetInterface,DHCPEnabled)217 TEST_F(TestEthernetInterface, DHCPEnabled)
218 {
219     EXPECT_CALL(manager.mockReload, schedule())
220         .WillRepeatedly(testing::Return());
221 
222     using DHCPConf = EthernetInterfaceIntf::DHCPConf;
223     auto test = [&](DHCPConf conf, bool dhcp4, bool dhcp6, bool ra) {
224         EXPECT_EQ(conf, interface.dhcpEnabled());
225         EXPECT_EQ(dhcp4, interface.dhcp4());
226         EXPECT_EQ(dhcp6, interface.dhcp6());
227         EXPECT_EQ(ra, interface.ipv6AcceptRA());
228     };
229     test(DHCPConf::both, /*dhcp4=*/true, /*dhcp6=*/true, /*ra=*/true);
230 
231     auto set_test = [&](DHCPConf conf, bool dhcp4, bool dhcp6, bool ra) {
232         EXPECT_EQ(conf, interface.dhcpEnabled(conf));
233         test(conf, dhcp4, dhcp6, ra);
234     };
235     set_test(DHCPConf::none, /*dhcp4=*/false, /*dhcp6=*/false, /*ra=*/false);
236     set_test(DHCPConf::v4, /*dhcp4=*/true, /*dhcp6=*/false, /*ra=*/false);
237     set_test(DHCPConf::v6stateless, /*dhcp4=*/false, /*dhcp6=*/false,
238              /*ra=*/true);
239     set_test(DHCPConf::v6, /*dhcp4=*/false, /*dhcp6=*/true, /*ra=*/true);
240     set_test(DHCPConf::v4v6stateless, /*dhcp4=*/true, /*dhcp6=*/false,
241              /*ra=*/true);
242     set_test(DHCPConf::both, /*dhcp4=*/true, /*dhcp6=*/true, /*ra=*/true);
243 
244     auto ind_test = [&](DHCPConf conf, bool dhcp4, bool dhcp6, bool ra) {
245         EXPECT_EQ(dhcp4, interface.dhcp4(dhcp4));
246         EXPECT_EQ(dhcp6, interface.dhcp6(dhcp6));
247         EXPECT_EQ(ra, interface.ipv6AcceptRA(ra));
248         test(conf, dhcp4, dhcp6, ra);
249     };
250     ind_test(DHCPConf::none, /*dhcp4=*/false, /*dhcp6=*/false, /*ra=*/false);
251     ind_test(DHCPConf::v4, /*dhcp4=*/true, /*dhcp6=*/false, /*ra=*/false);
252     ind_test(DHCPConf::v6stateless, /*dhcp4=*/false, /*dhcp6=*/false,
253              /*ra=*/true);
254     ind_test(DHCPConf::v6, /*dhcp4=*/false, /*dhcp6=*/true, /*ra=*/false);
255     set_test(DHCPConf::v6, /*dhcp4=*/false, /*dhcp6=*/true, /*ra=*/true);
256     ind_test(DHCPConf::v4v6stateless, /*dhcp4=*/true, /*dhcp6=*/false,
257              /*ra=*/true);
258     ind_test(DHCPConf::both, /*dhcp4=*/true, /*dhcp6=*/true, /*ra=*/false);
259     set_test(DHCPConf::both, /*dhcp4=*/true, /*dhcp6=*/true, /*ra=*/true);
260 }
261 
TEST_F(TestEthernetInterface,AddStaticGateway)262 TEST_F(TestEthernetInterface, AddStaticGateway)
263 {
264     createStaticGatewayObject("10.10.10.1", IP::Protocol::IPv4);
265     EXPECT_THAT(interface.staticGateways,
266                 UnorderedElementsAre(Key(std::string("10.10.10.1"))));
267 }
268 
TEST_F(TestEthernetInterface,AddMultipleStaticGateways)269 TEST_F(TestEthernetInterface, AddMultipleStaticGateways)
270 {
271     createStaticGatewayObject("10.10.10.1", IP::Protocol::IPv4);
272     createStaticGatewayObject("10.20.30.1", IP::Protocol::IPv4);
273     EXPECT_THAT(interface.staticGateways,
274                 UnorderedElementsAre(Key(std::string("10.10.10.1")),
275                                      Key(std::string("10.20.30.1"))));
276 }
277 
TEST_F(TestEthernetInterface,DeleteStaticGateway)278 TEST_F(TestEthernetInterface, DeleteStaticGateway)
279 {
280     createStaticGatewayObject("10.10.10.1", IP::Protocol::IPv4);
281     createStaticGatewayObject("10.20.30.1", IP::Protocol::IPv4);
282 
283     interface.staticGateways.at(std::string("10.10.10.1"))->delete_();
284     interface.staticGateways.at(std::string("10.20.30.1"))->delete_();
285     EXPECT_EQ(interface.staticGateways.empty(), true);
286 }
287 
TEST_F(TestEthernetInterface,AddIPv6StaticGateway)288 TEST_F(TestEthernetInterface, AddIPv6StaticGateway)
289 {
290     createStaticGatewayObject("2002:903:15f:325::1", IP::Protocol::IPv6);
291     EXPECT_THAT(interface.staticGateways,
292                 UnorderedElementsAre(Key(std::string("2002:903:15f:325::1"))));
293 }
294 
TEST_F(TestEthernetInterface,AddMultipleIPv6StaticGateways)295 TEST_F(TestEthernetInterface, AddMultipleIPv6StaticGateways)
296 {
297     createStaticGatewayObject("2003:903:15f:325::1", IP::Protocol::IPv6);
298     createStaticGatewayObject("2004:903:15f:325::1", IP::Protocol::IPv6);
299     EXPECT_THAT(interface.staticGateways,
300                 UnorderedElementsAre(Key(std::string("2003:903:15f:325::1")),
301                                      Key(std::string("2004:903:15f:325::1"))));
302 }
303 
304 } // namespace network
305 } // namespace phosphor
306