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"
37 using namespace lxcpp;
45 static std::string getUniqueName(const std::string& prefix) {
46 std::vector<std::string> iflist = NetworkInterface::getInterfaces(0);
50 name = prefix + std::to_string(i++);
51 } while (std::find(iflist.begin(), iflist.end(), name) != iflist.end());
55 static void sendCmd(int fd, const char *txt) {
56 if (::write(fd, txt, 2) != 2) {
57 throw std::runtime_error("pipe write error");
63 int child_exec(void *_fd)
71 lxcpp::NetworkInterface("lo").up();
73 // child: waiting for parent
74 if (::read(fd[0], cmdbuf, 2) != 2) {
82 } else if (cmd == 'a') {
83 const char *argv[] = {
86 if (!utils::executeAndWait("/sbin/ip", argv)) {
87 throw std::runtime_error("ip addr failed");
89 } else if (cmd == 'r') {
90 const char *argv[] = {
91 "ip", "route", "list", NULL
93 if (!utils::executeAndWait("/sbin/ip", argv)) {
94 throw std::runtime_error("ip route failed");
96 } else if (cmd == 's') {
97 const char *argv[] = {
100 if (!utils::executeAndWait("/bin/bash", argv)) {
101 throw std::runtime_error("bash failed");
103 } else if (cmd == 'c') {
104 LOGW("connecting ... to be done");
122 * NOTE: network inerface unit tests are not finished yet
123 * tests are developed/added together with network interface code
124 * and container code development
127 BOOST_FIXTURE_TEST_SUITE(LxcppNetworkSuite, Fixture)
129 BOOST_AUTO_TEST_CASE(NetworkListInterfaces)
131 std::vector<std::string> iflist;
132 BOOST_CHECK_NO_THROW(iflist=NetworkInterface::getInterfaces(0));
133 for (const auto& ifn : iflist) {
134 const Attrs& attrs = NetworkInterface(ifn).getAttrs();
135 BOOST_CHECK(attrs.size() > 0);
140 BOOST_AUTO_TEST_CASE(NetworkConfigSerialization)
142 std::string tmpConfigFile = "/tmp/netconfig.conf";
144 BOOST_CHECK_NO_THROW(config::saveToJsonString(cfg));
146 cfg.addInterfaceConfig("host-veth0", "zone-eth0", InterfaceType::VETH);
147 cfg.addInterfaceConfig("host-veth1", "zone-eth1", InterfaceType::BRIDGE);
148 cfg.addInterfaceConfig("host-veth2", "zone-eth2", InterfaceType::MACVLAN);
150 cfg.addInetConfig("zone-eth0", InetAddr("1.2.3.4", 24));
152 config::saveToJsonFile(tmpConfigFile, cfg);
155 config::loadFromJsonFile(tmpConfigFile, cfg2);
157 int ifnum = cfg.getInterfaces().size();
158 for (int i = 0; i < ifnum; ++i) {
159 const NetworkInterfaceConfig& ni1 = cfg.getInterface(i);
160 const NetworkInterfaceConfig& ni2 = cfg2.getInterface(i);
162 BOOST_CHECK_EQUAL(ni1.getHostIf(), ni2.getHostIf());
163 BOOST_CHECK_EQUAL(ni1.getZoneIf(), ni2.getZoneIf());
164 BOOST_CHECK(ni1.getType() == ni2.getType());
165 BOOST_CHECK(ni1.getMode() == ni2.getMode());
169 BOOST_AUTO_TEST_CASE(NetworkBridgeCreateDestroy)
171 std::string name = getUniqueName("test-br");
172 NetworkInterface ni(name);
173 InetAddr myip("10.100.1.1", 32);
175 BOOST_CHECK_NO_THROW(ni.create(InterfaceType::BRIDGE));
176 ni.setMACAddress("12:22:33:44:55:66"); // note bit0=0 within first byte !!!
177 BOOST_CHECK_NO_THROW(ni.addInetAddr(myip));
179 std::vector<std::string> iflist = NetworkInterface::getInterfaces(0);
180 BOOST_CHECK(std::find(iflist.begin(), iflist.end(), name) != iflist.end());
182 std::vector<InetAddr> addrs = ni.getInetAddressList();
183 BOOST_CHECK(std::find(addrs.begin(), addrs.end(), myip) != addrs.end());
185 BOOST_CHECK_NO_THROW(ni.delInetAddr(myip));
186 BOOST_CHECK_NO_THROW(ni.destroy());
187 iflist = NetworkInterface::getInterfaces(0);
188 BOOST_CHECK(std::find(iflist.begin(), iflist.end(), ni.getName()) == iflist.end());
191 BOOST_AUTO_TEST_CASE(NetworkMacVLanCreateDestroy)
193 std::string masterif;
194 std::vector<std::string> iflist = NetworkInterface::getInterfaces(0);
195 for (const auto& ifn : iflist) {
199 NetworkInterface n(ifn);
200 if (n.status() == NetStatus::UP) {
206 NetworkInterface ni(getUniqueName("test-vlan"));
207 // creating MACVLAN on masterif
208 BOOST_CHECK_NO_THROW(ni.create(InterfaceType::MACVLAN, masterif, MacVLanMode::VEPA));
210 iflist = NetworkInterface::getInterfaces(0);
211 BOOST_CHECK(std::find(iflist.begin(), iflist.end(), ni.getName()) != iflist.end());
214 BOOST_CHECK_NO_THROW(ni.destroy());
216 iflist = NetworkInterface::getInterfaces(0);
217 BOOST_CHECK(std::find(iflist.begin(), iflist.end(), ni.getName()) == iflist.end());
220 BOOST_AUTO_TEST_CASE(NetworkListRoutes)
223 std::vector<Route> routes;
224 // tbl MAIN, all devs
225 BOOST_CHECK_NO_THROW(routes = NetworkInterface::getRoutes(0));
226 for (auto route : routes) {
227 if (route.ifname == "lo") {
232 // tbl LOCAL, all devs
233 BOOST_CHECK_NO_THROW(routes = NetworkInterface::getRoutes(0,RoutingTable::LOCAL));
235 // tbl DEFAULT, all devs
236 BOOST_CHECK_NO_THROW(routes = NetworkInterface::getRoutes(0,RoutingTable::DEFAULT));
238 NetworkInterface ni("lo");
240 BOOST_CHECK_NO_THROW(routes = ni.getRoutes());
241 BOOST_CHECK(routes.size() == mainLo);
244 BOOST_CHECK_NO_THROW(routes = ni.getRoutes(RoutingTable::LOCAL));
247 BOOST_AUTO_TEST_CASE(NetworkAddDelRoute)
249 std::vector<Route> routes;
252 InetAddr("10.100.1.0", 24),//dst - destination network
253 InetAddr("", 0), //src - not specified (prefix=0)
255 "", // ifname (used only when read routes)
256 RoutingTable::UNSPEC // table (used only when read rotes)
259 NetworkInterface ni("lo");
261 BOOST_CHECK_NO_THROW(ni.addRoute(route));
262 BOOST_CHECK_NO_THROW(routes = ni.getRoutes());
263 BOOST_CHECK(std::find_if(routes.begin(), routes.end(),
264 [&route](const Route& item) -> bool {
265 return item.dst == route.dst;
270 BOOST_CHECK_NO_THROW(ni.delRoute(route));
271 BOOST_CHECK_NO_THROW(routes = ni.getRoutes());
272 BOOST_CHECK(std::find_if(routes.begin(), routes.end(),
273 [&route](const Route& item) -> bool {
274 return item.dst == route.dst;
280 BOOST_AUTO_TEST_CASE(NetworkNamespaceCreate)
284 BOOST_CHECK(r != -1);
286 pid_t pid = lxcpp::clone(child_exec, fd, CLONE_NEWNET);
289 //directives for child process
290 sendCmd(fd[1], "0"); // exit
292 // waiting for child to finish
294 BOOST_CHECK_NO_THROW(status = lxcpp::waitpid(pid));
297 BOOST_CHECK_MESSAGE(status == 0, "child failed");
300 // this test case shows how to create container with network
301 // Note: this test needs some preparation to successfuly connect an external site:
302 // 1. allow network forwading (echo 1 > /proc/sys/net/ipv4/ip_forward)
303 // 2. configure ip masquarading (iptables -t nat -A POSTROUTING -s 10.0.0.0/16 ! -d 10.0.0.0/16 -j MASQUERADE)
304 BOOST_AUTO_TEST_CASE(NetworkNamespaceVETH)
306 const char *vbr = "vbr";
307 const char *veth1 = "veth-ma";
308 const char *veth2 = "veth-sl";
312 BOOST_CHECK(r != -1);
314 pid_t pid = lxcpp::clone(child_exec, fd, CLONE_NEWNET);
317 NetworkInterface br(vbr);
318 NetworkInterface v1(veth1);
319 NetworkInterface v2(veth2);
321 NetworkInterface("lo", pid).up();
323 // creating Bridge vbr
324 BOOST_CHECK_NO_THROW(br.create(InterfaceType::BRIDGE));
325 BOOST_CHECK_NO_THROW(br.up());
326 br.addInetAddr(InetAddr("10.0.0.1", 24));
328 // creating VETH pair veth1 <-> veth2
329 BOOST_CHECK_NO_THROW(v1.create(InterfaceType::VETH, v2.getName()));
331 // add veth1 to bridge
332 BOOST_CHECK_NO_THROW(v1.addToBridge(br.getName()));
334 // move veth2 to network namespace (container)
335 BOOST_CHECK_NO_THROW(v2.moveToContainer(pid));
337 v2.addInetAddr(InetAddr("10.0.0.2", 24));
339 v1.up(); // after v2 up and configured
343 InetAddr("10.0.0.1", 0), //dst - gateway
344 InetAddr("", 0), //src - not specified (prefix=0)
350 //directives for child process
351 sendCmd(fd[1], "a"); // ip addr show
352 sendCmd(fd[1], "r"); // ip route list
353 sendCmd(fd[1], "c"); // connect extern (needs configured NAT)
354 //sendCmd(fd[1], "s"); // exec shell
355 sendCmd(fd[1], "0"); // exit
357 // waiting for child to finish
359 BOOST_CHECK_NO_THROW(status = lxcpp::waitpid(pid));
361 BOOST_CHECK_MESSAGE(status == 0, "child failed");
363 BOOST_CHECK_NO_THROW(br.destroy());
366 BOOST_AUTO_TEST_SUITE_END()