lxcpp: network implementation (part 2) 01/48301/17
authorKrzysztof Dynowski <k.dynowski@samsung.com>
Thu, 3 Sep 2015 07:34:37 +0000 (09:34 +0200)
committerKrzysztof Dynowski <k.dynowski@samsung.com>
Sun, 27 Sep 2015 00:20:02 +0000 (02:20 +0200)
[Feature]       Network implementation for lxcpp (create/destroy, add/del ip addr)
[Cause]         N/A
[Solution]      N/A
[Verification]  Build, install, run tests

Change-Id: I1286efb4893b9b77bebf20f0e40b9fd06611e48b

14 files changed:
common/netlink/netlink-message.hpp
common/netlink/netlink.hpp
libs/config/CMakeLists.txt
libs/lxcpp/commands/netcreate.cpp
libs/lxcpp/commands/netcreate.hpp
libs/lxcpp/container-impl.cpp
libs/lxcpp/container-impl.hpp
libs/lxcpp/container.hpp
libs/lxcpp/network-config.cpp
libs/lxcpp/network-config.hpp
libs/lxcpp/network.cpp
libs/lxcpp/network.hpp
tests/unit_tests/lxcpp/ut-network.cpp
tests/unit_tests/server/ut-zone.cpp

index 73e6a4c..3ee729b 100644 (file)
@@ -35,6 +35,7 @@
 #include <sys/socket.h>
 #include <linux/netlink.h>
 
+//FIXME remove from namespace vasum
 namespace vasum {
 namespace netlink {
 
index 8d33957..56eff0b 100644 (file)
@@ -28,6 +28,7 @@
 #include <memory>
 #include <vector>
 
+//FIXME remove from namespace vasum
 namespace vasum {
 namespace netlink {
 
index 160cb09..81c8bbb 100644 (file)
@@ -40,7 +40,7 @@ SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES
 PKG_CHECK_MODULES(CONFIG_DEPS REQUIRED sqlite3 glib-2.0)
 PKG_SEARCH_MODULE(JSON_C REQUIRED json json-c)
 
-INCLUDE_DIRECTORIES(${LIBS_FOLDER})
+INCLUDE_DIRECTORIES(${LIBS_FOLDER} ${COMMON_FOLDER})
 INCLUDE_DIRECTORIES(SYSTEM ${CONFIG_DEPS_INCLUDE_DIRS} ${JSON_C_INCLUDE_DIRS})
 TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkgs_LDFLAGS} ${CONFIG_DEPS_LIBRARIES} ${JSON_C_LIBRARIES})
 
index 3c88d8e..56c1e2a 100644 (file)
@@ -28,17 +28,46 @@ namespace lxcpp {
 
 void NetCreateAll::execute()
 {
-    for (const auto& i : mInterfaceConfigs) {
-        NetworkInterface networkInerface(mContainerPid, i.getZoneIf());
-        networkInerface.create(i.getHostIf(), i.getType(), i.getMode());
+    pid_t pid = mContainer.getInitPid();
+    for (const auto& interface : mNetwork.getInterfaces()) {
+        NetworkInterface networkInterface(interface.getZoneIf(), pid);
+        networkInterface.create(interface.getType(), interface.getHostIf(), interface.getMode());
 
         Attrs attrs;
-        for (const auto& a : i.getAddrList()) {
-            Attr attr;
-            NetworkInterface::convertInetAddr2Attr(a, attr);
-            attrs.push_back(attr);
+        if (interface.getMTU() > 0) {
+            attrs.push_back(Attr{AttrName::MTU, std::to_string(interface.getMTU())});
         }
-        networkInerface.setAttrs(attrs);
+        if (!interface.getMACAddress().empty()) {
+            attrs.push_back(Attr{AttrName::MAC, interface.getMACAddress()});
+        }
+        if (interface.getTxLength() > 0) {
+            attrs.push_back(Attr{AttrName::TXQLEN, std::to_string(interface.getTxLength())});
+        }
+        networkInterface.setAttrs(attrs);
+
+        for (const auto& addr : interface.getAddrList()) {
+            networkInterface.addInetAddr(addr);
+        }
+    }
+}
+
+void NetInteraceCreate::execute()
+{
+    NetworkInterface networkInterface(mZoneIf, mContainer.getInitPid());
+    networkInterface.create(mType, mHostIf, mMode);
+}
+
+void NetInterfaceSetAttrs::execute()
+{
+    NetworkInterface networkInterface(mIfname, mContainer.getInitPid());
+    networkInterface.setAttrs(mAttrs);
+}
+
+void NetInterfaceAddInetAddr::execute()
+{
+    NetworkInterface networkInterface(mIfname, mContainer.getInitPid());
+    for (const auto& a : mAddrList) {
+        networkInterface.addInetAddr(a);
     }
 }
 
index 5d6e512..dec7288 100644 (file)
@@ -26,6 +26,7 @@
 
 #include "lxcpp/commands/command.hpp"
 #include "lxcpp/network-config.hpp"
+#include "lxcpp/container.hpp"
 
 #include <sys/types.h>
 
@@ -37,19 +38,81 @@ public:
     * Runs call in the container's context
     *
     * Creates and configures network interfaces in the container
-    *
     */
-    NetCreateAll(pid_t containerPid, const std::vector<NetworkInterfaceConfig>& iflist) :
-        mContainerPid(containerPid),
-        mInterfaceConfigs(iflist)
+    NetCreateAll(const Container& container, const NetworkConfig& network) :
+        mContainer(container),
+        mNetwork(network)
+    {
+    }
+
+    void execute();
+
+private:
+    const Container& mContainer;
+    const NetworkConfig& mNetwork;
+};
+
+class NetInteraceCreate final: Command {
+public:
+    NetInteraceCreate(const Container& container,
+                      const std::string& zoneif,
+                      const std::string& hostif,
+                      InterfaceType type,
+                      MacVLanMode mode=MacVLanMode::PRIVATE) :
+        mContainer(container),
+        mZoneIf(zoneif),
+        mHostIf(hostif),
+        mType(type),
+        mMode(mode)
+    {
+    }
+
+    void execute();
+
+private:
+    const Container& mContainer;
+    const std::string& mZoneIf;
+    const std::string& mHostIf;
+    InterfaceType mType;
+    MacVLanMode mMode;
+};
+
+class NetInterfaceSetAttrs final: Command {
+public:
+    NetInterfaceSetAttrs(const Container& container,
+                         const std::string& ifname,
+                         const Attrs& attrs) :
+        mContainer(container),
+        mIfname(ifname),
+        mAttrs(attrs)
+    {
+    }
+
+    void execute();
+
+private:
+    const Container& mContainer;
+    const std::string& mIfname;
+    const Attrs& mAttrs;
+};
+
+class NetInterfaceAddInetAddr final: Command {
+public:
+    NetInterfaceAddInetAddr(const Container& container,
+                            const std::string& ifname,
+                            const std::vector<InetAddr>& addrList) :
+        mContainer(container),
+        mIfname(ifname),
+        mAddrList(addrList)
     {
     }
 
     void execute();
 
 private:
-    const pid_t mContainerPid;
-    const std::vector<NetworkInterfaceConfig>& mInterfaceConfigs;
+    const Container& mContainer;
+    const std::string& mIfname;
+    const std::vector<InetAddr>& mAddrList;
 };
 
 } // namespace lxcpp
index 5301cb5..c7035e4 100644 (file)
@@ -230,9 +230,10 @@ const std::vector<Namespace>& ContainerImpl::getNamespaces() const
 void ContainerImpl::addInterfaceConfig(const std::string& hostif,
                                        const std::string& zoneif,
                                        InterfaceType type,
+                                       const std::vector<InetAddr>& addrs,
                                        MacVLanMode mode)
 {
-    mConfig.mNetwork.addInterfaceConfig(hostif, zoneif, type, mode);
+    mConfig.mNetwork.addInterfaceConfig(hostif, zoneif, type, addrs, mode);
 }
 
 void ContainerImpl::addInetConfig(const std::string& ifname, const InetAddr& addr)
@@ -247,10 +248,9 @@ std::vector<std::string> ContainerImpl::getInterfaces() const
 
 NetworkInterfaceInfo ContainerImpl::getInterfaceInfo(const std::string& ifname) const
 {
-    NetworkInterface ni(getInitPid(), ifname);
+    NetworkInterface ni(ifname, getInitPid());
     std::vector<InetAddr> addrs;
     std::string macaddr;
-    InetAddr addr;
     int mtu = 0, flags = 0;
     Attrs attrs = ni.getAttrs();
     for (const Attr& a : attrs) {
@@ -261,11 +261,6 @@ NetworkInterfaceInfo ContainerImpl::getInterfaceInfo(const std::string& ifname)
         case AttrName::MTU:
             mtu = std::stoul(a.value);
             break;
-        case AttrName::IPV6:
-        case AttrName::IPV4:
-            NetworkInterface::convertAttr2InetAddr(a, addr);
-            addrs.push_back(addr);
-            break;
         case AttrName::FLAGS:
             flags = std::stoul(a.value);
             break;
@@ -273,6 +268,7 @@ NetworkInterfaceInfo ContainerImpl::getInterfaceInfo(const std::string& ifname)
             break;
         }
     }
+    addrs = ni.getInetAddressList();
     return NetworkInterfaceInfo{ifname, ni.status(), macaddr, mtu, flags, addrs};
 }
 
@@ -281,33 +277,44 @@ void ContainerImpl::createInterface(const std::string& hostif,
                                     InterfaceType type,
                                     MacVLanMode mode)
 {
-    NetworkInterface ni(getInitPid(), zoneif);
-    ni.create(hostif, type, mode);
+    NetworkInterface ni(zoneif, getInitPid());
+    ni.create(type, hostif, mode);
 }
 
-void ContainerImpl::destroyInterface(const std::string& /*ifname*/)
+void ContainerImpl::destroyInterface(const std::string& ifname)
 {
-    throw NotImplementedException();
+    NetworkInterface ni(ifname, getInitPid());
+    ni.destroy();
 }
 
-void ContainerImpl::setUp(const std::string& /*ifname*/)
+void ContainerImpl::moveInterface(const std::string& ifname)
 {
-    throw NotImplementedException();
+    NetworkInterface ni(ifname);
+    ni.moveToContainer(getInitPid());
 }
 
-void ContainerImpl::setDown(const std::string& /*ifname*/)
+void ContainerImpl::setUp(const std::string& ifname)
 {
-    throw NotImplementedException();
+    NetworkInterface ni(ifname, getInitPid());
+    ni.up();
 }
 
-void ContainerImpl::addAddr(const std::string& /*ifname*/, const InetAddr& /*addr*/)
+void ContainerImpl::setDown(const std::string& ifname)
 {
-    throw NotImplementedException();
+    NetworkInterface ni(ifname, getInitPid());
+    ni.down();
 }
 
-void ContainerImpl::delAddr(const std::string& /*ifname*/, const InetAddr& /*addr*/)
+void ContainerImpl::addInetAddr(const std::string& ifname, const InetAddr& addr)
 {
-    throw NotImplementedException();
+    NetworkInterface ni(ifname, getInitPid());
+    ni.addInetAddr(addr);
+}
+
+void ContainerImpl::delInetAddr(const std::string& ifname, const InetAddr& addr)
+{
+    NetworkInterface ni(ifname, getInitPid());
+    ni.delInetAddr(addr);
 }
 
 } // namespace lxcpp
index b0786a1..7393974 100644 (file)
@@ -30,7 +30,6 @@
 #include "lxcpp/container-config.hpp"
 #include "lxcpp/container.hpp"
 #include "lxcpp/namespace.hpp"
-#include "lxcpp/network.hpp"
 
 namespace lxcpp {
 
@@ -77,6 +76,7 @@ public:
     void addInterfaceConfig(const std::string& hostif,
                             const std::string& zoneif,
                             InterfaceType type,
+                            const std::vector<InetAddr>& addrs,
                             MacVLanMode mode);
     void addInetConfig(const std::string& ifname, const InetAddr& addr);
 
@@ -87,11 +87,12 @@ public:
                          const std::string& zoneif,
                          InterfaceType type,
                          MacVLanMode mode);
+    void moveInterface(const std::string& ifname);
     void destroyInterface(const std::string& ifname);
     void setUp(const std::string& ifname);
     void setDown(const std::string& ifname);
-    void addAddr(const std::string& ifname, const InetAddr& addr);
-    void delAddr(const std::string& ifname, const InetAddr& addr);
+    void addInetAddr(const std::string& ifname, const InetAddr& addr);
+    void delInetAddr(const std::string& ifname, const InetAddr& addr);
 
 private:
     ContainerConfig mConfig;
index 96af842..51dda8c 100644 (file)
@@ -78,6 +78,7 @@ public:
     virtual void addInterfaceConfig(const std::string& hostif,
                                     const std::string& zoneif,
                                     InterfaceType type,
+                                    const std::vector<InetAddr>& addrs,
                                     MacVLanMode mode) = 0;
     virtual void addInetConfig(const std::string& ifname, const InetAddr& addr) = 0;
 
@@ -89,10 +90,11 @@ public:
                                  InterfaceType type,
                                  MacVLanMode mode) = 0;
     virtual void destroyInterface(const std::string& ifname) = 0;
