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";
142 ::unlink(tmpConfigFile.c_str());
145 BOOST_CHECK_NO_THROW(config::saveToJsonString(cfg));
147 cfg.addInterfaceConfig("host-veth0", "zone-eth0", InterfaceType::VETH);
148 cfg.addInterfaceConfig("host-veth1", "zone-eth1", InterfaceType::BRIDGE);
149 cfg.addInterfaceConfig("host-veth2", "zone-eth2", InterfaceType::MACVLAN);
151 cfg.addInetConfig("zone-eth0", InetAddr("1.2.3.4", 24));
153 config::saveToJsonFile(tmpConfigFile, cfg);
156 BOOST_CHECK_NO_THROW(config::loadFromJsonFile(tmpConfigFile, cfg2));
158 int ifn1 = cfg.getInterfaces().size();
159 int ifn2 = cfg2.getInterfaces().size();
160 BOOST_CHECK_EQUAL(ifn1, ifn2);
161 for (int i = 0; i < ifn2; ++i) {
162 const NetworkInterfaceConfig& ni1 = cfg.getInterface(i);
163 const NetworkInterfaceConfig& ni2 = cfg2.getInterface(i);
165 BOOST_CHECK_EQUAL(ni1.getHostIf(), ni2.getHostIf());
166 BOOST_CHECK_EQUAL(ni1.getZoneIf(), ni2.getZoneIf());
167 BOOST_CHECK(ni1.getType() == ni2.getType());
168 BOOST_CHECK(ni1.getMode() == ni2.getMode());
172 BOOST_AUTO_TEST_CASE(NetworkBridgeCreateDestroy)
174 std::string name = getUniqueName("test-br");
175 NetworkInterface ni(name);
176 InetAddr myip("10.100.1.1", 32);
178 BOOST_CHECK_NO_THROW(ni.create(InterfaceType::BRIDGE));
179 ni.setMACAddress("12:22:33:44:55:66"); // note bit0=0 within first byte !!!
180 BOOST_CHECK_NO_THROW(ni.addInetAddr(myip));
182 std::vector<std::string> iflist = NetworkInterface::getInterfaces(0);
183 BOOST_CHECK(std::find(iflist.begin(), iflist.end(), name) != iflist.end());
185 std::vector<InetAddr> addrs = ni.getInetAddressList();
186 BOOST_CHECK(std::find(addrs.begin(), addrs.end(), myip) != addrs.end());
188 BOOST_CHECK_NO_THROW(ni.delInetAddr(myip));
189 BOOST_CHECK_NO_THROW(ni.destroy());
190 iflist = NetworkInterface::getInterfaces(0);
191 BOOST_CHECK(std::find(iflist.begin(), iflist.end(), ni.getName()) == iflist.end());
194 BOOST_AUTO_TEST_CASE(NetworkMacVLanCreateDestroy)
196 std::string masterif;
197 std::vector<std::string> iflist = NetworkInterface::getInterfaces(0);
198 for (const auto& ifn : iflist) {
202 NetworkInterface n(ifn);
203 if (n.status() == NetStatus::UP) {
209 NetworkInterface ni(getUniqueName("test-vlan"));
210 // creating MACVLAN on masterif
211 BOOST_CHECK_NO_THROW(ni.create(InterfaceType::MACVLAN, masterif, MacVLanMode::VEPA));
213 iflist = NetworkInterface::getInterfaces(0);
214 BOOST_CHECK(std::find(iflist.begin(), iflist.end(), ni.getName()) != iflist.end());
217 BOOST_CHECK_NO_THROW(ni.destroy());
219 iflist = NetworkInterface::getInterfaces(0);
220 BOOST_CHECK(std::find(iflist.begin(), iflist.end(), ni.getName()) == iflist.end());
223 BOOST_AUTO_TEST_CASE(NetworkListRoutes)
226 std::vector<Route> routes;
227 // tbl MAIN, all devs
228 BOOST_CHECK_NO_THROW(routes = NetworkInterface::getRoutes(0));
229 for (auto route : routes) {
230 if (route.ifname == "lo") {
235 // tbl LOCAL, all devs
236 BOOST_CHECK_NO_THROW(routes = NetworkInterface::getRoutes(0,RoutingTable::LOCAL));
238 // tbl DEFAULT, all devs
239 BOOST_CHECK_NO_THROW(routes = NetworkInterface::getRoutes(0,RoutingTable::DEFAULT));
241 NetworkInterface ni("lo");
243 BOOST_CHECK_NO_THROW(routes = ni.getRoutes());
244 BOOST_CHECK(routes.size() == mainLo);
247 BOOST_CHECK_NO_THROW(routes = ni.getRoutes(RoutingTable::LOCAL));
250 BOOST_AUTO_TEST_CASE(NetworkAddDelRoute)
252 std::vector<Route> routes;
255 InetAddr("10.100.1.0", 24),//dst - destination network
256 InetAddr("", 0), //src - not specified (prefix=0)
258 "", // ifname (used only when read routes)
259 RoutingTable::UNSPEC // table (used only when read rotes)
262 NetworkInterface ni("lo");
264 BOOST_CHECK_NO_THROW(ni.addRoute(route));
265 BOOST_CHECK_NO_THROW(routes = ni.getRoutes());
266 BOOST_CHECK(std::find_if(routes.begin(), routes.end(),
267 [&route](const Route& item) -> bool {
268 return item.dst == route.dst;
273 BOOST_CHECK_NO_THROW(ni.delRoute(route));
274 BOOST_CHECK_NO_THROW(routes = ni.getRoutes());
275 BOOST_CHECK(std::find_if(routes.begin(), routes.end(),
276 [&route](const Route& item) -> bool {
277 return item.dst == route.dst;
283 BOOST_AUTO_TEST_CASE(NetworkNamespaceCreate)
287 BOOST_CHECK(r != -1);
289 pid_t pid = lxcpp::clone(child_exec, fd, CLONE_NEWNET);
292 //directives for child process
293 sendCmd(fd[1], "0"); // exit
295 // waiting for child to finish
297 BOOST_CHECK_NO_THROW(status = lxcpp::waitpid(pid));
300 BOOST_CHECK_MESSAGE(status == 0, "child failed");
303 // this test case shows how to create container with network
304 // Note: this test needs some preparation to successfuly connect an external site:
305 // 1. allow network forwading (echo 1 > /proc/sys/net/ipv4/ip_forward)
306 // 2. configure ip masquarading (iptables -t nat -A POSTROUTING -s 10.0.0.0/16 ! -d 10.0.0.0/16 -j MASQUERADE)
307 BOOST_AUTO_TEST_CASE(NetworkNamespaceVETH)
309 const char *vbr = "vbr";
310 const char *veth1 = "veth-ma";
311 const char *veth2 = "veth-sl";
315 BOOST_CHECK(r != -1);
317 pid_t pid = lxcpp::clone(child_exec, fd, CLONE_NEWNET);
320 NetworkInterface br(vbr);
321 NetworkInterface v1(veth1);
322 NetworkInterface v2(veth2);
324 NetworkInterface("lo", pid).up();
326 // creating Bridge vbr
327 BOOST_CHECK_NO_THROW(br.create(InterfaceType::BRIDGE));
328 BOOST_CHECK_NO_THROW(br.up());
329 br.addInetAddr(InetAddr("10.0.0.1", 24));
331 // creating VETH pair veth1 <-> veth2
332 BOOST_CHECK_NO_THROW(v1.create(InterfaceType::VETH, v2.getName()));
334 // add veth1 to bridge
335 BOOST_CHECK_NO_THROW(v1.addToBridge(br.getName()));
337 // move veth2 to network namespace (container)
338 BOOST_CHECK_NO_THROW(v2.moveToContainer(pid));
340 v2.addInetAddr(InetAddr("10.0.0.2", 24));
342 v1.up(); // after v2 up and configured
346 InetAddr("10.0.0.1", 0), //dst - gateway
347 InetAddr("", 0), //src - not specified (prefix=0)
353 //directives for child process
354 sendCmd(fd[1], "a"); // ip addr show
355 sendCmd(fd[1], "r"); // ip route list
356 sendCmd(fd[1], "c"); // connect extern (needs configured NAT)
357 //sendCmd(fd[1], "s"); // exec shell
358 sendCmd(fd[1], "0"); // exit
360 // waiting for child to finish
362 BOOST_CHECK_NO_THROW(status = lxcpp::waitpid(pid));
364 BOOST_CHECK_MESSAGE(status == 0, "child failed");
366 BOOST_CHECK_NO_THROW(br.destroy());
369 BOOST_AUTO_TEST_SUITE_END()