#include <logger/logger.hpp>
+#include <algorithm>
#include <memory>
#include <cstring>
+#include <atomic>
#include <cassert>
#include <linux/netlink.h>
#include <sys/socket.h>
#include <unistd.h>
-#ifndef PAGE_SIZE
-#define PAGE_SIZE 4096
-#endif
-
namespace {
-const int NLMSG_GOOD_SIZE = 2*PAGE_SIZE;
-inline rtattr* NLMSG_TAIL(nlmsghdr* nmsg)
+inline const rtattr* asAttr(const void* data) { return reinterpret_cast<const rtattr*>(data); }
+inline const nlmsghdr* asHdr(const void* data) { return reinterpret_cast<const nlmsghdr*>(data); }
+inline rtattr* asAttr(void* data) { return reinterpret_cast<rtattr*>(data); }
+inline nlmsghdr* asHdr(void* data) { return reinterpret_cast<nlmsghdr*>(data); }
+inline char* NLMSG_TAIL(nlmsghdr* nmsg)
{
- return reinterpret_cast<rtattr*>(reinterpret_cast<char*>(nmsg) + NLMSG_ALIGN(nmsg->nlmsg_len));
+ return reinterpret_cast<char*>(nmsg) + NLMSG_ALIGN(nmsg->nlmsg_len);
}
} // namespace
namespace vasum {
namespace netlink {
+NetlinkResponse send(const NetlinkMessage& msg)
+{
+ return send(msg, 0);
+}
+
NetlinkMessage::NetlinkMessage(uint16_t type, uint16_t flags)
{
- static uint32_t seq = 0;
- mNlmsg.resize(NLMSG_GOOD_SIZE, 0);
+ static std::atomic<uint32_t> seq(0);
+ mNlmsg.resize(NLMSG_HDRLEN, 0);
hdr().nlmsg_len = NLMSG_HDRLEN;
hdr().nlmsg_flags = flags | NLM_F_ACK;
hdr().nlmsg_type = type;
NetlinkMessage& NetlinkMessage::beginNested(int ifla)
{
- struct rtattr *nest = NLMSG_TAIL(&hdr());
+ auto offset = std::distance(reinterpret_cast<char*>(&hdr()), NLMSG_TAIL(&hdr()));
put(ifla, NULL, 0);
- mNested.push(nest);
+ mNested.push(offset);
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())));
+ rtattr* nest = asAttr(reinterpret_cast<char*>(&hdr()) + mNested.top());
+ nest->rta_len = std::distance(reinterpret_cast<char*>(nest), NLMSG_TAIL(&hdr()));
mNested.pop();
return *this;
}
int newLen = NLMSG_ALIGN(hdr().nlmsg_len) + RTA_ALIGN(rtalen);
setMinCapacity(newLen);
- rta = NLMSG_TAIL(&hdr());
+ rta = asAttr(NLMSG_TAIL(&hdr()));
rta->rta_type = ifla;
rta->rta_len = rtalen;
memcpy(RTA_DATA(rta), data, len);
}
nlmsghdr& NetlinkMessage::hdr() {
- return *reinterpret_cast<nlmsghdr*>(mNlmsg.data());
+ return *asHdr(mNlmsg.data());
}
const nlmsghdr& NetlinkMessage::hdr() const {
- return *reinterpret_cast<const nlmsghdr*>(mNlmsg.data());
+ return *asHdr(mNlmsg.data());
}
void NetlinkMessage::setMinCapacity(unsigned int size)
}
}
-void send(const NetlinkMessage& msg)
+NetlinkResponse::NetlinkResponse(std::unique_ptr<std::vector<char>>&& message)
+ : mNlmsg(std::move(message))
+ , mNlmsgHdr(asHdr(mNlmsg.get()->data()))
+ , mPosition(NLMSG_HDRLEN)
{
- //TODO: Handle messages with responses
- assert(msg.hdr().nlmsg_flags & NLM_F_ACK);
+}
+
+bool NetlinkResponse::hasMessage() const
+{
+ unsigned int tail = size() - getHdrPosition();
+ bool hasHeader = NLMSG_OK(mNlmsgHdr, tail);
+ if (!hasHeader) {
+ return false;
+ }
+ //Check if isn't ACK message
+ return NLMSG_PAYLOAD(mNlmsgHdr,0) > sizeof(uint32_t);
+}
+
+int NetlinkResponse::getMessageType() const
+{
+ return mNlmsgHdr->nlmsg_type;
+}
+
+void NetlinkResponse::fetchNextMessage()
+{
+ if (mNlmsgHdr->nlmsg_type == NLMSG_DONE) {
+ throw VasumException("There is no next message");
+ }
+ int tail = size() - mPosition;
+ mNlmsgHdr = NLMSG_NEXT(mNlmsgHdr, tail);
+ mPosition = getHdrPosition() + NLMSG_HDRLEN;
+}
+
+bool NetlinkResponse::hasAttribute() const
+{
+ assert(mPosition >= getHdrPosition());
+ int tail = mNlmsgHdr->nlmsg_len - (mPosition - getHdrPosition());
+ return RTA_OK(asAttr(get(0)), tail);
+}
- 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;
+bool NetlinkResponse::isNestedAttribute() const
+{
+ return asAttr(get(RTA_LENGTH(0)))->rta_len == RTA_LENGTH(0);
+}
+
+void NetlinkResponse::skipAttribute()
+{
+ const rtattr *rta = asAttr(get(RTA_LENGTH(0)));
+ if (size() < mPosition + RTA_ALIGN(rta->rta_len)) {
+ LOGE("Skipping out of buffer:"
+ << " to: " << mPosition + RTA_ALIGN(rta->rta_len)
+ << ", buf size: " << size());
+ throw VasumException("Skipping out of buffer");
+ }
+ seek(RTA_ALIGN(rta->rta_len));
+}
+
+NetlinkResponse& NetlinkResponse::openNested(int ifla)
+{
+ const rtattr *rta = asAttr(get(RTA_LENGTH(0)));
+ if (rta->rta_type == ifla) {
+ LOGE("Wrong attribute type, expected: " << ifla << ", got: " << rta->rta_type);
+ throw VasumException("Wrong attribute type");
+ }
+ int pos = mPosition;
+ seek(RTA_LENGTH(0));
+ mNested.push(pos);
+ return *this;
+}
+
+NetlinkResponse& NetlinkResponse::closeNested()
+{
+ assert(!mNested.empty());
+ int pos = mNested.top();
+ const rtattr *rta = asAttr(mNlmsg->data() + pos);
+ if (rta->rta_len != mPosition - pos) {
+ LOGE("There is no nested attribute end. Did you read all attributes (read: "
+ << mPosition - pos << ", length: " << rta->rta_len);
+ throw VasumException("There is no nested attribute end");
+ }
+ mNested.pop();
+ mPosition = pos;
+ return *this;
+}
+NetlinkResponse& NetlinkResponse::fetch(int ifla, std::string& value, int maxSize)
+{
+ value = std::string(get(ifla, maxSize));
+ skipAttribute();
+ return *this;
+}
+
+const char* NetlinkResponse::get(int ifla, int len) const
+{
+ const rtattr *rta = asAttr(get(RTA_LENGTH(len < 0 ? 0 : len)));
+ if (rta->rta_type != ifla) {
+ LOGE("Wrong attribute type, expected:" << ifla << ", got: " << rta->rta_type);
+ throw VasumException("Wrong attribute type");
+ }
+ if (len >= 0 && rta->rta_len != RTA_LENGTH(len)) {
+ LOGE("Wrong attribute length, expected: " << rta->rta_len + ", got " << len);
+ throw VasumException("Wrong attribute length");
+ }
+ return reinterpret_cast<const char*>(RTA_DATA(get(rta->rta_len)));
+}
+
+const char* NetlinkResponse::get(int len) const
+{
+ if (size() < mPosition + len) {
+ LOGE("Read out of buffer:"
+ << " from: " << mPosition + len
+ << ", buf size: " << size());
+ throw VasumException("Read out of buffer");
+ }
+ return mNlmsg->data() + mPosition;
+}
+
+NetlinkResponse& NetlinkResponse::fetch(int ifla, char* data, int len)
+{
+ std::copy_n(get(ifla, len), len, data);
+ skipAttribute();
+ return *this;
+}
+
+NetlinkResponse& NetlinkResponse::fetch(char* data, int len)
+{
+ std::copy_n(get(len), len, data);
+ seek(len);
+ return *this;
+}
+
+int NetlinkResponse::getAttributeType() const
+{
+ return asAttr(get(RTA_LENGTH(0)))->rta_type;
+}
+
+NetlinkResponse& NetlinkResponse::seek(int len)
+{
+ if (size() < mPosition + len) {
+ throw VasumException("Skipping out of buffer");
+ }
+ mPosition += len;
+ return *this;
+}
+
+int NetlinkResponse::size() const
+{
+ return mNlmsg->size();
+}
+
+inline int NetlinkResponse::getHdrPosition() const
+{
+ return std::distance(reinterpret_cast<const char*>(mNlmsg->data()),
+ reinterpret_cast<const char*>(mNlmsgHdr));
+}
+
+NetlinkResponse send(const NetlinkMessage& msg, int pid)
+{
+ assert(msg.hdr().nlmsg_flags & NLM_F_ACK);
+
+ std::unique_ptr<std::vector<char>> data;
Netlink nl;
- nl.open();
+ nl.open(pid);
try {
nl.send(&msg.hdr());
- //Receive ACK Netlink Message
- do {
- nl.rcv(answer);
- } while (answer->nlmsg_type == NLMSG_NOOP);
+ data = nl.rcv(msg.hdr().nlmsg_seq);
} 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) + ")");
- }
+ return NetlinkResponse(std::move(data));
}
} // namespace netlink
#ifndef COMMON_NETLINK_NETLINK_MESSAGE_HPP
#define COMMON_NETLINK_NETLINK_MESSAGE_HPP
+#include <memory>
#include <string>
#include <vector>
#include <stack>
namespace vasum {
namespace netlink {
+class NetlinkResponse;
+class NetlinkMessage;
+
/**
* NetlinkMessage is used to creatie a netlink messages
*/
* Send netlink message
*
* It is not thread safe
+ * @param msg Netlink message
+ * @param pid Process id which describes network namespace
*/
- friend void send(const NetlinkMessage& msg);
+ friend NetlinkResponse send(const NetlinkMessage& msg, int pid);
private:
std::vector<char> mNlmsg;
- std::stack<void*> mNested;
+ std::stack<int> 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);
+};
+
+/**
+ * NetlinkResponse is used to read netlink messages
+ */
+class NetlinkResponse {
+public:
+ /**
+ * Check if theres is next message in netlink response
+ */
+ bool hasMessage() const;
+
+ /**
+ * Fetch next message
+ */
+ void fetchNextMessage();
+ /**
+ * Get message type
+ */
+ int getMessageType() const;
+ /**
+ * Check if there is any attribute in message
+ */
+ bool hasAttribute() const;
+
+ /**
+ * Check if current attribute is nested
+ */
+ bool isNestedAttribute() const;
+
+ /**
+ * Skip attribute
+ */
+ void skipAttribute();
+
+ /**
+ * Start reading nested attribute
+ */
+ NetlinkResponse& openNested(int ifla);
+
+ /**
+ * End reading nested attribute
+ */
+ NetlinkResponse& closeNested();
+
+ ///@{
+ /**
+ * Fetch attribute
+ */
+ NetlinkResponse& fetch(int ifla, std::string& value, int maxSize = std::string::npos);
+ template<class T>
+ NetlinkResponse& fetch(int ifla, T& value);
+ ///@}
+
+ /**
+ * Get attributie type
+ **/
+ int getAttributeType() const;
+
+ /**
+ * Fetch data of type T
+ */
+ template<class T>
+ NetlinkResponse& fetch(T& value);
+
+ /**
+ * Skip data of type T
+ */
+ template<class T>
+ NetlinkResponse& skip();
+
+ /**
+ * Send netlink message
+ *
+ * It is not thread safe
+ * @param msg Netlink message
+ * @param pid Process id which describes network namespace
+ */
+ friend NetlinkResponse send(const NetlinkMessage& msg, int pid);
+private:
+ NetlinkResponse(std::unique_ptr<std::vector<char>>&& message);
+
+ std::unique_ptr<std::vector<char>> mNlmsg;
+ std::stack<int> mNested;
+ nlmsghdr* mNlmsgHdr;
+ int mPosition;
+
+ const char* get(int ifla, int iflasize) const;
+ const char* get(int size = 0) const;
+ NetlinkResponse& fetch(int ifla, char* data, int len);
+ NetlinkResponse& fetch(char* data, int len);
+ NetlinkResponse& seek(int len);
+ int size() const;
+ int getHdrPosition() const;
};
+/**
+ * Send netlink message
+ *
+ * It is not thread safe
+ */
+NetlinkResponse send(const NetlinkMessage& msg);
+
template<class T>
NetlinkMessage& NetlinkMessage::put(int ifla, const T& value)
{
return put(&value, sizeof(value));
}
+template<class T>
+NetlinkResponse& NetlinkResponse::fetch(int ifla, T& value)
+{
+ static_assert(std::is_pod<T>::value, "Require trivial and standard-layout");
+ return fetch(ifla, reinterpret_cast<char*>(&value), sizeof(value));
+}
+
+template<class T>
+NetlinkResponse& NetlinkResponse::fetch(T& value)
+{
+ static_assert(std::is_pod<T>::value, "Require trivial and standard-layout structure");
+ return fetch(reinterpret_cast<char*>(&value), sizeof(value));
+}
+
+template<class T>
+NetlinkResponse& NetlinkResponse::skip()
+{
+ static_assert(std::is_pod<T>::value, "Require trivial and standard-layout structure");
+ return seek(sizeof(T));
+}
+
} // namespace netlink
} // namespace vasum
#include "netlink.hpp"
#include "utils.hpp"
#include "base-exception.hpp"
+#include "utils/make-clean.hpp"
+#include "utils/environment.hpp"
#include <logger/logger.hpp>
#include <cassert>
#include <unistd.h>
#include <linux/netlink.h>
-namespace vasum {
+#ifndef PAGE_SIZE
+#define PAGE_SIZE 4096
+#endif
+
+using namespace vasum;
namespace {
-template<class T>
-T make_clean()
+const int NLMSG_RCV_GOOD_SIZE = 2*PAGE_SIZE;
+
+int vsm_recvmsg(int fd, struct msghdr *msg, int flags)
{
- 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;
+ int ret = recvmsg(fd, msg, flags);
+ if (ret < 0) {
+ LOGE("Can't receive message: " + getSystemErrorMessage());
+ } else if (ret == 0 && msg->msg_iov && msg->msg_iov->iov_len > 0) {
+ LOGE("Peer has performed an orderly shutdown");
+ } else if (msg->msg_flags & MSG_TRUNC) {
+ LOGE("Can't receive message: " + getSystemErrorMessage(EMSGSIZE));
+ } else if (msg->msg_flags & MSG_ERRQUEUE) {
+ LOGE("No data was received but an extended error");
+ } else if (msg->msg_flags & MSG_OOB) {
+ LOGE("Internal error (expedited or out-of-band data were received)");
+ } else if (msg->msg_flags & MSG_CTRUNC) {
+ LOGE("Some control data were discarded");
+ } else if (msg->msg_flags & MSG_EOR) {
+ LOGE("End-of-record");
+ } else {
+ // All ok
+ return ret;
+ }
+ throw VasumException("Can't receive netlink message");
+}
+
+void vsm_sendmsg(int fd, const struct msghdr *msg, int flags)
+{
+ int ret = sendmsg(fd, msg, flags);
+ if (ret < 0) {
+ LOGE("Can't send message: " << getSystemErrorMessage());
+ throw VasumException("Can't send netlink message");
+ }
}
} // namespace
+namespace vasum {
+namespace netlink {
+
Netlink::Netlink() : mFd(-1)
{
}
close();
}
-void Netlink::open()
+void Netlink::open(int netNsPid)
{
+ auto fdFactory = []{ return socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); };
+
assert(mFd == -1);
- mFd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (netNsPid == 0 || netNsPid == getpid()) {
+ mFd = fdFactory();
+ if (mFd == -1) {
+ LOGE("Can't open socket: " << getSystemErrorMessage());
+ }
+ } else {
+ mFd = utils::passNemaspacedFd(netNsPid, CLONE_NEWNET, fdFactory);
+ }
if (mFd == -1) {
- LOGE("Can't open socket (" << getSystemErrorMessage() << ")");
throw VasumException("Can't open netlink connection");
}
- sockaddr_nl local = make_clean<sockaddr_nl>();
+ sockaddr_nl local = utils::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) << ")");
+ LOGE("Can't bind to socket: " << getSystemErrorMessage(err));
throw VasumException("Can't set up netlink connection");
}
}
}
}
-void Netlink::send(const nlmsghdr *nlmsg)
+unsigned int Netlink::send(const void *nlmsg)
{
- msghdr msg = make_clean<msghdr>();
- sockaddr_nl nladdr = make_clean<sockaddr_nl>();
- iovec iov = make_clean<iovec>();
+ msghdr msg = utils::make_clean<msghdr>();
+ sockaddr_nl nladdr = utils::make_clean<sockaddr_nl>();
+ iovec iov = utils::make_clean<iovec>();
- iov.iov_base = (void *)nlmsg;
- iov.iov_len = nlmsg->nlmsg_len;
+ iov.iov_base = const_cast<void*>(nlmsg);
+ iov.iov_len = reinterpret_cast<const nlmsghdr*>(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");
- }
+ vsm_sendmsg(mFd, &msg, 0);
+ return reinterpret_cast<const nlmsghdr*>(nlmsg)->nlmsg_seq;
}
-int Netlink::rcv(nlmsghdr *answer)
+std::unique_ptr<std::vector<char>> Netlink::rcv(unsigned int nlmsgSeq)
{
- //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>();
+ std::unique_ptr<std::vector<char>> buf(new std::vector<char>());
+
+ msghdr msg = utils::make_clean<msghdr>();
+ sockaddr_nl nladdr = utils::make_clean<sockaddr_nl>();
+ iovec iov = utils::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;
+ nlmsghdr* answer;
+ nlmsghdr* lastOk = NULL;
+ size_t offset = 0;
+ do {
+ buf->resize(offset + NLMSG_RCV_GOOD_SIZE);
+ answer = reinterpret_cast<nlmsghdr*>(buf->data() + offset);
+ iov.iov_base = answer;
+ iov.iov_len = buf->size() - offset;
+ unsigned int ret = vsm_recvmsg(mFd, &msg, 0);
+ for (unsigned int len = ret; NLMSG_OK(answer, len); answer = NLMSG_NEXT(answer, len)) {
+ lastOk = answer;
+ if (answer->nlmsg_type == NLMSG_ERROR) {
+ // It is NACK/ACK message
+ nlmsgerr *err = reinterpret_cast<nlmsgerr*>(NLMSG_DATA(answer));
+ if (answer->nlmsg_seq != nlmsgSeq) {
+ throw VasumException("Sending failed: answer message was mismatched");
+ }
+ if (err->error) {
+ throw VasumException("Sending failed: " + getSystemErrorMessage(-err->error));
+ }
+ } else if (answer->nlmsg_type == NLMSG_OVERRUN) {
+ throw VasumException("Sending failed: data lost");
+ }
+ }
+ if (lastOk == NULL) {
+ LOGE("Something went terribly wrong. Check vsm_recvmsg function");
+ throw VasumException("Can't receive data from system");
+ }
+ offset += NLMSG_ALIGN(ret);
+ } while (lastOk->nlmsg_type != NLMSG_DONE && lastOk->nlmsg_flags & NLM_F_MULTI);
+
+ buf->resize(offset);
+ return buf;
}
+} //namespace netlink
} //namespace vasum
#ifndef COMMON_NETLINK_NETLINK_HPP
#define COMMON_NETLINK_NETLINK_HPP
-#include <linux/netlink.h>
+#include <memory>
+#include <vector>
namespace vasum {
+namespace netlink {
/**
* Netlink class is responsible for communicating
/**
* Open connnection
+ *
+ * @param netNsPid pid which defines net namespace
*/
- void open();
+ void open(int netNsPid = 0);
/**
* Close connection
* different instances at the same time
*
* @param nlmsg pointer to message
+ * @return sequence number
*/
- void send(const nlmsghdr *nlmsg);
+ unsigned int send(const void* 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
+ * @param nlmsgSeq sequence number
+ * @return received data
*/
- int rcv(nlmsghdr *answer);
+ std::unique_ptr<std::vector<char>> rcv(unsigned int nlmsgSeq);
private:
int mFd;
};
+} // namesapce netlink
} // namespace vasum
#endif /* COMMON_NETLINK_NETLINK_HPP */
#include "config.hpp"
#include "netdev.hpp"
#include "netlink/netlink-message.hpp"
+#include "utils/make-clean.hpp"
#include "utils.hpp"
#include "exception.hpp"
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 {
validateNetdevName(netdev2);
NetlinkMessage nlm(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK);
- ifinfomsg infoPeer = make_clean<ifinfomsg>();
+ ifinfomsg infoPeer = utils::make_clean<ifinfomsg>();
infoPeer.ifi_family = AF_UNSPEC;
infoPeer.ifi_change = 0xFFFFFFFF;
nlm.put(infoPeer)
throw ZoneOperationException("Can't attach to bridge");
}
- struct ifreq ifr = make_clean<ifreq>();
+ struct ifreq ifr = utils::make_clean<ifreq>();
strncpy(ifr.ifr_name, bridge.c_str(), IFNAMSIZ);
ifr.ifr_ifindex = index;
int err = ioctl(fd, SIOCBRADDIF, &ifr);
{
uint32_t index = getInterfaceIndex(name);
NetlinkMessage nlm(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_ACK);
- ifinfomsg infoPeer = make_clean<ifinfomsg>();
+ ifinfomsg infoPeer = utils::make_clean<ifinfomsg>();
infoPeer.ifi_family = AF_UNSPEC;
infoPeer.ifi_index = index;
infoPeer.ifi_flags = flags;
{
uint32_t index = getInterfaceIndex(netdev);
NetlinkMessage nlm(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_ACK);
- ifinfomsg infopeer = make_clean<ifinfomsg>();
+ ifinfomsg infopeer = utils::make_clean<ifinfomsg>();
infopeer.ifi_family = AF_UNSPEC;
infopeer.ifi_index = index;
nlm.put(infopeer)
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>();
+ ifinfomsg infopeer = utils::make_clean<ifinfomsg>();
infopeer.ifi_family = AF_UNSPEC;
infopeer.ifi_change = 0xFFFFFFFF;
nlm.put(infopeer)
moveToNS(devId, nsPid);
}
+std::vector<std::string> listNetdev(const pid_t& nsPid)
+{
+ 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);
+ NetlinkResponse response = send(nlm, nsPid);
+ std::vector<std::string> interfaces;
+ while (response.hasMessage()) {
+ std::string ifName;
+ response.skip<ifinfomsg>();
+ response.fetch(IFLA_IFNAME, ifName);
+ interfaces.push_back(ifName);
+ response.fetchNextMessage();
+ }
+ return interfaces;
+}
+
} //namespace netdev
} //namespace vasum
#define SERVER_NETDEV_HPP
#include <string>
+#include <vector>
#include <linux/if_link.h>
#include <sys/types.h>
const std::string& hostDev,
const macvlan_mode& mode);
void movePhys(const pid_t& nsPid, const std::string& devId);
+std::vector<std::string> listNetdev(const pid_t& nsPid);
} //namespace netdev
} //namespace vasum
std::vector<std::string> ZoneAdmin::getNetdevList()
{
- throw ZoneOperationException("Not implemented");
+ return netdev::listNetdev(mZone.getInitPid());
}
} // namespace vasum
#include "utils/glib-loop.hpp"
#include "utils/scoped-dir.hpp"
#include "config/exception.hpp"
+#include "netdev.hpp"
#include <memory>
#include <string>
#include <thread>
#include <chrono>
-
using namespace vasum;
using namespace config;
// TODO: DbusReconnectionTest
+BOOST_AUTO_TEST_CASE(ListNetdevTest)
+{
+ typedef std::vector<std::string> NetdevList;
+
+ auto c = create(TEST_CONFIG_PATH);
+ c->start();
+ ensureStarted();
+ // Depending on the kernel configuration there can be lots of interfaces (f.e. sit0, ip6tnl0)
+ NetdevList netdevs = c->getNetdevList();
+ // Check if there is mandatory loopback interface
+ BOOST_CHECK(find(netdevs.begin(), netdevs.end(), "lo") != netdevs.end());
+ NetdevList hostNetdevs = netdev::listNetdev(0);
+ // Check if we get interfaces from zone net namespace
+ BOOST_CHECK(hostNetdevs != netdevs);
+
+ c->stop(false);
+}
BOOST_AUTO_TEST_SUITE_END()