+    virtual void moveInterface(const std::string& ifname) = 0;
     virtual void setUp(const std::string& ifname) = 0;
     virtual void setDown(const std::string& ifname) = 0;
-    virtual void addAddr(const std::string& ifname, const InetAddr& addr) = 0;
-    virtual void delAddr(const std::string& ifname, const InetAddr& addr) = 0;
+    virtual void addInetAddr(const std::string& ifname, const InetAddr& addr) = 0;
+    virtual void delInetAddr(const std::string& ifname, const InetAddr& addr) = 0;
 };
 
 } // namespace lxcpp
index 17e1449..89019ec 100644 (file)
  */
 
 #include "lxcpp/network-config.hpp"
-#include "lxcpp/network.hpp"
 #include "lxcpp/exception.hpp"
 #include "logger/logger.hpp"
 #include <algorithm>
 
-
 namespace lxcpp {
 
 const std::string& NetworkInterfaceConfig::getHostIf() const
@@ -41,14 +39,44 @@ const std::string& NetworkInterfaceConfig::getZoneIf() const
     return mZoneIf;
 }
 
-const InterfaceType& NetworkInterfaceConfig::getType() const
+InterfaceType NetworkInterfaceConfig::getType() const
+{
+    return static_cast<InterfaceType>(mType);
+}
+
+MacVLanMode NetworkInterfaceConfig::getMode() const
+{
+    return static_cast<MacVLanMode>(mMode);
+}
+
+void NetworkInterfaceConfig::setMTU(int mtu)
+{
+    mMtu = mtu;
+}
+
+void NetworkInterfaceConfig::setMACAddress(const std::string& mac)
 {
-    return mType;
+    mMacAddress = mac;
 }
 
-const MacVLanMode& NetworkInterfaceConfig::getMode() const
+void NetworkInterfaceConfig::setTxLength(int txlen)
 {
-    return mMode;
+    mTxLength = txlen;
+}
+
+int NetworkInterfaceConfig::getMTU() const
+{
+    return mMtu;
+}
+
+const std::string& NetworkInterfaceConfig::getMACAddress() const
+{
+    return mMacAddress;
+}
+
+int NetworkInterfaceConfig::getTxLength() const
+{
+    return mTxLength;
 }
 
 const std::vector<InetAddr>& NetworkInterfaceConfig::getAddrList() const
