xref: /openbmc/phosphor-networkd/test/test_ethernet_interface.cpp (revision 59e5b91d9784274d1d99b4c10e939c38606efacc)
1 #include "config_parser.hpp"
2 #include "ipaddress.hpp"
3 #include "mock_network_manager.hpp"
4 #include "mock_syscall.hpp"
5 #include "system_queries.hpp"
6 #include "util.hpp"
7 
8 #include <arpa/inet.h>
9 #include <net/if.h>
10 #include <netinet/in.h>
11 #include <stdlib.h>
12 
13 #include <charconv>
14 #include <exception>
15 #include <sdbusplus/bus.hpp>
16 #include <stdplus/gtest/tmp.hpp>
17 #include <string_view>
18 #include <xyz/openbmc_project/Common/error.hpp>
19 
20 #include <gmock/gmock.h>
21 #include <gtest/gtest.h>
22 
23 namespace phosphor
24 {
25 namespace network
26 {
27 
28 using std::literals::string_view_literals::operator""sv;
29 using testing::Key;
30 using testing::UnorderedElementsAre;
31 
32 class TestEthernetInterface : public stdplus::gtest::TestWithTmp
33 {
34   public:
35     sdbusplus::bus_t bus;
36     std::string confDir;
37     MockManager manager;
38     MockEthernetInterface interface;
39     TestEthernetInterface() :
40         bus(sdbusplus::bus::new_default()), confDir(CaseTmpDir()),
41         manager(bus, "/xyz/openbmc_test/network", confDir),
42         interface(makeInterface(bus, manager))
43 
44     {
45     }
46 
47     static MockEthernetInterface makeInterface(sdbusplus::bus_t& bus,
48                                                MockManager& manager)
49     {
50         system::mock_clear();
51         system::InterfaceInfo info{.idx = 1, .flags = 0, .name = "test0"};
52         system::mock_addIF(info);
53         return {bus, manager, info, "/xyz/openbmc_test/network"sv,
54                 config::Parser()};
55     }
56 
57     std::string getObjectPath(const std::string& ipaddress, uint8_t subnetMask,
58                               IP::AddressOrigin origin)
59     {
60         IP::Protocol addressType = IP::Protocol::IPv4;
61 
62         return interface.generateObjectPath(addressType, ipaddress, subnetMask,
63                                             origin);
64     }
65 
66     auto createIPObject(IP::Protocol addressType, const std::string& ipaddress,
67                         uint8_t subnetMask)
68     {
69         return interface.ip(addressType, ipaddress, subnetMask, "");
70     }
71 
72     void setNtpServers()
73     {
74         ServerList ntpServers = {"10.1.1.1", "10.2.2.2", "10.3.3.3"};
75         interface.EthernetInterfaceIntf::ntpServers(ntpServers);
76     }
77 
78     ServerList getNtpServers()
79     {
80         return interface.EthernetInterfaceIntf::ntpServers();
81     }
82 };
83 
84 TEST_F(TestEthernetInterface, Fields)
85 {
86     EXPECT_EQ(0, interface.mtu());
87     EXPECT_EQ("", interface.macAddress());
88     EXPECT_FALSE(interface.linkUp());
89 
90     constexpr ether_addr mac{0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
91     constexpr unsigned mtu = 150;
92 
93     system::InterfaceInfo info{.idx = 2,
94                                .flags = IFF_RUNNING,
95                                .name = "test1",
96                                .mac = mac,
97                                .mtu = mtu};
98     system::mock_addIF(info);
99     MockEthernetInterface intf(bus, manager, info,
100                                "/xyz/openbmc_test/network"sv, config::Parser());
101 
102     EXPECT_EQ(mtu, intf.mtu());
103     EXPECT_EQ(std::to_string(mac), intf.macAddress());
104     EXPECT_TRUE(intf.linkUp());
105 }
106 
107 TEST_F(TestEthernetInterface, NoIPaddress)
108 {
109     EXPECT_TRUE(interface.addrs.empty());
110 }
111 
112 TEST_F(TestEthernetInterface, AddIPAddress)
113 {
114     createIPObject(IP::Protocol::IPv4, "10.10.10.10", 16);
115     EXPECT_THAT(interface.addrs, UnorderedElementsAre(Key(
116                                      IfAddr(in_addr{htonl(0x0a0a0a0a)}, 16))));
117 }
118 
119 TEST_F(TestEthernetInterface, AddMultipleAddress)
120 {
121     createIPObject(IP::Protocol::IPv4, "10.10.10.10", 16);
122     createIPObject(IP::Protocol::IPv4, "20.20.20.20", 16);
123     EXPECT_THAT(
124         interface.addrs,
125         UnorderedElementsAre(Key(IfAddr(in_addr{htonl(0x0a0a0a0a)}, 16)),
126                              Key(IfAddr(in_addr{htonl(0x14141414)}, 16))));
127 }
128 
129 TEST_F(TestEthernetInterface, DeleteIPAddress)
130 {
131     createIPObject(IP::Protocol::IPv4, "10.10.10.10", 16);
132     createIPObject(IP::Protocol::IPv4, "20.20.20.20", 16);
133     interface.addrs.at(IfAddr(in_addr{htonl(0x0a0a0a0a)}, 16))->delete_();
134     EXPECT_THAT(interface.addrs, UnorderedElementsAre(Key(
135                                      IfAddr(in_addr{htonl(0x14141414)}, 16))));
136 }
137 
138 TEST_F(TestEthernetInterface, CheckObjectPath)
139 {
140     auto path = createIPObject(IP::Protocol::IPv4, "10.10.10.10", 16);
141     EXPECT_EQ(path.parent_path(), "/xyz/openbmc_test/network/test0");
142     EXPECT_EQ(path.filename(), "10.10.10.10/16");
143 }
144 
145 TEST_F(TestEthernetInterface, addStaticNameServers)
146 {
147     ServerList servers = {"9.1.1.1", "9.2.2.2", "9.3.3.3"};
148     EXPECT_CALL(manager, reloadConfigs());
149     interface.staticNameServers(servers);
150     fs::path filePath = confDir;
151     filePath /= "00-bmc-test0.network";
152     config::Parser parser(filePath.string());
153     EXPECT_EQ(servers, parser.map.getValueStrings("Network", "DNS"));
154 }
155 
156 TEST_F(TestEthernetInterface, getDynamicNameServers)
157 {
158     ServerList servers = {"9.1.1.1", "9.2.2.2", "9.3.3.3"};
159     EXPECT_CALL(interface, getNameServerFromResolvd())
160         .WillRepeatedly(testing::Return(servers));
161     EXPECT_EQ(interface.getNameServerFromResolvd(), servers);
162 }
163 
164 TEST_F(TestEthernetInterface, addStaticNTPServers)
165 {
166     ServerList servers = {"10.1.1.1", "10.2.2.2", "10.3.3.3"};
167     EXPECT_CALL(manager, reloadConfigs());
168     interface.staticNTPServers(servers);
169     fs::path filePath = confDir;
170     filePath /= "00-bmc-test0.network";
171     config::Parser parser(filePath.string());
172     EXPECT_EQ(servers, parser.map.getValueStrings("Network", "NTP"));
173 }
174 
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 
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 
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     interface.defaultGateway("");
195     EXPECT_EQ(interface.defaultGateway(), "");
196 }
197 
198 TEST_F(TestEthernetInterface, addGateway6)
199 {
200     std::string gateway6 = "ffff:ffff:ffff:fe80::1";
201     interface.defaultGateway6(gateway6);
202     EXPECT_EQ(interface.defaultGateway6(), gateway6);
203     interface.defaultGateway6("");
204     EXPECT_EQ(interface.defaultGateway6(), "");
205 }
206 
207 TEST_F(TestEthernetInterface, DHCPEnabled)
208 {
209     EXPECT_CALL(manager, reloadConfigs()).WillRepeatedly(testing::Return());
210 
211     using DHCPConf = EthernetInterfaceIntf::DHCPConf;
212     auto test = [&](DHCPConf conf, bool dhcp4, bool dhcp6, bool ra) {
213         EXPECT_EQ(conf, interface.dhcpEnabled());
214         EXPECT_EQ(dhcp4, interface.dhcp4());
215         EXPECT_EQ(dhcp6, interface.dhcp6());
216         EXPECT_EQ(ra, interface.ipv6AcceptRA());
217     };
218     test(DHCPConf::both, /*dhcp4=*/true, /*dhcp6=*/true, /*ra=*/true);
219 
220     auto set_test = [&](DHCPConf conf, bool dhcp4, bool dhcp6, bool ra) {
221         EXPECT_EQ(conf, interface.dhcpEnabled(conf));
222         test(conf, dhcp4, dhcp6, ra);
223     };
224     set_test(DHCPConf::none, /*dhcp4=*/false, /*dhcp6=*/false, /*ra=*/false);
225     set_test(DHCPConf::v4, /*dhcp4=*/true, /*dhcp6=*/false, /*ra=*/false);
226     set_test(DHCPConf::v6stateless, /*dhcp4=*/false, /*dhcp6=*/false,
227              /*ra=*/true);
228     set_test(DHCPConf::v6, /*dhcp4=*/false, /*dhcp6=*/true, /*ra=*/true);
229     set_test(DHCPConf::v4v6stateless, /*dhcp4=*/true, /*dhcp6=*/false,
230              /*ra=*/true);
231     set_test(DHCPConf::both, /*dhcp4=*/true, /*dhcp6=*/true, /*ra=*/true);
232 
233     auto ind_test = [&](DHCPConf conf, bool dhcp4, bool dhcp6, bool ra) {
234         EXPECT_EQ(dhcp4, interface.dhcp4(dhcp4));
235         EXPECT_EQ(dhcp6, interface.dhcp6(dhcp6));
236         EXPECT_EQ(ra, interface.ipv6AcceptRA(ra));
237         test(conf, dhcp4, dhcp6, ra);
238     };
239     ind_test(DHCPConf::none, /*dhcp4=*/false, /*dhcp6=*/false, /*ra=*/false);
240     ind_test(DHCPConf::v4, /*dhcp4=*/true, /*dhcp6=*/false, /*ra=*/false);
241     ind_test(DHCPConf::v6stateless, /*dhcp4=*/false, /*dhcp6=*/false,
242              /*ra=*/true);
243     ind_test(DHCPConf::v6, /*dhcp4=*/false, /*dhcp6=*/true, /*ra=*/false);
244     set_test(DHCPConf::v6, /*dhcp4=*/false, /*dhcp6=*/true, /*ra=*/true);
245     ind_test(DHCPConf::v4v6stateless, /*dhcp4=*/true, /*dhcp6=*/false,
246              /*ra=*/true);
247     ind_test(DHCPConf::both, /*dhcp4=*/true, /*dhcp6=*/true, /*ra=*/false);
248     set_test(DHCPConf::both, /*dhcp4=*/true, /*dhcp6=*/true, /*ra=*/true);
249 }
250 
251 } // namespace network
252 } // namespace phosphor
253