[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
#include <sys/socket.h>
#include <linux/netlink.h>
+//FIXME remove from namespace vasum
namespace vasum {
namespace netlink {
#include <memory>
#include <vector>
+//FIXME remove from namespace vasum
namespace vasum {
namespace netlink {
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})
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);
}
}
#include "lxcpp/commands/command.hpp"
#include "lxcpp/network-config.hpp"
+#include "lxcpp/container.hpp"
#include <sys/types.h>
* 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
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)
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) {
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;
break;
}
}
+ addrs = ni.getInetAddressList();
return NetworkInterfaceInfo{ifname, ni.status(), macaddr, mtu, flags, addrs};
}
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
#include "lxcpp/container-config.hpp"
#include "lxcpp/container.hpp"
#include "lxcpp/namespace.hpp"
-#include "lxcpp/network.hpp"
namespace lxcpp {
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);
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;
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;
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
*/
#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
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
{
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);
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(),
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)
);
if (it == mInterfaces.end()) {
- std::string msg = "No such interface";
+ const std::string msg = "No such interface";
LOGE(msg);
throw NetworkException(msg);
}
#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)
{
}
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
#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:
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);
}
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);
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);
}
// 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
break;
}
}
- NetworkInterface::convertInetAddr2Attr(a, attr);
- attrs.push_back(attr);
+ addrs.push_back(a);
}
response.fetchNextMessage();
}
} // 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);
}
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);
}
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()) {
/*
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);
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
#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,
MTU,
LINK,
TXQLEN,
- IPV4,
- IPV6,
};
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;
}
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
#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
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()
#include <thread>
#include <chrono>
#include <sys/socket.h>
-#include <linux/in6.h>
-#include <linux/if_bridge.h>
#include <linux/if.h>
using namespace utils;