@@ -60,7 +88,7 @@ void NetworkInterfaceConfig::addInetAddr(const InetAddr& addr)
 {
     std::vector<InetAddr>::iterator exists = std::find(mIpAddrList.begin(), mIpAddrList.end(), addr);
     if (exists != mIpAddrList.end()) {
-        std::string msg("Address already assigned");
+        const std::string msg("Address already assigned");
         throw NetworkException(msg);
     }
     mIpAddrList.push_back(addr);
@@ -69,6 +97,7 @@ void NetworkInterfaceConfig::addInetAddr(const InetAddr& addr)
 void NetworkConfig::addInterfaceConfig(const std::string& hostif,
                                        const std::string& zoneif,
                                        InterfaceType type,
+                                       const std::vector<InetAddr>& addrs,
                                        MacVLanMode mode)
 {
     auto it = std::find_if(mInterfaces.begin(), mInterfaces.end(),
@@ -76,12 +105,13 @@ void NetworkConfig::addInterfaceConfig(const std::string& hostif,
             return entry.getZoneIf() == zoneif;
         }
     );
+
     if (it != mInterfaces.end()) {
-        std::string msg = "Interface already exists";
+        const std::string msg = "Interface already exists";
         LOGE(msg);
         throw NetworkException(msg);
     }
-    mInterfaces.push_back(NetworkInterfaceConfig(hostif,zoneif,type,mode));
+    mInterfaces.push_back(NetworkInterfaceConfig(hostif, zoneif, type, addrs, mode));
 }
 
 void NetworkConfig::addInetConfig(const std::string& ifname, const InetAddr& addr)
@@ -93,7 +123,7 @@ void NetworkConfig::addInetConfig(const std::string& ifname, const InetAddr& add
     );
 
     if (it == mInterfaces.end()) {
-        std::string msg = "No such interface";
+        const std::string msg = "No such interface";
         LOGE(msg);
         throw NetworkException(msg);
     }
index c94f45b..aa1ee18 100644 (file)
@@ -26,6 +26,9 @@
 
 #include "config/config.hpp"
 #include "config/fields.hpp"
+//#include "config/fields-union.hpp"
+#include "lxcpp/network.hpp"
+#include "lxcpp/exception.hpp"
 
 #include <vector>
 #include <string>
 namespace lxcpp {
 
 /**
- * Created interface type
- */
-enum class InterfaceType {
-    VETH,
-    BRIDGE,
-    MACVLAN,
-    MOVE
-};
-
-/**
- * Suported MacVLan modes
- */
-enum class MacVLanMode {
-    PRIVATE,
-    VEPA,
-    BRIDGE,
-    PASSTHRU
-};
-
-/**
- * Suported address types
- */
-enum class InetAddrType {
-    IPV4,
-    IPV6
-};
-
-enum class NetStatus {
-    DOWN,
-    UP
-};
-
-
-/**
- * Unified ip address
- */
-struct InetAddr {
-    InetAddrType type;
-    uint32_t flags;
-    int prefix;
-    union {
-        struct in_addr ipv4;
-        struct in6_addr ipv6;
-    } addr;
-};
-
-static inline bool operator==(const InetAddr& a, const InetAddr& b) {
-    if (a.type == b.type && a.prefix == b.prefix) {
-        if (a.type == InetAddrType::IPV4) {
-            return ::memcmp(&a.addr.ipv4, &b.addr.ipv4, sizeof(a.addr.ipv4)) == 0;
-        }
-        if (a.type == InetAddrType::IPV6) {
-            return ::memcmp(&a.addr.ipv6, &b.addr.ipv6, sizeof(a.addr.ipv6)) == 0;
-        }
-    }
-    return false;
-}
-
-
-/**
  * Network interface configuration
  */
 class NetworkInterfaceConfig {
 public:
+    NetworkInterfaceConfig() = default;  // default constructor required by visitor
+
     NetworkInterfaceConfig(const std::string& hostif,
                            const std::string& zoneif,
                            InterfaceType type,
-                           MacVLanMode mode = MacVLanMode::PRIVATE) :
+                           const std::vector<InetAddr>& addrs,
+                           MacVLanMode mode) :
         mHostIf(hostif),
         mZoneIf(zoneif),
-        mType(type),
-        mMode(mode)
+        mType(static_cast<int>(type)),
+        mMode(static_cast<int>(mode)),
+        mMtu(0),
+        mMacAddress(),
+        mTxLength(0),
+        mIpAddrList(addrs)
     {
     }
 
@@ -116,48 +66,79 @@ public:
 
     const std::string& getZoneIf() const;
 
-    const InterfaceType& getType() const;
+    InterfaceType getType() const;
 
-    const MacVLanMode& getMode() const;
+    MacVLanMode getMode() const;
+
+    void setMTU(int mtu);
+    int getMTU() const;
+
+    void setMACAddress(const std::string& mac);
+    const std::string& getMACAddress() const;
+
+    void setTxLength(int txlen);
+    int getTxLength() const;
 
     const std::vector<InetAddr>& getAddrList() const;
 
-    void addInetAddr(const InetAddr&);
+    void addInetAddr(const InetAddr& addr);
+
+    CONFIG_REGISTER
+    (
+        mHostIf,
+        mZoneIf,
+        mType,
+        mMode,
+        mIpAddrList
+    )
 
 private:
-    const std::string mHostIf;
-    const std::string mZoneIf;
-    const InterfaceType mType;
-    const MacVLanMode mMode;
-    //TODO mtu, macaddress, txqueue
+    std::string mHostIf;
+    std::string mZoneIf;
+    int mType;
+    int mMode;
+
     /*
-     * above are interface parameters which can be read/modified:
+     * interface parameters which can be set after interface is created
      *   MTU (Maximum Transmit Unit) is maximum length of link level packet in TCP stream
      *   MAC address is also called hardware card address
      *   TXQueue is transmit queue length
      *
-     * I think most usufull would be possibility to set MAC address, other have their
-     * well working defaults but can be tuned to make faster networking (especially localy)
+     * I think most useful would be possibility to set MAC address, other have their
+     * well working defaults but can be tuned to make faster networking (especially locally)
      */
+    int mMtu;
+    std::string mMacAddress;
+    int mTxLength;
+
     std::vector<InetAddr> mIpAddrList;
 };
 
 /**
  * Network interface configuration
  */
-struct NetworkConfig {
-
-    //for convinience
+class NetworkConfig {
+public:
+    /**
+     * adds interface configuration.
+     * throws NetworkException if zoneif name already on list
+     */
     void addInterfaceConfig(const std::string& hostif,
                             const std::string& zoneif,
                             InterfaceType type,
-                            MacVLanMode mode);
+                            const std::vector<InetAddr>& addrs = std::vector<InetAddr>(),
+                            MacVLanMode mode = MacVLanMode::PRIVATE);
     void addInetConfig(const std::string& ifname, const InetAddr& addr);
 
-    std::vector<NetworkInterfaceConfig> mInterfaces;
+    const std::vector<NetworkInterfaceConfig>& getInterfaces() const { return mInterfaces; }
+    const NetworkInterfaceConfig& getInterface(int i) const { return mInterfaces.at(i); }
+
+    CONFIG_REGISTER(
+        mInterfaces
+    )
 
-    //TODO tmporary to allow serialization of this object
-    CONFIG_REGISTER_EMPTY
+private:
+    std::vector<NetworkInterfaceConfig> mInterfaces;
 };
 
 } //namespace lxcpp
index 965f20c..1214e5c 100644 (file)
 #include "netlink/netlink-message.hpp"
 #include "utils/make-clean.hpp"
 #include "utils/text.hpp"
+#include "utils/exception.hpp"
 #include "logger/logger.hpp"
 
 #include <iostream>
 
-#include <linux/rtnetlink.h>
+#include <unistd.h>
 #include <net/if.h>
