Creating netdev 69/35369/13
authorMateusz Malicki <m.malicki2@samsung.com>
Thu, 12 Feb 2015 15:39:58 +0000 (16:39 +0100)
committerJan Olszak <j.olszak@samsung.com>
Mon, 2 Mar 2015 15:40:26 +0000 (07:40 -0800)
[Feature]       Filled stubs for creating netdev (create_netdev_phys,
                create_netdev_macvlan, create_netdev_veth)
[Cause]         N/A
[Solution]      Manage netdev through netlink interface
[Verification]  Build, install, run vasum-server,
                create zone (vasum-cli create_zone zone1),
                start zone (vasum-cli start_zone zone1),
                move interface f.e. p2p1 to zone (vasum-cli create_netdev_phys zone1 p2p1)
                enter to zone (lxc-console -n zone1 --lxcpath=/usr/local/share/.zones -t 0)
                    check interfaces (ifconfig -a)
                do analogous for create_netdev_macvlan and create_netdev_veth

Change-Id: I299d3ebeb8f101a386f5b156dbe79d7779600ef6

common/lxc/zone.cpp
common/lxc/zone.hpp
common/netlink/netlink-message.cpp [new file with mode: 0644]
common/netlink/netlink-message.hpp [new file with mode: 0644]
common/netlink/netlink.cpp [new file with mode: 0644]
common/netlink/netlink.hpp [new file with mode: 0644]
server/netdev.cpp [new file with mode: 0644]
server/netdev.hpp [new file with mode: 0644]
server/zone-admin.cpp

index dc148e4..bbb1e02 100644 (file)
@@ -313,6 +313,11 @@ bool LxcZone::waitForState(State state, int timeout)
     return true;
 }
 
