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