+#include <sys/ioctl.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+#include <linux/sockios.h>
+#include <linux/if_bridge.h>
 
 #define CHANGE_FLAGS_DEFAULT 0xffffffff
 /* from linux/if_addr.h:
@@ -52,35 +58,12 @@ using namespace vasum::netlink;
 namespace lxcpp {
 
 namespace {
-std::string toString(const in_addr& addr)
-{
-    char buf[INET_ADDRSTRLEN];
-    const char* ret = ::inet_ntop(AF_INET, &addr, buf, INET_ADDRSTRLEN);
-    if (ret == NULL) {
-        std::string msg = "Can't parse inet v4 addr";
-        LOGE(msg);
-        throw NetworkException(msg);
-    }
-    return ret;
-}
-
-std::string toString(const in6_addr& addr)
-{
-    char buf[INET6_ADDRSTRLEN];
-    const char* ret = ::inet_ntop(AF_INET6, &addr, buf, INET6_ADDRSTRLEN);
-    if (ret == NULL) {
-        std::string msg = "Can't parse inet v6 addr";
-        LOGE(msg);
-        throw NetworkException(msg);
-    }
-    return ret;
-}
 
 uint32_t getInterfaceIndex(const std::string& name)
 {
     uint32_t index = ::if_nametoindex(name.c_str());
     if (!index) {
-        std::string msg = "Can't find interface";
+        const std::string msg = "Can't find interface " + utils::getSystemErrorMessage();
         LOGE(msg);
         throw NetworkException(msg);
     }
@@ -90,24 +73,35 @@ uint32_t getInterfaceIndex(const std::string& name)
 uint32_t getInterfaceIndex(const std::string& name, pid_t pid)
 {
     NetlinkMessage nlm(RTM_GETLINK, NLM_F_REQUEST | NLM_F_ACK);
-    ifinfomsg infoPeer = utils::make_clean<ifinfomsg>();
-    infoPeer.ifi_family = AF_UNSPEC;
-    infoPeer.ifi_change = CHANGE_FLAGS_DEFAULT;
-    nlm.put(infoPeer)
+    ifinfomsg info = utils::make_clean<ifinfomsg>();
+    info.ifi_family = AF_UNSPEC;
+    info.ifi_change = CHANGE_FLAGS_DEFAULT;
+    nlm.put(info)
         .put(IFLA_IFNAME, name);
 
     NetlinkResponse response = send(nlm, pid);
     if (!response.hasMessage()) {
-        std::string msg = "Can't get interface index";
+        const std::string msg = "Can't get interface index";
         LOGE(msg);
         throw NetworkException(msg);
     }
 
-    response.fetch(infoPeer);
-    return infoPeer.ifi_index;
+    response.fetch(info);
+    return info.ifi_index;
+}
+
+void bridgeModify(const std::string& ifname, uint32_t masterIndex) {
+    NetlinkMessage nlm(RTM_SETLINK, NLM_F_REQUEST | NLM_F_ACK);
+    ifinfomsg info = utils::make_clean<ifinfomsg>();
+    info.ifi_family = AF_UNSPEC;
+    info.ifi_change = CHANGE_FLAGS_DEFAULT;
+    info.ifi_index = getInterfaceIndex(ifname);
+    nlm.put(info)
+        .put(IFLA_MASTER, masterIndex);
+    send(nlm);
 }
 
-void getAddressAttrs(Attrs& attrs, int family, const std::string& ifname, pid_t pid)
+void getAddressList(std::vector<InetAddr>& addrs, int family, const std::string& ifname, pid_t pid)
 {
     uint32_t index = getInterfaceIndex(ifname, pid);
     NetlinkMessage nlm(RTM_GETADDR, NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP);
@@ -116,22 +110,17 @@ void getAddressAttrs(Attrs& attrs, int family, const std::string& ifname, pid_t
     nlm.put(infoAddr);
 
     NetlinkResponse response = send(nlm, pid);
-    if (!response.hasMessage()) {
-        return ;
-    }
-
-    Attr attr;
     while (response.hasMessage()) {
         ifaddrmsg addrmsg;
         response.fetch(addrmsg);
         if (addrmsg.ifa_index == index) {
             InetAddr a;
             if (addrmsg.ifa_family == AF_INET6) {
-                a.type = InetAddrType::IPV6;
+                a.setType(InetAddrType::IPV6);
             } else if (addrmsg.ifa_family == AF_INET) {
-                a.type = InetAddrType::IPV4;
+                a.setType(InetAddrType::IPV4);
             } else {
-                std::string msg = "Unsupported inet family";
+                const std::string msg = "Unsupported inet family";
                 LOGE(msg);
                 throw NetworkException(msg);
             }
@@ -153,14 +142,14 @@ void getAddressAttrs(Attrs& attrs, int family, const std::string& ifname, pid_t
                     // fall thru
                 case IFA_LOCAL: //2
                     if (addrmsg.ifa_family == AF_INET6) {
-                        response.fetch(attrType, a.addr.ipv6);
+                        response.fetch(attrType, a.getAddr<in6_addr>());
                     } else if (addrmsg.ifa_family == AF_INET) {
-                        response.fetch(attrType, a.addr.ipv4);
+                        response.fetch(attrType, a.getAddr<in_addr>());
                     } else {
                         LOGW("unsupported family " << addrmsg.ifa_family);
                         response.skipAttribute();
                     }
-                    hasLocal=true;
+                    hasLocal = true;
                     break;
 
                 case IFA_FLAGS:  //8  extended flags - overwrites addrmsg.ifa_flags
@@ -180,8 +169,7 @@ void getAddressAttrs(Attrs& attrs, int family, const std::string& ifname, pid_t
                     break;
                 }
             }
-            NetworkInterface::convertInetAddr2Attr(a, attr);
-            attrs.push_back(attr);
+            addrs.push_back(a);
         }
         response.fetchNextMessage();
     }
@@ -189,146 +177,256 @@ void getAddressAttrs(Attrs& attrs, int family, const std::string& ifname, pid_t
 } // anonymous namespace
 
 
-void NetworkInterface::create(const std::string& hostif,
-                              InterfaceType type,
+std::string toString(const in_addr& addr)
+{
+    char buf[INET_ADDRSTRLEN];
+    const char* ret = ::inet_ntop(AF_INET, &addr, buf, INET_ADDRSTRLEN);
+    if (ret == NULL) {
+        const std::string msg = "Wrong inet v4 addr " + utils::getSystemErrorMessage();
+        LOGE(msg);
+        throw NetworkException(msg);
+    }
+    return ret;
+}
+
+std::string toString(const in6_addr& addr)
+{
+    char buf[INET6_ADDRSTRLEN];
+    const char* ret = ::inet_ntop(AF_INET6, &addr, buf, INET6_ADDRSTRLEN);
+    if (ret == NULL) {
+        const std::string msg = "Wrong inet v6 addr " + utils::getSystemErrorMessage();
+        LOGE(msg);
+        throw NetworkException(msg);
+    }
+    return ret;
+}
+
+void fromString(const std::string& s, in_addr& addr)
+{
+    if (s.empty()) {
+        ::memset(&addr, 0, sizeof(addr));
+    }
+    else if (::inet_pton(AF_INET, s.c_str(), &addr) != 1) {
+        const std::string msg = "Can't parse inet v4 addr " + utils::getSystemErrorMessage();
+        LOGE(msg);
+        throw NetworkException(msg);
+    }
+}
+
+void fromString(const std::string& s, in6_addr& addr)
+{
+    if (s == ":") {
+        ::memset(&addr, 0, sizeof(addr));
+    }
+    else if (::inet_pton(AF_INET6, s.c_str(), &addr) != 1) {
+        const std::string msg = "Can't parse inet v6 addr " + utils::getSystemErrorMessage();
+        LOGE(msg);
+        throw NetworkException(msg);
+    }
+}
+
+std::string toString(const InetAddr& a) {
+    std::string opts = "/" + std::to_string(a.prefix);
+    if (a.getType() == InetAddrType::IPV6) {
+        return toString(a.getAddr<in6_addr>()) + opts;
+    }
+    if (a.getType() == InetAddrType::IPV4) {
+        return toString(a.getAddr<in_addr>()) + opts;
+    }
+    return "";
+}
+
+InetAddr::InetAddr(uint32_t f, int p, const std::string& a)
+{
+    if (a.find(":") != std::string::npos) {
+        setType(InetAddrType::IPV6);
+        fromString(a, getAddr<in6_addr>());
+    } else {
+        setType(InetAddrType::IPV4);
+        fromString(a, getAddr<in_addr>());
+    }
+    flags = f;
+    prefix = p;
+}
+
+void NetworkInterface::create(InterfaceType type,
+                              const std::string& peerif,
                               MacVLanMode mode)
 {
     switch (type) {
         case InterfaceType::VETH:
-            createVeth(hostif);
+            createVeth(peerif);
             break;
         case InterfaceType::BRIDGE:
-            createBridge(hostif);
+            createBridge();
             break;
         case InterfaceType::MACVLAN:
-            createMacVLan(hostif, mode);
-            break;
-        case InterfaceType::MOVE:
-            move(hostif);
+            createMacVLan(peerif, mode);
             break;
         default:
             throw NetworkException("Unsuported interface type");
     }
 }
 
-void NetworkInterface::createVeth(const std::string& /*hostif*/)
+void NetworkInterface::createVeth(const std::string& peerif)
 {
-    throw NotImplementedException();
+    NetlinkMessage nlm(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK);
+    ifinfomsg info = utils::make_clean<ifinfomsg>();
+    info.ifi_family = AF_UNSPEC;
+    info.ifi_change = CHANGE_FLAGS_DEFAULT;
+    nlm.put(info)
+        .put(IFLA_IFNAME, mIfname)
+        .beginNested(IFLA_LINKINFO)
+            .put(IFLA_INFO_KIND, "veth")
+            .beginNested(IFLA_INFO_DATA)
+                .beginNested(VETH_INFO_PEER)
+                    .put(info)
+                    .put(IFLA_IFNAME, peerif)
+                .endNested()
+            .endNested()
+        .endNested();
+    send(nlm);
 }
 
-void NetworkInterface::createBridge(const std::string& /*hostif*/)
+void NetworkInterface::createBridge()
 {
-    throw NotImplementedException();
+    NetlinkMessage nlm(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK);
+    ifinfomsg info = utils::make_clean<ifinfomsg>();
+    info.ifi_family = AF_UNSPEC;
+    info.ifi_change = CHANGE_FLAGS_DEFAULT;
+    nlm.put(info)
+        .beginNested(IFLA_LINKINFO)
+            .put(IFLA_INFO_KIND, "bridge")
+            .beginNested(IFLA_INFO_DATA)
+                .beginNested(IFLA_AF_SPEC)
+                    .put<uint32_t>(IFLA_BRIDGE_FLAGS, BRIDGE_FLAGS_MASTER)
+                .endNested()
+            .endNested()
+        .endNested()
+        .put(IFLA_IFNAME, mIfname); //bridge name (will be created)
+    send(nlm);
 }
 
