2 * Copyright (C) 2015 Samsung Electronics Co., Ltd All Rights Reserved
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License version 2.1 as published by the Free Software Foundation.
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 * @author Krzysztof Dynowski (k.dynowski@samsumg.com)
21 * @brief Unit tests of lxcpp network helpers
25 #include "config/manager.hpp"
26 #include "logger/logger.hpp"
27 #include "lxcpp/network-config.hpp"
28 #include "lxcpp/process.hpp"
29 #include "utils/execute.hpp"
36 using namespace lxcpp;
44 static std::string getUniqueName(const std::string& prefix) {
45 std::vector<std::string> iflist = NetworkInterface::getInterfaces(0);
49 name = prefix + std::to_string(i++);
50 } while (std::find(iflist.begin(), iflist.end(), name) != iflist.end());
54 static void sendCmd(int fd, const char *txt) {
55 if (::write(fd, txt, 2) != 2) {
56 throw std::runtime_error("pipe write error");
62 int child_exec(void *_fd)
70 lxcpp::NetworkInterface("lo").up();
72 // child: waiting for parent
73 if (::read(fd[0], cmdbuf, 2) != 2) {
81 } else if (cmd == 'a') {
82 const char *argv[] = {
85 if (!utils::executeAndWait("/sbin/ip", argv)) {
86 throw std::runtime_error("ip addr failed");
88 } else if (cmd == 'r') {
89 const char *argv[] = {
90 "ip", "route", "list", NULL
92 if (!utils::executeAndWait("/sbin/ip", argv)) {
93 throw std::runtime_error("ip route failed");
95 } else if (cmd == 's') {
96 const char *argv[] = {
99 if (!utils::executeAndWait("/bin/bash", argv)) {
100 throw std::runtime_error("bash failed");
102 } else if (cmd == 'c') {
103 LOGW("connecting ... to be done");
121 * NOTE: network inerface unit tests are not finished yet
122 * tests are developed/added together with network interface code
123 * and container code development
126 BOOST_FIXTURE_TEST_SUITE(LxcppNetworkSuite, Fixture)
128 BOOST_AUTO_TEST_CASE(NetworkListInterfaces)
130 std::vector<std::string> iflist;
131 BOOST_CHECK_NO_THROW(iflist=NetworkInterface::getInterfaces(0));
132 for (const auto& ifn : iflist) {
133 const Attrs& attrs = NetworkInterface(ifn).getAttrs();
134 BOOST_CHECK(attrs.size() > 0);
139 BOOST_AUTO_TEST_CASE(NetworkConfigSerialization)
141 std::string tmpConfigFile = "/tmp/netconfig.conf";
143 BOOST_CHECK_NO_THROW(config::saveToJsonString(cfg));
145 cfg.addInterfaceConfig("host-veth0", "zone-eth0", InterfaceType::VETH);
146 cfg.addInterfaceConfig("host-veth1", "zone-eth1", InterfaceType::BRIDGE);
147 cfg.addInterfaceConfig("host-veth2", "zone-eth2", InterfaceType::MACVLAN);
149 cfg.addInetConfig("zone-eth0", InetAddr("1.2.3.4", 24));
151 config::saveToJsonFile(tmpConfigFile, cfg);
154 config::loadFromJsonFile(tmpConfigFile, cfg2);
156 int ifnum = cfg.getInterfaces().size();
157 for (int i = 0; i < ifnum; ++i) {
158 const NetworkInterfaceConfig& ni1 = cfg.getInterface(i);
159 const NetworkInterfaceConfig& ni2 = cfg2.getInterface(i);
161 BOOST_CHECK_EQUAL(ni1.getHostIf(), ni2.getHostIf());
162 BOOST_CHECK_EQUAL(ni1.getZoneIf(), ni2.getZoneIf());
163 BOOST_CHECK(ni1.getType() == ni2.getType());
164 BOOST_CHECK(ni1.getMode() == ni2.getMode());
168 BOOST_AUTO_TEST_CASE(NetworkBridgeCreateDestroy)
170 std::string name = getUniqueName("test-br");
171 NetworkInterface ni(name);
172 InetAddr myip("10.100.1.1", 32);
174 BOOST_CHECK_NO_THROW(ni.create(InterfaceType::BRIDGE));
175 ni.setMACAddress("12:22:33:44:55:66"); // note bit0=0 within first byte !!!
176 BOOST_CHECK_NO_THROW(ni.addInetAddr(myip));
178 std::vector<std::string> iflist = NetworkInterface::getInterfaces(0);
179 BOOST_CHECK(std::find(iflist.begin(), iflist.end(), name) != iflist.end());
181 std::vector<InetAddr> addrs = ni.getInetAddressList();
182 BOOST_CHECK(std::find(addrs.begin(), addrs.end(), myip) != addrs.end());
184 BOOST_CHECK_NO_THROW(ni.delInetAddr(myip));
185 BOOST_CHECK_NO_THROW(ni.destroy());
186 iflist = NetworkInterface::getInterfaces(0);
187 BOOST_CHECK(std::find(iflist.begin(), iflist.end(), ni.getName()) == iflist.end());
190 BOOST_AUTO_TEST_CASE(NetworkMacVLanCreateDestroy)
192 std::string masterif;
193 std::vector<std::string> iflist = NetworkInterface::getInterfaces(0);
194 for (const auto& ifn : iflist) {
198 NetworkInterface n(ifn);
199 if (n.status() == NetStatus::UP) {
205 NetworkInterface ni(getUniqueName("test-vlan"));
206 // creating MACVLAN on masterif
207 BOOST_CHECK_NO_THROW(ni.create(InterfaceType::MACVLAN, masterif, MacVLanMode::VEPA));
209 iflist = NetworkInterface::getInterfaces(0);
210 BOOST_CHECK(std::find(iflist.begin(), iflist.end(), ni.getName()) != iflist.end());
213 BOOST_CHECK_NO_THROW(ni.destroy());
215 iflist = NetworkInterface::getInterfaces(0);
216 BOOST_CHECK(std::find(iflist.begin(), iflist.end(), ni.getName()) == iflist.end());
219 BOOST_AUTO_TEST_CASE(NetworkListRoutes)
222 std::vector<Route> routes;
223 // tbl MAIN, all devs
224 BOOST_CHECK_NO_THROW(routes = NetworkInterface::getRoutes(0));
225 for (auto route : routes) {
226 if (route.ifname == "lo") {
231 // tbl LOCAL, all devs
232 BOOST_CHECK_NO_THROW(routes = NetworkInterface::getRoutes(0,RoutingTable::LOCAL));
234 // tbl DEFAULT, all devs
235 BOOST_CHECK_NO_THROW(routes = NetworkInterface::getRoutes(0,RoutingTable::DEFAULT));
237 NetworkInterface ni("lo");
239 BOOST_CHECK_NO_THROW(routes = ni.getRoutes());
240 BOOST_CHECK(routes.size() == mainLo);
243 BOOST_CHECK_NO_THROW(routes = ni.getRoutes(RoutingTable::LOCAL));
246 BOOST_AUTO_TEST_CASE(NetworkAddDelRoute)
248 std::vector<Route> routes;
251 InetAddr("10.100.1.0", 24),//dst - destination network
252 InetAddr("", 0), //src - not specified (prefix=0)
254 "", // ifname (used only when read routes)
255 RoutingTable::UNSPEC // table (used only when read rotes)
258 NetworkInterface ni("lo");
260 BOOST_CHECK_NO_THROW(ni.addRoute(route));
261 BOOST_CHECK_NO_THROW(routes = ni.getRoutes());
262 BOOST_CHECK(std::find_if(routes.begin(), routes.end(),
263 [&route](const Route& item) -> bool {
264 return item.dst == route.dst;
269 BOOST_CHECK_NO_THROW(ni.delRoute(route));
270 BOOST_CHECK_NO_THROW(routes = ni.getRoutes());
271 BOOST_CHECK(std::find_if(routes.begin(), routes.end(),
272 [&route](const Route& item) -> bool {
273 return item.dst == route.dst;
279 BOOST_AUTO_TEST_CASE(NetworkNamespaceCreate)
283 BOOST_CHECK(r != -1);
285 pid_t pid = lxcpp::clone(child_exec, fd, CLONE_NEWNET);
288 //directives for child process
289 sendCmd(fd[1], "0"); // exit
291 // waiting for child to finish
293 BOOST_CHECK_NO_THROW(status = lxcpp::waitpid(pid));
296 BOOST_CHECK_MESSAGE(status == 0, "child failed");
299 // this test case shows how to create container with network
300 // Note: this test needs some preparation to successfuly connect an external site:
301 // 1. allow network forwading (echo 1 > /proc/sys/net/ipv4/ip_forward)
302 // 2. configure ip masquarading (iptables -t nat -A POSTROUTING -s 10.0.0.0/16 ! -d 10.0.0.0/16 -j MASQUERADE)
303 BOOST_AUTO_TEST_CASE(NetworkNamespaceVETH)
305 const char *vbr = "vbr";
306 const char *veth1 = "veth-ma";
307 const char *veth2 = "veth-sl";
311 BOOST_CHECK(r != -1);
313 pid_t pid = lxcpp::clone(child_exec, fd, CLONE_NEWNET);
316 NetworkInterface br(vbr);
317 NetworkInterface v1(veth1);
318 NetworkInterface v2(veth2);
320 NetworkInterface("lo", pid).up();
322 // creating Bridge vbr
323 BOOST_CHECK_NO_THROW(br.create(InterfaceType::BRIDGE));
324 BOOST_CHECK_NO_THROW(br.up());
325 br.addInetAddr(InetAddr("10.0.0.1", 24));
327 // creating VETH pair veth1 <-> veth2
328 BOOST_CHECK_NO_THROW(v1.create(InterfaceType::VETH, v2.getName()));
330 // add veth1 to bridge
331 BOOST_CHECK_NO_THROW(v1.addToBridge(br.getName()));
333 // move veth2 to network namespace (container)
334 BOOST_CHECK_NO_THROW(v2.moveToContainer(pid));
336 v2.addInetAddr(InetAddr("10.0.0.2", 24));
338 v1.up(); // after v2 up and configured
342 InetAddr("10.0.0.1", 0), //dst - gateway
343 InetAddr("", 0), //src - not specified (prefix=0)
349 //directives for child process
350 sendCmd(fd[1], "a"); // ip addr show
351 sendCmd(fd[1], "r"); // ip route list
352 sendCmd(fd[1], "c"); // connect extern (needs configured NAT)
353 //sendCmd(fd[1], "s"); // exec shell
354 sendCmd(fd[1], "0"); // exit
356 // waiting for child to finish
358 BOOST_CHECK_NO_THROW(status = lxcpp::waitpid(pid));
360 BOOST_CHECK_MESSAGE(status == 0, "child failed");
362 BOOST_CHECK_NO_THROW(br.destroy());
365 BOOST_AUTO_TEST_SUITE_END()