+pid_t LxcZone::getInitPid() const
+{
+    return mLxcContainer->init_pid(mLxcContainer);
+}
+
 bool LxcZone::setRunLevel(int runLevel)
 {
     auto callback = [](void* param) -> int {
index 1573c7d..0ed19a3 100644 (file)
@@ -26,6 +26,7 @@
 #define COMMON_LXC_ZONE_HPP
 
 #include <string>
+#include <sys/types.h>
 
 // fwd declaration of lxc internals
 struct lxc_container;
@@ -136,6 +137,12 @@ public:
      * Unfreeze zone
      */
     bool unfreeze();
+
+    /**
+     * Get pid of init process
+     */
+    pid_t getInitPid() const;
+
 private:
     lxc_container* mLxcContainer;
 
diff --git a/common/netlink/netlink-message.cpp b/common/netlink/netlink-message.cpp
new file mode 100644 (file)
index 0000000..72d3597
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ *  Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Mateusz Malicki <m.malicki2@samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author  Mateusz Malicki (m.malicki2@samsung.com)
+ * @brief   Netlink message class definition
+ */
+
+#include "config.hpp"
+#include "netlink-message.hpp"
+#include "netlink.hpp"
+#include "base-exception.hpp"
+
+#include <logger/logger.hpp>
+
+#include <memory>
+#include <cstring>
+#include <cassert>
+
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#ifndef PAGE_SIZE
+#define PAGE_SIZE 4096
+#endif
+
+const int NLMSG_GOOD_SIZE = 2*PAGE_SIZE;
+constexpr rtattr* NLMSG_TAIL(nlmsghdr* nmsg)
+{
+    return reinterpret_cast<rtattr*>(reinterpret_cast<char*>(nmsg) + NLMSG_ALIGN(nmsg->nlmsg_len));
+}
+
+namespace vasum {
+namespace netlink {
+
+NetlinkMessage::NetlinkMessage(uint16_t type, uint16_t flags)
+{
+    static uint32_t seq = 0;
+    mNlmsg.resize(NLMSG_GOOD_SIZE, 0);
+    hdr().nlmsg_len = NLMSG_HDRLEN;
+    hdr().nlmsg_flags = flags | NLM_F_ACK;
+    hdr().nlmsg_type = type;
+    hdr().nlmsg_seq = ++seq;
+    hdr().nlmsg_pid = getpid();
+}
+
+NetlinkMessage& NetlinkMessage::beginNested(int ifla)
+{
+    struct rtattr *nest = NLMSG_TAIL(&hdr());
+    put(ifla, NULL, 0);
+    mNested.push(nest);
+    return *this;
+}
+
+NetlinkMessage& NetlinkMessage::endNested()
+{
+    assert(!mNested.empty());
+    rtattr *nest = reinterpret_cast<rtattr*>(mNested.top());
+    nest->rta_len = std::distance(reinterpret_cast<char*>(nest),
+                                  reinterpret_cast<char*>(NLMSG_TAIL(&hdr())));
+    mNested.pop();
+    return *this;
+}
+
+NetlinkMessage& NetlinkMessage::put(int ifla, const std::string& value)
+{
+    return put(ifla, value.c_str(), value.size() + 1);
+}
+
+NetlinkMessage& NetlinkMessage::put(int ifla, const void* data, int len)
+{
+    struct rtattr *rta;
+    size_t rtalen = RTA_LENGTH(len);
+    int newLen = NLMSG_ALIGN(hdr().nlmsg_len) + RTA_ALIGN(rtalen);
+
+    setMinCapacity(newLen);
+    rta = NLMSG_TAIL(&hdr());
+    rta->rta_type = ifla;
+    rta->rta_len = rtalen;
+    memcpy(RTA_DATA(rta), data, len);
+    hdr().nlmsg_len = newLen;
+    return *this;
+}
+
+NetlinkMessage& NetlinkMessage::put(const void* data, int len)
+{
+    setMinCapacity(hdr().nlmsg_len + len);
+    memcpy((reinterpret_cast<char*>(&hdr()) + hdr().nlmsg_len), data, len);
+    hdr().nlmsg_len += len;
+    return *this;
+}
+
+nlmsghdr& NetlinkMessage::hdr() {
+    return *reinterpret_cast<nlmsghdr*>(mNlmsg.data());
+}
+
+const nlmsghdr& NetlinkMessage::hdr() const {
+    return *reinterpret_cast<const nlmsghdr*>(mNlmsg.data());
+}
+
+void NetlinkMessage::setMinCapacity(unsigned int size)
+{
+    if (mNlmsg.size() < size) {
+        mNlmsg.resize(size, 0);
+    }
+}
+
+void send(const NetlinkMessage& msg)
+{
+    //TODO: Handle messages with responses
+    assert(msg.hdr().nlmsg_flags & NLM_F_ACK);
+
+    const int answerLen = NLMSG_ALIGN(msg.hdr().nlmsg_len + sizeof(nlmsgerr));
+    std::unique_ptr<char[]> answerBuff(new char[answerLen]);
+    nlmsghdr* answer = reinterpret_cast<nlmsghdr*>(answerBuff.get());
+    answer->nlmsg_len =  answerLen;
+
+    Netlink nl;
+    nl.open();
+    try {
+        nl.send(&msg.hdr());
+        //Receive ACK Netlink Message
+        do {
+            nl.rcv(answer);
+        } while (answer->nlmsg_type == NLMSG_NOOP);
+    } catch (const std::exception& ex) {
+        LOGE("Sending failed (" << ex.what() << ")");
+        nl.close();
+        throw;
+    }
+    nl.close();
+    if (answer->nlmsg_type != NLMSG_ERROR) {
+        // It is not NACK/ACK message
+        throw VasumException("Sending failed ( unrecognized message type )");
+    }
+    nlmsgerr *err = reinterpret_cast<nlmsgerr*>(NLMSG_DATA(answer));
+    if (answer->nlmsg_seq != msg.hdr().nlmsg_seq) {
+        throw VasumException("Sending failed ( answer message was mismatched )");
+    }
+    if (err->error) {
+        throw VasumException("Sending failed (" + getSystemErrorMessage(-err->error) + ")");
+    }
+}
+
+} // namespace netlink
+} // namespace vasum
diff --git a/common/netlink/netlink-message.hpp b/common/netlink/netlink-message.hpp
new file mode 100644 (file)
index 0000000..e828feb
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ *  Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Mateusz Malicki <m.malicki2@samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author  Mateusz Malicki (m.malicki2@samsung.com)
+ * @brief   Netlink message class declaration
+ */
+
+#ifndef COMMON_NETLINK_NETLINK_MESSAGE_HPP
+#define COMMON_NETLINK_NETLINK_MESSAGE_HPP
+
+#include <string>
+#include <vector>
+#include <stack>
+#include <type_traits>
+#include <cstdlib>
+#include <linux/netlink.h>
+
+namespace vasum {
+namespace netlink {
+
+/**
+ *  NetlinkMessage is used to creatie a netlink messages
+ */
+class NetlinkMessage {
+public:
+    /**
+     * Create netlink message
+     *
+     * @param type rtnetlink message type (see man 7 rtnetlink)
+     * @param flags nlmsg flags (see man 7 netlink)
+     */
+    NetlinkMessage(std::uint16_t type, std::uint16_t flags);
+
+    /**
+     * Add nested atribute type
+     *
+     * All future attributes will be nested in this attribute (till call to endNested)
+     *
+     * @param ifla attribute name
+     */
+    NetlinkMessage& beginNested(int ifla);
+
+    /**
+     * End nested atribute
+     */
+    NetlinkMessage& endNested();
+
+    ///@{
+    /*Add sample attribute */
+    NetlinkMessage& put(int ifla, const std::string& value);
+    template<class T>
+    NetlinkMessage& put(int ifla, const T& value);
+    ///@}
+
+    /**
+     * Add raw data
+     *
+     * Add raw data to end of netlink message
+     */
+    template<class T>
+    NetlinkMessage& put(const T& value);
+
+    /**
+     * Send netlink message
+     *
+     * It is not thread safe
+     */
+    friend void send(const NetlinkMessage& msg);
+private:
+    std::vector<char> mNlmsg;
+    std::stack<void*> mNested;
+
+    NetlinkMessage& put(int ifla, const void* data, int len);
+    NetlinkMessage& put(const void* data, int len);
+    nlmsghdr& hdr();
+    const nlmsghdr& hdr() const;
+    void setMinCapacity(unsigned int size);
+
+
+};
+
+template<class T>
+NetlinkMessage& NetlinkMessage::put(int ifla, const T& value)
+{
+    static_assert(std::is_pod<T>::value, "Require trivial and standard-layout");
+    return put(ifla, &value, sizeof(value));
+}
+
+template<class T>
+NetlinkMessage& NetlinkMessage::put(const T& value)
+{
+    static_assert(std::is_pod<T>::value, "Require trivial and standard-layout structure");
+    return put(&value, sizeof(value));
+}
+
+} // namespace netlink
+} // namespace vasum
+
+#endif // COMMON_NETLINK_NETLINK_MESSAGE_HPP
diff --git a/common/netlink/netlink.cpp b/common/netlink/netlink.cpp
new file mode 100644 (file)
index 0000000..fa86b45
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ *  Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Mateusz Malicki <m.malicki2@samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author  Mateusz Malicki (m.malicki2@samsung.com)
+ * @brief   Netlink class definition
+ */
+
+#include "config.hpp"
+#include "netlink.hpp"
+#include "utils.hpp"
+#include "base-exception.hpp"
+
+#include <logger/logger.hpp>
+#include <cassert>
+#include <algorithm>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <linux/netlink.h>
+
+namespace vasum {
+
+namespace {
+
+template<class T>
+T make_clean()
+{
+    static_assert(std::is_pod<T>::value, "make_clean require trivial and standard-layout");
+    T value;
+    std::fill_n(reinterpret_cast<char*>(&value), sizeof(value), 0);
+    return value;
+}
+
+} // namespace
+
+Netlink::Netlink() : mFd(-1)
+{
+}
+
+Netlink::~Netlink()
+{
+    close();
+}
+
+void Netlink::open()
+{
+    assert(mFd == -1);
+    mFd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+    if (mFd == -1) {
+        LOGE("Can't open socket (" << getSystemErrorMessage() << ")");
+        throw VasumException("Can't open netlink connection");
+    }
+
+    sockaddr_nl local = make_clean<sockaddr_nl>();
+    local.nl_family = AF_NETLINK;
+
+    if (bind(mFd, (struct sockaddr *)&local, sizeof(local)) < 0) {
+        int err = errno;
+        close();
+        LOGE("Can't bind to socket (" << getSystemErrorMessage(err) << ")");
+        throw VasumException("Can't set up netlink connection");
+    }
+}
+
+void Netlink::close()
+{
+    if (mFd != -1) {
+        ::close(mFd);
+        mFd = -1;
+    }
+}
+
+void Netlink::send(const nlmsghdr *nlmsg)
+{
+    msghdr msg = make_clean<msghdr>();
+    sockaddr_nl nladdr = make_clean<sockaddr_nl>();
+    iovec iov = make_clean<iovec>();
+
+    iov.iov_base = (void *)nlmsg;
+    iov.iov_len = nlmsg->nlmsg_len;
+    msg.msg_name = &nladdr;
+    msg.msg_namelen = sizeof(nladdr);
+    msg.msg_iov = &iov;
+    msg.msg_iovlen = 1;
+    nladdr.nl_family = AF_NETLINK;
+
+    int ret = sendmsg(mFd, &msg, 0);
+    if (ret < 0) {
+        LOGE("Can't send message (" << getSystemErrorMessage() << ")");
+        throw VasumException("Can't send netlink message");
+    }
+}
+
+int Netlink::rcv(nlmsghdr *answer)
+{
+    //TODO: Handle too small buffer situation (buffer resizing)
+    msghdr msg = make_clean<msghdr>();
+    sockaddr_nl nladdr = make_clean<sockaddr_nl>();
+    iovec iov = make_clean<iovec>();
+
+    iov.iov_base = answer;
+    iov.iov_len = answer->nlmsg_len;
+    msg.msg_name = &nladdr;
+    msg.msg_namelen = sizeof(nladdr);
+    msg.msg_iov = &iov;
+    msg.msg_iovlen = 1;
+    nladdr.nl_family = AF_NETLINK;
+
+    int ret = recvmsg(mFd, &msg, 0);
+    if (ret < 0) {
+        LOGE("Can't receive message (" + getSystemErrorMessage() + ")");
+        throw VasumException("Can't receive netlink message");
+    }
+    if (ret == 0) {
+        LOGE("Peer has performed an orderly shutdown");
+        throw VasumException("Can't receive netlink message");
+    }
+    if (msg.msg_flags & MSG_TRUNC) {
+        LOGE("Can't receive message (" + getSystemErrorMessage(EMSGSIZE) + ")");
+        throw VasumException("Can't receive netlink message");
+    }
+    if (msg.msg_flags & MSG_ERRQUEUE) {
+        LOGE("No data was received but an extended error");
+        throw VasumException("Can't receive netlink message");
+    }
+    if (msg.msg_flags & MSG_OOB) {
+        LOGE("Internal error (expedited or out-of-band data were received)");
+        throw VasumException("Can't receive netlink message");
+    }
+    if (msg.msg_flags & (MSG_EOR | MSG_CTRUNC)) {
+        assert(!"This should not happen!");
+        LOGE("Internal error (" << std::to_string(msg.msg_flags) << ")");
+        throw VasumException("Internal error while recaiving netlink message");
+    }
+
+    return ret;
+}
+
+} //namespace vasum
diff --git a/common/netlink/netlink.hpp b/common/netlink/netlink.hpp
new file mode 100644 (file)
index 0000000..2e73ce8
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ *  Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Mateusz Malicki <m.malicki2@samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author  Mateusz Malicki (m.malicki2@samsung.com)
+ * @brief   Netlink class declaration
+ */
+
+#ifndef COMMON_NETLINK_NETLINK_HPP
+#define COMMON_NETLINK_NETLINK_HPP
+
+#include <linux/netlink.h>
+
+namespace vasum {
+
+/**
+ * Netlink class is responsible for communicating
+ * with kernel through netlink interface
+ */
+class Netlink {
+public:
+    Netlink();
+    ~Netlink();
+
+    Netlink(const Netlink& other) = delete;
+    Netlink& operator=(const Netlink& other) = delete;
+
+    /**
+     * Open connnection
+     */
+    void open();
+
+    /**
+     * Close connection
+     */
+    void close();
+
+    /**
+     * Send message
+     *
+     * It is not thread safe and even you shouldn't call this function on
+     * different instances at the same time
+     *
+     * @param nlmsg pointer to message
+     */
+    void send(const nlmsghdr *nlmsg);
+
+    /**
+     * Receive message
+     *
+     * It is not thread safe and even you shouldn't call this function on
+     * different instances at the same time
+     *
+     * @param answer pointer to answer buffer
+     */
+    int rcv(nlmsghdr *answer);
+private:
+    int mFd;
+};
+
+} // namespace vasum
+
+#endif /* COMMON_NETLINK_NETLINK_HPP */
diff --git a/server/netdev.cpp b/server/netdev.cpp
new file mode 100644 (file)
index 0000000..b4a2d21
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+ *  Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Mateusz Malicki <m.malicki2@samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author  Mateusz Malicki (m.malicki2@samsung.com)
+ * @brief   Network devices management functions definition
+ */
+
+#include "config.hpp"
+#include "netdev.hpp"
+#include "netlink/netlink-message.hpp"
+#include "utils.hpp"
+#include "exception.hpp"
+
+#include <logger/logger.hpp>
+
+#include <algorithm>
+#include <string>
+#include <cstdint>
+#include <cstring>
+#include <cassert>
+
+#include <net/if.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <ifaddrs.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+#include <linux/sockios.h>
+#include <linux/if_link.h>
+#include <linux/rtnetlink.h>
+
+using namespace std;
+using namespace vasum;
+using namespace vasum::netlink;
+
+namespace vasum {
+namespace netdev {
+
+namespace {
+
+template<class T>
+T make_clean()
+{
+    static_assert(std::is_pod<T>::value, "make_clean require trivial and standard-layout");
+    T value;
+    std::fill_n(reinterpret_cast<char*>(&value), sizeof(value), 0);
+    return value;
+}
+
+string getUniqueVethName()
+{
+    auto find = [](const ifaddrs* ifaddr, const string& name) -> bool {
+        for (const ifaddrs* ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
+            if (name == ifa->ifa_name) {
+                return true;
+            }
+        }
+        return false;
+    };
+
+    ifaddrs* ifaddr;
+    getifaddrs(&ifaddr);
+    string newName;
+    int i = 0;
+    do {
+        newName = "veth0" + to_string(++i);
+    } while (find(ifaddr, newName));
+
+    freeifaddrs(ifaddr);
+    return newName;
+}
+
+uint32_t getInterfaceIndex(const string& name) {
+    uint32_t index = if_nametoindex(name.c_str());
+    if (!index) {
+        LOGE("Can't get " << name << " interface index (" << getSystemErrorMessage() << ")");
+        throw ZoneOperationException("Can't find interface");
+    }
+    return index;
+}
+
+void validateNetdevName(const string& name)
+{
+    if (name.size() <= 1 || name.size() >= IFNAMSIZ) {
+        throw ZoneOperationException("Invalid netdev name format");
+    }
+}
+
+void createPipedNetdev(const string& netdev1, const string& netdev2)
+{
+    validateNetdevName(netdev1);
+    validateNetdevName(netdev2);
+
+    NetlinkMessage nlm(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK);
+    ifinfomsg infoPeer = make_clean<ifinfomsg>();
+    infoPeer.ifi_family = AF_UNSPEC;
+    infoPeer.ifi_change = 0xFFFFFFFF;
+    nlm.put(infoPeer)
+        .beginNested(IFLA_LINKINFO)
+            .put(IFLA_INFO_KIND, "veth")
+            .beginNested(IFLA_INFO_DATA)
+                .beginNested(VETH_INFO_PEER)
+                    .put(infoPeer)
+                    .put(IFLA_IFNAME, netdev2)
+                .endNested()
+            .endNested()
+        .endNested()
+        .put(IFLA_IFNAME, netdev1);
+    send(nlm);
+}
+
+void attachToBridge(const string& bridge, const string& netdev)
+{
+    validateNetdevName(bridge);
+    validateNetdevName(netdev);
+
+    uint32_t index = getInterfaceIndex(netdev);
+    int fd = socket(AF_LOCAL, SOCK_STREAM, 0);
+    if (fd < 0) {
+        LOGE("Can't open socket (" << getSystemErrorMessage() << ")");
+        throw ZoneOperationException("Can't attach to bridge");
+    }
+
+    struct ifreq ifr = make_clean<ifreq>();
+    strncpy(ifr.ifr_name, bridge.c_str(), IFNAMSIZ);
+    ifr.ifr_ifindex = index;
+    int err = ioctl(fd, SIOCBRADDIF, &ifr);
+    if (err < 0) {
+        int error = errno;
+        //TODO: Close can be interrupted. Move util functions from ipc
+        ::close(fd);
+        LOGE("Can't attach to bridge (" + getSystemErrorMessage(error) + ")");
+        throw ZoneOperationException("Can't attach to bridge");
+    }
+    close(fd);
+}
+
+int setFlags(const string& name, uint32_t mask, uint32_t flags)
+{
+    uint32_t index = getInterfaceIndex(name);
+    NetlinkMessage nlm(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_ACK);
+    ifinfomsg infoPeer = make_clean<ifinfomsg>();
+    infoPeer.ifi_family = AF_UNSPEC;
+    infoPeer.ifi_index = index;
+    infoPeer.ifi_flags = flags;
+    // since kernel v2.6.22 ifi_change is used to change only selected flags;
+    infoPeer.ifi_change = mask;
+    nlm.put(infoPeer);
+    send(nlm);
+    return 0;
+}
+
+void up(const string& netdev)
+{
+    setFlags(netdev, IFF_UP, IFF_UP);
+}
+
+void moveToNS(const string& netdev, pid_t pid)
+{
+    uint32_t index = getInterfaceIndex(netdev);
+    NetlinkMessage nlm(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_ACK);
+    ifinfomsg infopeer = make_clean<ifinfomsg>();
+    infopeer.ifi_family = AF_UNSPEC;
+    infopeer.ifi_index = index;
+    nlm.put(infopeer)
+        .put(IFLA_NET_NS_PID, pid);
+    send(nlm);
+}
+
+void createMacvlan(const string& master, const string& slave, const macvlan_mode& mode)
+{
+    validateNetdevName(master);
+    validateNetdevName(slave);
+
+    uint32_t index = getInterfaceIndex(master);
+    NetlinkMessage nlm(RTM_NEWLINK, NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK);
+    ifinfomsg infopeer = make_clean<ifinfomsg>();
+    infopeer.ifi_family = AF_UNSPEC;
+    infopeer.ifi_change = 0xFFFFFFFF;
+    nlm.put(infopeer)
+        .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)
+        .put(IFLA_IFNAME, slave);
+    send(nlm);
+}
+
+} // namespace
+
+void createVeth(const pid_t& nsPid, const string& nsDev, const string& hostDev)
+{
+    string hostVeth = getUniqueVethName();
+    LOGT("Creating veth: bridge: " << hostDev << ", port: " << hostVeth << ", zone: " << nsDev);
+    createPipedNetdev(nsDev, hostVeth);
+    //TODO: clean up if following instructions fail
+    attachToBridge(hostDev, hostVeth);
+    up(hostVeth);
+    moveToNS(nsDev, nsPid);
+}
+
+void createMacvlan(const pid_t& nsPid,
+                   const string& nsDev,
+                   const string& hostDev,
+                   const macvlan_mode& mode)
+{
+    LOGT("Creating macvlan: host: " << hostDev << ", zone: " << nsDev << ", mode: " << mode);
+    createMacvlan(hostDev, nsDev, mode);
+    //TODO: clean up if following instructions fail
+    up(nsDev);
+    moveToNS(nsDev, nsPid);
+}
+
+void movePhys(const pid_t& nsPid, const string& devId)
+{
+    LOGT("Creating phys: dev: " << devId);
+    moveToNS(devId, nsPid);
+}
+
+} //namespace netdev
+} //namespace vasum
+
diff --git a/server/netdev.hpp b/server/netdev.hpp
new file mode 100644 (file)
index 0000000..de761ca
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ *  Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Mateusz Malicki <m.malicki2@samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author  Mateusz Malicki (m.malicki2@samsung.com)
+ * @brief   Network devices management functions declaration
+ */
+
+#ifndef SERVER_NETDEV_HPP
+#define SERVER_NETDEV_HPP
+
+#include <string>
+#include <linux/if_link.h>
+#include <sys/types.h>
+
+namespace vasum {
+namespace netdev {
+
+void createVeth(const pid_t& nsPid, const std::string& nsDev, const std::string& hostDev);
+void createMacvlan(const pid_t& nsPid,
+                   const std::string& nsDev,
+                   const std::string& hostDev,
+                   const macvlan_mode& mode);
+void movePhys(const pid_t& nsPid, const std::string& devId);
+
+} //namespace netdev
+} //namespace vasum
+
+#endif // SERVER_NETDEV_HPP
index c5e994d..5a4adfa 100644 (file)
@@ -26,6 +26,7 @@
 
 #include "zone-admin.hpp"
 #include "exception.hpp"
+#include "netdev.hpp"
 
 #include "logger/logger.hpp"
 #include "utils/paths.hpp"
@@ -270,22 +271,22 @@ std::int64_t ZoneAdmin::getSchedulerQuota()
     return std::stoll(ret);
 }
 
-void ZoneAdmin::createNetdevVeth(const std::string& /* zoneDev */,
-                                 const std::string& /* hostDev */)
+void ZoneAdmin::createNetdevVeth(const std::string& zoneDev,
+                                 const std::string& hostDev)
 {
-    throw ZoneOperationException("Not implemented");
+    netdev::createVeth(mZone.getInitPid(), zoneDev, hostDev);
 }
 
-void ZoneAdmin::createNetdevMacvlan(const std::string& /* zoneDev */,
-                                    const std::string& /* hostDev */,
-                                    const uint32_t& /* mode */)
+void ZoneAdmin::createNetdevMacvlan(const std::string& zoneDev,
+                                    const std::string& hostDev,
+                                    const uint32_t& mode)
 {
-    throw ZoneOperationException("Not implemented");
+    netdev::createMacvlan(mZone.getInitPid(), zoneDev, hostDev, static_cast<macvlan_mode>(mode));
 }
 
-void ZoneAdmin::moveNetdev(const std::string& /* devId */)
+void ZoneAdmin::moveNetdev(const std::string& devId)
 {
-    throw ZoneOperationException("Not implemented");
+    netdev::movePhys(mZone.getInitPid(), devId);
 }
 
 } // namespace vasum