-void NetworkInterface::createMacVLan(const std::string& /*hostif*/, MacVLanMode /*mode*/)
+void NetworkInterface::createMacVLan(const std::string& maserif, MacVLanMode mode)
 {
-    throw NotImplementedException();
+    uint32_t index = getInterfaceIndex(maserif);
+    NetlinkMessage nlm(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK);
+    ifinfomsg info = utils::make_clean<ifinfomsg>();
+    info.ifi_family = AF_UNSPEC;
+    info.ifi_change = CHANGE_FLAGS_DEFAULT;
+    nlm.put(info)
+        .beginNested(IFLA_LINKINFO)
+            .put(IFLA_INFO_KIND, "macvlan")
+            .beginNested(IFLA_INFO_DATA)
+                .put(IFLA_MACVLAN_MODE, static_cast<uint32_t>(mode))
+            .endNested()
+        .endNested()
+        .put(IFLA_LINK, index)      //master index
+        .put(IFLA_IFNAME, mIfname); //slave name (will be created)
+    send(nlm);
 }
 
-void NetworkInterface::move(const std::string& hostif)
+void NetworkInterface::moveToContainer(pid_t pid)
 {
-     uint32_t index = getInterfaceIndex(hostif);
-     NetlinkMessage nlm(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_ACK);
-     ifinfomsg infopeer = utils::make_clean<ifinfomsg>();
-     infopeer.ifi_family = AF_UNSPEC;
-     infopeer.ifi_index = index;
-     nlm.put(infopeer)
-        .put(IFLA_NET_NS_PID, mContainerPid);
-     send(nlm);
-
-     //rename to mIfname inside container
-     if (mIfname != hostif) {
-         renameFrom(hostif);
-     }
+    NetlinkMessage nlm(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_ACK);
+    ifinfomsg info = utils::make_clean<ifinfomsg>();
+    info.ifi_family = AF_UNSPEC;
+    info.ifi_index = getInterfaceIndex(mIfname);
+    nlm.put(info)
+        .put(IFLA_NET_NS_PID, pid);
+    send(nlm);
+    mContainerPid = pid;
 }
 
 void NetworkInterface::destroy()
 {
-    throw NotImplementedException();
+    //uint32_t index = getInterfaceIndex(mIfname);
+    NetlinkMessage nlm(RTM_DELLINK, NLM_F_REQUEST | NLM_F_ACK);
+    ifinfomsg info = utils::make_clean<ifinfomsg>();
+    info.ifi_family = AF_UNSPEC;
+    info.ifi_change = CHANGE_FLAGS_DEFAULT;
+    info.ifi_index = getInterfaceIndex(mIfname, mContainerPid);
+    nlm.put(info)
+        .put(IFLA_IFNAME, mIfname);
+    send(nlm);
 }
 
-NetStatus NetworkInterface::status()
+NetStatus NetworkInterface::status() const
 {
-    throw NotImplementedException();
-    /*
-    //TODO get container status, if stopped return CONFIGURED
-    if (mContainerPid<=0) return CONFIGURED;
-    // read netlink
-    return DOWN;*/
-}
-
+    NetlinkMessage nlm(RTM_GETLINK, NLM_F_REQUEST | NLM_F_ACK);
+    ifinfomsg info = utils::make_clean<ifinfomsg>();
+    info.ifi_family = AF_UNSPEC;
+    info.ifi_change = CHANGE_FLAGS_DEFAULT;
+    nlm.put(info)
+        .put(IFLA_IFNAME, mIfname);
 
-void NetworkInterface::up()
-{
-    throw NotImplementedException();
-}
+    NetlinkResponse response = send(nlm, mContainerPid);
+    if (!response.hasMessage()) {
+        throw NetworkException("Can't get interface information");
+    }
 
-void NetworkInterface::down()
-{
-    throw NotImplementedException();
+    response.fetch(info);
+    return (info.ifi_flags & IFF_UP) != 0 ? NetStatus::UP : NetStatus::DOWN;
 }
 
 void NetworkInterface::renameFrom(const std::string& oldif)
 {
     NetlinkMessage nlm(RTM_SETLINK, NLM_F_REQUEST | NLM_F_ACK);
-    ifinfomsg infoPeer = utils::make_clean<ifinfomsg>();
-    infoPeer.ifi_family = AF_UNSPEC;
-    infoPeer.ifi_index = getInterfaceIndex(oldif, mContainerPid);
-    infoPeer.ifi_change = CHANGE_FLAGS_DEFAULT;
+    ifinfomsg info = utils::make_clean<ifinfomsg>();
+    info.ifi_family = AF_UNSPEC;
+    info.ifi_index = getInterfaceIndex(oldif, mContainerPid);
+    info.ifi_change = CHANGE_FLAGS_DEFAULT;
 
-    nlm.put(infoPeer)
+    nlm.put(info)
         .put(IFLA_IFNAME, mIfname);
     send(nlm, mContainerPid);
 }
 
-void NetworkInterface::addInetAddr(const InetAddr& addr)
+void NetworkInterface::addToBridge(const std::string& bridge)
 {
-    NetlinkMessage nlm(RTM_NEWADDR, NLM_F_CREATE | NLM_F_REQUEST | NLM_F_ACK);
-    ifaddrmsg infoAddr = utils::make_clean<ifaddrmsg>();
-    infoAddr.ifa_index = getInterfaceIndex(mIfname, mContainerPid);
-    infoAddr.ifa_family = addr.type == InetAddrType::IPV4 ? AF_INET : AF_INET6;
-    infoAddr.ifa_prefixlen = addr.prefix;
-    infoAddr.ifa_flags = addr.flags;
-    nlm.put(infoAddr);
-
-    if (addr.type == InetAddrType::IPV6) {
-        nlm.put(IFA_ADDRESS, addr.addr.ipv6);
-        nlm.put(IFA_LOCAL, addr.addr.ipv6);
-    } else if (addr.type == InetAddrType::IPV4) {
-        nlm.put(IFA_ADDRESS, addr.addr.ipv4);
-        nlm.put(IFA_LOCAL, addr.addr.ipv4);
-    }
+    bridgeModify(mIfname, getInterfaceIndex(bridge));
+}
 
-    send(nlm, mContainerPid);
+void NetworkInterface::delFromBridge()
+{
+    bridgeModify(mIfname, 0);
 }
 
+
 void NetworkInterface::setAttrs(const Attrs& attrs)
 {
+    if (attrs.empty()) {
+        return ;
+    }
+
     //TODO check this: NetlinkMessage nlm(RTM_SETLINK, NLM_F_REQUEST | NLM_F_ACK);
     NetlinkMessage nlm(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_CREATE | NLM_F_ACK);
-    unsigned mtu=0, link=0, txq=0;
-    ifinfomsg infoPeer = utils::make_clean<ifinfomsg>();
-    infoPeer.ifi_family = AF_UNSPEC;
-    infoPeer.ifi_index = getInterfaceIndex(mIfname, mContainerPid);
-    infoPeer.ifi_change = CHANGE_FLAGS_DEFAULT;
+    ifinfomsg info = utils::make_clean<ifinfomsg>();
+    info.ifi_index = getInterfaceIndex(mIfname, mContainerPid);
+    info.ifi_family = AF_UNSPEC;
+    info.ifi_change = CHANGE_FLAGS_DEFAULT;
 
+    std::string mac;
+    unsigned mtu = 0, link = 0, txq = 0;
     for (const auto& attr : attrs) {
         if (attr.name == AttrName::FLAGS) {
-             infoPeer.ifi_flags = stoul(attr.value);
+            info.ifi_flags = stoul(attr.value);
         } else if (attr.name == AttrName::CHANGE) {
-            infoPeer.ifi_change = stoul(attr.value);
+            info.ifi_change = stoul(attr.value);
         } else if (attr.name == AttrName::TYPE) {
-            infoPeer.ifi_type = stoul(attr.value);
+            info.ifi_type = stoul(attr.value);
         } else if (attr.name == AttrName::MTU) {
             mtu = stoul(attr.value);
         } else if (attr.name == AttrName::LINK) {
             link = stoul(attr.value);
         } else if (attr.name == AttrName::TXQLEN) {
             txq = stoul(attr.value);
+        } else if (attr.name == AttrName::MAC) {
+            mac = attr.value;
         }
+
     }
-    nlm.put(infoPeer);
+    nlm.put(info);
     if (mtu) {
         nlm.put<uint32_t>(IFLA_MTU, mtu);
     }
@@ -338,28 +436,23 @@ void NetworkInterface::setAttrs(const Attrs& attrs)
     if (txq) {
         nlm.put<uint32_t>(IFLA_TXQLEN, txq);
     }
+    if (!mac.empty()) {
+        nlm.put(IFLA_ADDRESS, mac);
+    }
 
     NetlinkResponse response = send(nlm, mContainerPid);
     if (!response.hasMessage()) {
         throw NetworkException("Can't set interface information");
     }
-
-    // configure inet addresses
-    InetAddr addr;
-    for (const Attr& a : attrs) {
-        if (convertAttr2InetAddr(a, addr)) {
-            addInetAddr(addr);
-        }
-    }
 }
 
 Attrs NetworkInterface::getAttrs() const
 {
     NetlinkMessage nlm(RTM_GETLINK, NLM_F_REQUEST | NLM_F_ACK);
-    ifinfomsg infoPeer = utils::make_clean<ifinfomsg>();
-    infoPeer.ifi_family = AF_UNSPEC;
-    infoPeer.ifi_change = CHANGE_FLAGS_DEFAULT;
-    nlm.put(infoPeer)
+    ifinfomsg info = utils::make_clean<ifinfomsg>();
+    info.ifi_family = AF_UNSPEC;
+    info.ifi_change = CHANGE_FLAGS_DEFAULT;
+    nlm.put(info)
         .put(IFLA_IFNAME, mIfname);
 
     NetlinkResponse response = send(nlm, mContainerPid);
@@ -368,9 +461,9 @@ Attrs NetworkInterface::getAttrs() const
     }
 
     Attrs attrs;
-    response.fetch(infoPeer);
-    attrs.push_back(Attr{AttrName::FLAGS, std::to_string(infoPeer.ifi_flags)});
-    attrs.push_back(Attr{AttrName::TYPE, std::to_string(infoPeer.ifi_type)});
+    response.fetch(info);
+    attrs.push_back(Attr{AttrName::FLAGS, std::to_string(info.ifi_flags)});
+    attrs.push_back(Attr{AttrName::TYPE, std::to_string(info.ifi_type)});
 
     while (response.hasAttribute()) {
         /*
@@ -412,15 +505,100 @@ Attrs NetworkInterface::getAttrs() const
             break;
         }
     }
-    getAddressAttrs(attrs, AF_INET, mIfname, mContainerPid);
-    getAddressAttrs(attrs, AF_INET6, mIfname, mContainerPid);
     return attrs;
 }
 
+void NetworkInterface::addInetAddr(const InetAddr& addr)
+{
+    NetlinkMessage nlm(RTM_NEWADDR, NLM_F_CREATE | NLM_F_REQUEST | NLM_F_ACK);
+    ifaddrmsg infoAddr = utils::make_clean<ifaddrmsg>();
+    infoAddr.ifa_index = getInterfaceIndex(mIfname, mContainerPid);
+    infoAddr.ifa_family = addr.getType() == InetAddrType::IPV4 ? AF_INET : AF_INET6;
+    infoAddr.ifa_prefixlen = addr.prefix;
+    infoAddr.ifa_flags = addr.flags;
+    nlm.put(infoAddr);
+
+    if (addr.getType() == InetAddrType::IPV6) {
+        nlm.put(IFA_ADDRESS, addr.getAddr<in6_addr>());
+        nlm.put(IFA_LOCAL, addr.getAddr<in6_addr>());
+    } else if (addr.getType() == InetAddrType::IPV4) {
+        nlm.put(IFA_ADDRESS, addr.getAddr<in_addr>());
+        nlm.put(IFA_LOCAL, addr.getAddr<in_addr>());
+    }
+
+    send(nlm, mContainerPid);
+}
+
+void NetworkInterface::delInetAddr(const InetAddr& addr)
+{
+    NetlinkMessage nlm(RTM_DELADDR, NLM_F_REQUEST | NLM_F_ACK);
+    ifaddrmsg infoAddr = utils::make_clean<ifaddrmsg>();
+    infoAddr.ifa_index = getInterfaceIndex(mIfname, mContainerPid);
+    infoAddr.ifa_family = addr.getType() == InetAddrType::IPV4 ? AF_INET : AF_INET6;
+    infoAddr.ifa_prefixlen = addr.prefix;
+    infoAddr.ifa_flags = addr.flags;
+    nlm.put(infoAddr);
+
+    if (addr.getType() == InetAddrType::IPV6) {
+        nlm.put(IFA_ADDRESS, addr.getAddr<in6_addr>());
+        nlm.put(IFA_LOCAL, addr.getAddr<in6_addr>());
+    } else if (addr.getType() == InetAddrType::IPV4) {
+        nlm.put(IFA_ADDRESS, addr.getAddr<in_addr>());
+        nlm.put(IFA_LOCAL, addr.getAddr<in_addr>());
+    }
+
+    send(nlm, mContainerPid);
+}
+
+std::vector<InetAddr> NetworkInterface::getInetAddressList() const
+{
+    std::vector<InetAddr> addrs;
+    getAddressList(addrs, AF_UNSPEC, mIfname, mContainerPid);
+    return addrs;
+}
+
+void NetworkInterface::up()
+{
+    Attrs attrs;
+    attrs.push_back(Attr{AttrName::CHANGE, std::to_string(IFF_UP)});
+    attrs.push_back(Attr{AttrName::FLAGS, std::to_string(IFF_UP)});
+    setAttrs(attrs);
+}
+
+void NetworkInterface::down()
+{
+    Attrs attrs;
+    attrs.push_back(Attr{AttrName::CHANGE, std::to_string(IFF_UP)});
+    attrs.push_back(Attr{AttrName::FLAGS, std::to_string(0)});
+    setAttrs(attrs);
+}
+
+void NetworkInterface::setMACAddress(const std::string& macaddr)
+{
+    Attrs attrs;
+    attrs.push_back(Attr{AttrName::MAC, macaddr});
+    setAttrs(attrs);
+}
+
+void NetworkInterface::setMTU(int mtu)
+{
+    Attrs attrs;
+    attrs.push_back(Attr{AttrName::MTU, std::to_string(mtu)});
+    setAttrs(attrs);
+}
+
+void NetworkInterface::setTxLength(int txqlen)
+{
+    Attrs attrs;
+    attrs.push_back(Attr{AttrName::TXQLEN, std::to_string(txqlen)});
+    setAttrs(attrs);
+}
+
+
 std::vector<std::string> NetworkInterface::getInterfaces(pid_t initpid)
 {
     // get interfaces seen by netlink
-    NetlinkMessage nlm(RTM_GETLINK, NLM_F_REQUEST|NLM_F_DUMP|NLM_F_ROOT);
+    NetlinkMessage nlm(RTM_GETLINK, NLM_F_REQUEST | NLM_F_DUMP | NLM_F_ROOT);
     ifinfomsg info = utils::make_clean<ifinfomsg>();
     info.ifi_family = AF_PACKET;
     nlm.put(info);
@@ -439,78 +617,4 @@ std::vector<std::string> NetworkInterface::getInterfaces(pid_t initpid)
     return iflist;
 }
 
-void NetworkInterface::convertInetAddr2Attr(const InetAddr& a, Attr& attr)
-{
-    std::string value;
-
-    if (a.type == InetAddrType::IPV6) {
-        value += "ip=" + toString(a.addr.ipv6);
-    } else if (a.type == InetAddrType::IPV4) {
-        value += "ip=" + toString(a.addr.ipv4);
-    } else {
-        throw NetworkException();
-    }
-
-    value += ",pfx=" + std::to_string(a.prefix);
-    value += ",flags=" + std::to_string(a.flags);
-
-    if (a.type == InetAddrType::IPV6) {
-        attr = Attr{AttrName::IPV6, value};
-    } else {
-        attr = Attr{AttrName::IPV4, value};
-    }
-}
-
-bool NetworkInterface::convertAttr2InetAddr(const Attr& attr, InetAddr& addr)
-{
-    std::string::size_type s = 0U;
-    std::string::size_type e = s;
-
-    if (attr.name != AttrName::IPV6 && attr.name != AttrName::IPV4) {
-        return false; //not inet attribute
-    }
-
-    addr.prefix = 0;
-    addr.flags = 0;
-
-    bool addrFound = false;
-    while (e != std::string::npos) {
-        e = attr.value.find(',', s);
-        std::string ss = attr.value.substr(s, e - s);
-        s = e + 1;
-
-        std::string name;
-        std::string value;
-        std::string::size_type p = ss.find('=');
-        if (p != std::string::npos) {
-            name = ss.substr(0, p);
-            value = ss.substr(p + 1);
-        } else {
-            name = ss;
-            //value remains empty
-        }
-
-        if (name == "ip") {
-            if (attr.name == AttrName::IPV6) {
-                addr.type = InetAddrType::IPV6;
-                if (inet_pton(AF_INET6, value.c_str(), &addr.addr.ipv6) != 1) {
-                    throw NetworkException("Parse IPV6 address");
-                }
-            } else if (attr.name == AttrName::IPV4) {
-                addr.type = InetAddrType::IPV4;
-                if (inet_pton(AF_INET, value.c_str(), &addr.addr.ipv4) != 1) {
-                    throw NetworkException("Parse IPV4 address");
-                }
-            }
-            addrFound = true;
-        } else if (name == "pfx") {
-            addr.prefix = stoul(value);
-        } else if (name == "flags") {
-            addr.flags = stoul(value);
-        }
-    }
-
-    return addrFound;
-}
-
 } // namespace lxcpp
index cc0167e..a1ebf49 100644 (file)
 #ifndef LXCPP_NETWORK_HPP
 #define LXCPP_NETWORK_HPP
 
-#include "lxcpp/network-config.hpp"
+#include "config/fields.hpp"
 
+#include <cstring>
 #include <string>
 #include <vector>
 #include <ostream>
 
+#include <arpa/inet.h>
+
 namespace lxcpp {
 
+std::string toString(const in_addr& addr);
+std::string toString(const in6_addr& addr);
+void fromString(const std::string& s, in_addr& addr);
+void fromString(const std::string& s, in6_addr& addr);
+
+/**
+ * Suported address types
+ */
+enum class InetAddrType {
+    IPV4,
+    IPV6
+};
+
+/**
+ * Unified ip address
+ */
+class InetAddr {
+public:
+    InetAddr() {}
+    InetAddr(uint32_t flags, int prefix, const std::string& addr);
+
+    InetAddrType getType() const {
+        return static_cast<InetAddrType>(type);
+    }
+    void setType(InetAddrType t) {
+        type = static_cast<int>(t);
+    }
+
+    template<typename T>
+    T& getAddr() {
+        //FIXME return union field after fix of addr type
+        char *v = addr;
+        return *(reinterpret_cast<T*>(v));
+    }
+    template<typename T>
+    const T& getAddr() const {
+        //FIXME return union field after fix of addr type
+        const char *v = addr;
+        return *(reinterpret_cast<const T*>(v));
+    }
+
+    uint32_t flags;
+    int prefix;
+
+    CONFIG_REGISTER
+    (
+        type,
+        flags,
+        prefix
+        //FIXME add when visitor can serialize char[SIZE]
+        //addr
+    )
+
+private:
+ //FIXME change to union when visitor can serialize type by istream ostream operators
+    char addr[sizeof(in6_addr)];
+ //FIXME: change to enum when visitor can serialize type by istream ostream operators
+    int type;
+};
+
+static inline bool operator==(const in_addr& a, const in_addr& b)
+{
+    return ::memcmp(&a, &b, sizeof(a)) == 0;
+}
+
+static inline bool operator==(const in6_addr& a, const in6_addr& b)
+{
+    return ::memcmp(&a, &b, sizeof(a)) == 0;
+}
+
+static inline bool operator==(const InetAddr& a, const InetAddr& b)
+{
+    if (a.getType() == b.getType() && a.prefix == b.prefix) {
+        if (a.getType() == InetAddrType::IPV6)
+            return a.getAddr<in6_addr>() == b.getAddr<in6_addr>();
+        else
+            return a.getAddr<in_addr>() == b.getAddr<in_addr>();
+    }
+    return false;
+}
+
+std::string toString(const InetAddr& a);
+
+enum class RoutingTable {
+    UNSPEC, // also means 'any'
+    COMPAT,
+    DEFAULT,
+    MAIN,
+    LOCAL,
+    USER,
+};
+inline std::string toString(RoutingTable rt) {
+    switch (rt) {
+    case RoutingTable::UNSPEC:
+        return "unspec";
+    case RoutingTable::COMPAT:
+        return "compat";
+    case RoutingTable::DEFAULT:
+        return "default";
+    case RoutingTable::MAIN:
+        return "main";
+    case RoutingTable::LOCAL:
+        return "local";
+    default:
+        return "user";
+    }
+}
+
 enum class AttrName {
     MAC,
     FLAGS,
@@ -40,8 +151,6 @@ enum class AttrName {
     MTU,
     LINK,
     TXQLEN,
-    IPV4,
-    IPV6,
 };
 
 inline std::ostream& operator<<(std::ostream& os, const AttrName& a) {
@@ -53,8 +162,6 @@ inline std::ostream& operator<<(std::ostream& os, const AttrName& a) {
         case AttrName::MTU: os << "mtu"; break;
         case AttrName::LINK: os << "link"; break;
         case AttrName::TXQLEN: os << "txq"; break;
-        case AttrName::IPV4: os << "ipv4"; break;
-        case AttrName::IPV6: os << "ipv6"; break;
     }
     return os;
 }
@@ -67,62 +174,165 @@ struct Attr {
 typedef std::vector<Attr> Attrs;
 
 /**
+ * Created interface type
+ */
+enum class InterfaceType : int {
+    VETH,
+    BRIDGE,
+    MACVLAN
+};
+
+/**
+ * Suported MacVLan modes
+ */
+enum class MacVLanMode {
+    PRIVATE,
+    VEPA,
+    BRIDGE,
+    PASSTHRU
+};
+
+enum class NetStatus {
+    DOWN,
+    UP
+};
+
+std::string toString(const InetAddr& a);
+
+/**
  * Network operations to be performed on given container and interface
  * operates on netlink device
  */
 class NetworkInterface {
 public:
     /**
-     * Create network interface object for the ifname in the container
+     * Create network interface object for the ifname in the container (network namespace)
+     * Note: pid=0 is kernel
      */
-    NetworkInterface(pid_t pid, const std::string& ifname) :
-        mContainerPid(pid),
-        mIfname(ifname)
+    NetworkInterface(const std::string& ifname, pid_t pid = 0) :
+        mIfname(ifname),
+        mContainerPid(pid)
     {
     }
 
     const std::string& getName() const { return mIfname; }
 
-    //Network actions on Container
-    void create(const std::string& hostif, InterfaceType type, MacVLanMode mode=MacVLanMode::PRIVATE);
+    /**
+     * Retrieve network interface status (UP or DOWN)
+     */
+    NetStatus status() const;
+
+    /**
+     * Create network interface in container identified by mContainerPid
+     * Equivalent to: ip link add @mIfname type @type [...]
+     *   Create pair of virtual ethernet interfaces
+     *      ip link add @mIfname type veth peer name @peerif
+     *   Create bridge interface
+     *      ip link add @mIfname type bridge
+     *   Create psedo-ethernet interface on existing one
+     *      ip link add @mIfname type macvlan link @peerif [mode @mode]
+     */
+    void create(InterfaceType type, const std::string& peerif, MacVLanMode mode = MacVLanMode::PRIVATE);
+
+    /**
+     * Delete interface
+     * Equivalent to: ip link delete @mIfname
+     */
     void destroy();
 
-    NetStatus status();
-    void up();
-    void down();
+    /**
+     * Move interface to container
+     * Equivalent to: ip link set dev @hostif netns @mContainerPid
+     */
+    void moveToContainer(pid_t p);
 
     /**
      * Rename interface name
-     * Equivalent to: ip link set dev $oldif name $this.mIfname
+     * Equivalent to: ip link set dev @oldif name @mIfname
      */
     void renameFrom(const std::string& oldif);
 
+    /**
+     * Add interface to the bridge
+     * Equivalent to: ip link set @mIfname master @bridge
+     */
+    void addToBridge(const std::string& bridge);
+
+    /**
+     * Remove insterface from the bridge
+     * Equivalent to: ip link set @mIfname nomaster
+     */
+    void delFromBridge();
+
+    /**
+     * Set or get interface attributes in one netlink call.
+     * Supported attributes: see @AttrNames
+     */
     void setAttrs(const Attrs& attrs);
     Attrs getAttrs() const;
 
-    void setMACAddress(const std::string& macaddr);
-    void setMTU(int mtu);
-    void setTxLength(int txlen);
+    /**
+     * Add inet address to the interface
+     * Equivalent to: ip addr add @addr dev @mIfname
+     */
     void addInetAddr(const InetAddr& addr);
+
+    /**
+     * Remove inet address from the interface
+     * Equivalent to: ip addr del @addr dev @mIfname
+     */
     void delInetAddr(const InetAddr& addr);
 
-    static std::vector<std::string> getInterfaces(pid_t initpid);
+    /**
+     * Retrieve all inet addresses for the interface
+     * Equivalent to: ip addr show, ip -6 addr show
+     */
+    std::vector<InetAddr> getInetAddressList() const;
 
-    static void convertInetAddr2Attr(const InetAddr& addr, Attr& attr);
-    static bool convertAttr2InetAddr(const Attr& attr, InetAddr& addr);
+    /**
+     * Set interface up
+     * Equivalent to: ip link set @mInface up
+     */
+    void up();
 
-private:
-    void createVeth(const std::string& hostif);
-    void createBridge(const std::string& hostif);
-    void createMacVLan(const std::string& hostif, MacVLanMode mode);
     /**
-     * Move interface to container
-     * Equivalent to: ip link set dev $hostif netns $mContainerPid
+     * Set interface down
+     * Equivalent to: ip link set @mInface down
      */
-    void move(const std::string& hostif);
+    void down();
+
+    /**
+     * Set MAC address attribute
+     * Equivalent to: ip link set @mIface address @macaddr
+     * @macaddr in format AA:BB:CC:DD:FF:GG
+     */
+    void setMACAddress(const std::string& macaddr);
+
+    /**
+     * Set MTU attribute
+     * Equivalent to: ip link set @mIface mtu @mtu
+     */
+    void setMTU(int mtu);
+
+    /**
+     * Set TxQ attribute
+     * Equivalent to: ip link set @mIface txqueue @txlen
+     */
+    void setTxLength(int txlen);
+
+    /**
+     * Get list of network interafece names
+     * Equivalent to: ip link show
+     */
+    static std::vector<std::string> getInterfaces(pid_t initpid);
+
+private:
+    void createVeth(const std::string& peerif);
+    void createBridge();
+    void createMacVLan(const std::string& masterif, MacVLanMode mode);
 
-    pid_t mContainerPid;       ///< Container pid to operate on (0=kernel)
     const std::string mIfname; ///< network interface name inside zone
+    pid_t mContainerPid;       ///< Container pid to operate on (0 means kernel)
 };
 
 } // namespace lxcpp
index 373ec1b..f797a6c 100644 (file)
 
 #include "config.hpp"
 #include "config/manager.hpp"
-#include "lxcpp/network.hpp"
+#include "lxcpp/network-config.hpp"
 #include "ut.hpp"
 
 #include <iostream>
 #include <sched.h>
 
+#include <net/if.h>
+
 namespace {
 
+using namespace lxcpp;
+using namespace config;
+
 struct Fixture {
     Fixture() {}
     ~Fixture() {}
+
+    static std::string getUniqueName(const std::string& prefix) {
+        std::vector<std::string> iflist = NetworkInterface::getInterfaces(0);
+        std::string name;
+        unsigned i = 0;
+        do {
+            name = prefix + std::to_string(i++);
+        } while (std::find(iflist.begin(), iflist.end(), name) != iflist.end());
+        return name;
+    }
 };
 
 } // namespace
@@ -46,38 +61,112 @@ struct Fixture {
 
 BOOST_FIXTURE_TEST_SUITE(LxcppNetworkSuite, Fixture)
 
-using namespace lxcpp;
-
-BOOST_AUTO_TEST_CASE(ListInterfaces)
+BOOST_AUTO_TEST_CASE(NetworkListInterfaces)
 {
     std::vector<std::string> iflist;
-    BOOST_CHECK_NO_THROW(iflist = NetworkInterface::getInterfaces(0);)
-    for (const auto& i : iflist) {
-        std::cout << i << std::endl;
-    }
-}
+    BOOST_CHECK_NO_THROW(iflist = NetworkInterface::getInterfaces(0));
 
-BOOST_AUTO_TEST_CASE(DetailedListInterfaces)
-{
-    std::vector<std::string> iflist;
-    BOOST_CHECK_NO_THROW(iflist = NetworkInterface::getInterfaces(0);)
     for (const auto& i : iflist) {
-        NetworkInterface ni(1,i);
-        std::cout << "Attrs of " << i << std::endl;
+        NetworkInterface ni(i);
+        std::cout << i << ": ";
         Attrs attrs;
-        BOOST_CHECK_NO_THROW(attrs = ni.getAttrs();)
+        std::vector<InetAddr> addrs;
+        BOOST_CHECK_NO_THROW(attrs = ni.getAttrs());
         for (const Attr& a : attrs) {
-            std::cout << a.name << "=" << a.value << "; ";
+            std::cout << a.name << "=" << a.value;
+            if (a.name == AttrName::FLAGS) {
+                uint32_t f = stoul(a.value);
+                std::cout << "(";
+                std::cout << ((f & IFF_UP) !=0 ? "UP" : "DONW");
+                std::cout << ")";
+            }
+            std::cout << "; ";
         }
         std::cout << std::endl;
+
+        BOOST_CHECK_NO_THROW(addrs = ni.getInetAddressList());
+        for (const InetAddr& a : addrs) {
+            std::cout << "   " << toString(a) << std::endl;
+        }
     }
 }
+
 BOOST_AUTO_TEST_CASE(NetworkConfigSerialization)
 {
+    std::string tmpConfigFile = "/tmp/netconfig.conf";
     NetworkConfig cfg;
-    std::string json;
-    BOOST_CHECK_NO_THROW(json = config::saveToJsonString(cfg);)
-    std::cout << json << std::endl;
+    BOOST_CHECK_NO_THROW(config::saveToJsonString(cfg));
+
+    cfg.addInterfaceConfig("host-veth0", "zone-eth0", InterfaceType::VETH);
+    cfg.addInterfaceConfig("host-veth1", "zone-eth1", InterfaceType::BRIDGE);
+    cfg.addInterfaceConfig("host-veth2", "zone-eth2", InterfaceType::MACVLAN);
+
+    InetAddr addr(0, 24, "1.2.3.4");
+    cfg.addInetConfig("zone-eth0", addr);
+
+    config::saveToJsonFile(tmpConfigFile, cfg);
+
+    NetworkConfig cfg2;
+    config::loadFromJsonFile(tmpConfigFile, cfg2);
+
+    int ifnum = cfg.getInterfaces().size();
+    for (int i = 0; i < ifnum; ++i) {
+        const NetworkInterfaceConfig& ni1 = cfg.getInterface(i);
+        const NetworkInterfaceConfig& ni2 = cfg2.getInterface(i);
+
+        BOOST_CHECK_EQUAL(ni1.getHostIf(), ni2.getHostIf());
+        BOOST_CHECK_EQUAL(ni1.getZoneIf(), ni2.getZoneIf());
+        BOOST_CHECK(ni1.getType() == ni2.getType());
+        BOOST_CHECK(ni1.getMode() == ni2.getMode());
+    }
+}
+BOOST_AUTO_TEST_CASE(NetworkBridgeCreateDestroy)
+{
+    std::string name = getUniqueName("lolo");
+    NetworkInterface ni(name);
+    InetAddr myip(0, 32, "10.100.1.1");
+
+    BOOST_CHECK_NO_THROW(ni.create(InterfaceType::BRIDGE, ""));
+    BOOST_CHECK_NO_THROW(ni.addInetAddr(myip);)
+
+    std::vector<std::string> iflist = NetworkInterface::getInterfaces(0);
+    BOOST_CHECK(std::find(iflist.begin(), iflist.end(), name) != iflist.end());
+
+    std::vector<InetAddr> addrs = ni.getInetAddressList();
+    BOOST_CHECK(std::find(addrs.begin(), addrs.end(), myip) != addrs.end());
+    for (const auto& i : iflist) {
+        std::cout << "  " << i;
+    }
+    std::cout << std::endl;
+    for (const InetAddr& a : addrs) {
+        std::cout << "   " << toString(a) << std::endl;
+    }
+
+    BOOST_CHECK_NO_THROW(ni.delInetAddr(myip));
+    BOOST_CHECK_NO_THROW(ni.destroy());
+}
+
+BOOST_AUTO_TEST_CASE(NetworkMacVLanCreateDestroy)
+{
+    std::string masterif;
+    std::vector<std::string> iflist = NetworkInterface::getInterfaces(0);
+    for (const auto& ifn : iflist) {
+        if (ifn == "lo") continue;
+        NetworkInterface n(ifn);
+        if (n.status() == NetStatus::UP) {
+            masterif = ifn;
+            break;
+        }
+    }
+
+    NetworkInterface ni(getUniqueName("lolo"));
+    std::cout << " creating MACVLAN on " << masterif << std::endl;
+    BOOST_CHECK_NO_THROW(ni.create(InterfaceType::MACVLAN, masterif, MacVLanMode::VEPA));
+
+    iflist = NetworkInterface::getInterfaces(0);
+    BOOST_CHECK(std::find(iflist.begin(), iflist.end(), ni.getName()) != iflist.end());
+
+    BOOST_CHECK_NO_THROW(ni.destroy());
 }
 
 BOOST_AUTO_TEST_SUITE_END()
index aefb29a..c7740e9 100644 (file)
@@ -42,8 +42,6 @@
 #include <thread>
 #include <chrono>
 #include <sys/socket.h>
-#include <linux/in6.h>
-#include <linux/if_bridge.h>
 #include <linux/if.h>
 
 using namespace utils;