Skip to content

Commit 65572db

Browse files
Veth library:
This commit extends the functionality of the netlink class, and it adds the methods get_name and get_fd to the ns class. This commit adds a veth library, able to do: - create veth - remove veth - move veth into a namespace - change the MAC address of the veth (inside and outside the namespace) - set the IP address of the veth (inside and outside the namespace) Signed-off-by: francescomessina <francescomessina92@hotmail.com>
1 parent 6a14802 commit 65572db

7 files changed

Lines changed: 475 additions & 0 deletions

File tree

src/polycubed/src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ set(polycubed_sources
5959
id_generator.cpp
6060
utils/extiface_info.cpp
6161
utils/ns.cpp
62+
utils/veth.cpp
6263
utils/netlink.cpp
6364
utils/utils.cpp
6465
${server_sources}

src/polycubed/src/utils/netlink.cpp

Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,29 @@
2323
#include <arpa/inet.h>
2424
#include <sstream>
2525
#include <sys/socket.h>
26+
#include <netinet/ether.h>
2627

2728
#include "../exceptions.h"
2829

2930
#ifndef SOL_NETLINK
3031
#define SOL_NETLINK 270
3132
#endif
3233

34+
/*useful for memory paging*/
35+
#define SIZE_ALIGN 8192
36+
#define NLMSG_TAIL(nmsg) \
37+
((struct rtattr *) (((char *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
38+
39+
struct nl_req {
40+
struct nlmsghdr nlmsg;
41+
struct ifinfomsg ifinfomsg;
42+
};
43+
44+
struct nl_ipreq {
45+
struct nlmsghdr nlmsg;
46+
struct ifaddrmsg ifaddrmsg;
47+
};
48+
3349
namespace polycube {
3450
namespace polycubed {
3551

@@ -616,5 +632,220 @@ void Netlink::detach_from_xdp(const std::string &iface, int attach_flags) {
616632
logger->debug("XDP program detached from port: {0}", iface);
617633
}
618634

635+
struct nlmsghdr* Netlink::netlink_alloc() {
636+
size_t len = NLMSG_ALIGN(SIZE_ALIGN) + NLMSG_ALIGN(sizeof(struct nlmsghdr *));
637+
struct nlmsghdr *nlmsg = (struct nlmsghdr *) malloc(len);
638+
memset(nlmsg, 0, len);
639+
640+
struct nl_req *unr = (struct nl_req *)nlmsg;
641+
unr->ifinfomsg.ifi_family = AF_UNSPEC;
642+
nlmsg->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
643+
nlmsg->nlmsg_type = RTM_NEWLINK;
644+
// NLM_F_REQUEST Must be set on all request messages
645+
// NLM_F_ACK Request for an acknowledgment on success
646+
nlmsg->nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
647+
648+
return nlmsg;
649+
}
650+
651+
struct nlmsghdr* Netlink::netlink_ip_alloc() {
652+
size_t len = NLMSG_ALIGN(SIZE_ALIGN) + NLMSG_ALIGN(sizeof(struct nlmsghdr *));
653+
struct nlmsghdr *nlmsg = (struct nlmsghdr *) malloc(len);
654+
memset(nlmsg, 0, len);
655+
656+
struct nl_ipreq *uni = (struct nl_ipreq *)nlmsg;
657+
uni->ifaddrmsg.ifa_family = AF_INET;
658+
uni->ifaddrmsg.ifa_scope = 0;
659+
660+
nlmsg->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
661+
nlmsg->nlmsg_type = RTM_NEWADDR;
662+
// NLM_F_REQUEST Must be set on all request messages
663+
// NLM_F_ACK Request for an acknowledgment on success
664+
// NLM_F_CREATE Create object if it doesn't already exist
665+
// NLM_F_EXCL Don't replace if the object already exists
666+
nlmsg->nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK|NLM_F_CREATE|NLM_F_EXCL;
667+
668+
return nlmsg;
669+
}
670+
671+
int Netlink::netlink_nl_send(struct nlmsghdr *nlmsg) {
672+
struct sockaddr_nl nladdr;
673+
struct iovec iov = {
674+
.iov_base = (void*)nlmsg,
675+
.iov_len = nlmsg->nlmsg_len,
676+
};
677+
struct msghdr msg = {
678+
.msg_name = &nladdr,
679+
.msg_namelen = sizeof(nladdr),
680+
.msg_iov = &iov,
681+
.msg_iovlen = 1,
682+
};
683+
int nlfd;
684+
685+
memset(&nladdr, 0, sizeof(struct sockaddr_nl));
686+
nladdr.nl_family = AF_NETLINK;
687+
nladdr.nl_pid = 0;
688+
nladdr.nl_groups = 0;
689+
690+
nlfd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
691+
if (nlfd < 0) {
692+
free(nlmsg);
693+
logger->error("netlink_nl_send: Unable to open socket");
694+
throw std::runtime_error("netlink_nl_send: Unable to open socket");
695+
}
696+
697+
if (sendmsg(nlfd, &msg, 0) < 0) {
698+
free(nlmsg);
699+
close(nlfd);
700+
logger->error("netlink_nl_send: Unable to sendmsg");
701+
throw std::runtime_error("netlink_nl_send: Unable to sendmsg");
702+
}
703+
704+
/* read the reply message to check that there are no errors */
705+
if (recvmsg(nlfd, &msg, 0) < 0) {
706+
free(nlmsg);
707+
close(nlfd);
708+
logger->error("netlink_nl_send: Unable to recvmsg");
709+
throw std::runtime_error("netlink_nl_send: Unable to recvmsg");
710+
}
711+
712+
/* if there is an error return error code */
713+
if (nlmsg->nlmsg_type == NLMSG_ERROR) {
714+
struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(nlmsg);
715+
free(nlmsg);
716+
close(nlfd);
717+
return err->error;
718+
}
719+
720+
free(nlmsg);
721+
close(nlfd);
722+
return 0;
723+
}
724+
725+
void Netlink::set_iface_status(const std::string &iface, IFACE_STATUS status) {
726+
struct nlmsghdr *nlmsg = netlink_alloc();
727+
struct nl_req *unr = (struct nl_req *)nlmsg;
728+
729+
int index = get_iface_index(iface);
730+
if (index == -1) {
731+
logger->error("set_iface_status: iface {0} does not exist", iface);
732+
throw std::runtime_error("set_iface_status: iface does not exist");
733+
}
734+
735+
unr->ifinfomsg.ifi_index = index;
736+
unr->ifinfomsg.ifi_change |= IFF_UP;
737+
if (status == IFACE_STATUS::UP)
738+
unr->ifinfomsg.ifi_flags |= IFF_UP;
739+
else if (status == IFACE_STATUS::DOWN)
740+
unr->ifinfomsg.ifi_flags |= ~IFF_UP;
741+
742+
netlink_nl_send(nlmsg);
743+
}
744+
745+
void Netlink::set_iface_mac(const std::string &iface, const std::string &mac) {
746+
struct rtnl_link *link;
747+
struct rtnl_link *old_link;
748+
struct nl_sock *sk;
749+
struct nl_cache *link_cache;
750+
751+
sk = nl_socket_alloc();
752+
if (nl_connect(sk, NETLINK_ROUTE) < 0) {
753+
logger->error("set_iface_mac: Unable to open socket");
754+
throw std::runtime_error("set_iface_mac: Unable to open socket");
755+
}
756+
757+
link = rtnl_link_alloc();
758+
if (!link) {
759+
nl_close(sk);
760+
logger->error("set_iface_mac: Invalid link");
761+
throw std::runtime_error("set_iface_mac: Invalid link");
762+
}
763+
764+
rtnl_link_set_name(link, iface.c_str());
765+
766+
struct nl_addr* addr;
767+
addr = nl_addr_build(AF_LLC, ether_aton(mac.c_str()), ETH_ALEN);
768+
if (!addr) {
769+
nl_close(sk);
770+
logger->error("set_iface_mac: Invalid MAC address");
771+
throw std::runtime_error("set_iface_mac: Invalid MAC address");
772+
}
773+
rtnl_link_set_addr(link, addr);
774+
775+
if (rtnl_link_alloc_cache(sk, AF_UNSPEC, &link_cache) < 0) {
776+
nl_close(sk);
777+
logger->error("set_iface_mac: Unable to allocate cache");
778+
throw std::runtime_error("set_iface_mac: Unable to allocate cache");
779+
}
780+
781+
old_link = rtnl_link_get_by_name(link_cache, iface.c_str());
782+
if (rtnl_link_change(sk, old_link, link, 0) < 0) {
783+
nl_close(sk);
784+
logger->error("set_iface_mac: Unable to change link");
785+
throw std::runtime_error("set_iface_mac: Unable to change link");
786+
}
787+
788+
rtnl_link_put(link);
789+
nl_close(sk);
790+
}
791+
792+
void Netlink::set_iface_ip(const std::string &iface, const std::string &ip, int prefix) {
793+
struct nlmsghdr *nlmsg = netlink_ip_alloc();
794+
struct nl_ipreq *uni = (struct nl_ipreq *)nlmsg;
795+
struct rtattr *rta;
796+
struct in_addr ia;
797+
798+
int index = get_iface_index(iface);
799+
if (index == -1) {
800+
logger->error("set_iface_ip: iface {0} does not exist", iface);
801+
throw std::runtime_error("set_iface_ip: iface does not exist");
802+
}
803+
804+
uni->ifaddrmsg.ifa_index = index;
805+
uni->ifaddrmsg.ifa_prefixlen = prefix;
806+
807+
if (inet_pton(AF_INET, ip.c_str(), &ia) <= 0) {
808+
free(nlmsg);
809+
logger->error("set_iface_ip: Error in inet_pton");
810+
throw std::runtime_error("set_iface_ip: Error in inet_pton");
811+
}
812+
813+
rta = NLMSG_TAIL(nlmsg);
814+
rta->rta_type = IFA_LOCAL;
815+
rta->rta_len = RTA_LENGTH(sizeof(struct in_addr));
816+
memcpy(RTA_DATA(rta), &ia, sizeof(struct in_addr));
817+
nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta->rta_len);
818+
819+
rta = NLMSG_TAIL(nlmsg);
820+
rta->rta_type = IFA_ADDRESS;
821+
rta->rta_len = RTA_LENGTH(sizeof(struct in_addr));
822+
memcpy(RTA_DATA(rta), &ia, sizeof(struct in_addr));
823+
nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta->rta_len);
824+
825+
netlink_nl_send(nlmsg);
826+
}
827+
828+
void Netlink::move_iface_into_ns(const std::string &iface, int fd) {
829+
struct nlmsghdr *nlmsg = netlink_alloc();
830+
struct nl_req *unr = (struct nl_req *)nlmsg;
831+
struct rtattr *rta;
832+
833+
int index = get_iface_index(iface);
834+
if (index == -1) {
835+
logger->error("move_iface_into_ns: iface {0} does not exist", iface);
836+
throw std::runtime_error("move_iface_into_ns: iface does not exist");
837+
}
838+
839+
unr->ifinfomsg.ifi_index = index;
840+
rta = NLMSG_TAIL(nlmsg);
841+
rta->rta_type = IFLA_NET_NS_FD;
842+
rta->rta_len = RTA_LENGTH(sizeof(int));
843+
844+
memcpy(RTA_DATA(rta), &fd, sizeof(pid_t));
845+
nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta->rta_len);
846+
847+
netlink_nl_send(nlmsg);
848+
}
849+
619850
} // namespace polycubed
620851
} // namespace polycube

src/polycubed/src/utils/netlink.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@ enum class ATTACH_MODE {
4444
EGRESS,
4545
};
4646

47+
enum class IFACE_STATUS {
48+
UP,
49+
DOWN,
50+
};
51+
4752
class Observer; // a passible subscriber callback class
4853

4954
class Netlink {
@@ -72,6 +77,11 @@ class Netlink {
7277

7378
std::map<std::string, ExtIfaceInfo> get_available_ifaces();
7479

80+
void set_iface_status(const std::string &iface, IFACE_STATUS status);
81+
void set_iface_mac(const std::string &iface, const std::string &mac);
82+
void set_iface_ip(const std::string &iface, const std::string &ip, int prefix);
83+
void move_iface_into_ns(const std::string &iface, int fd);
84+
7585
template <typename Observer>
7686
int registerObserver(const Event &event, Observer &&observer) {
7787
std::lock_guard<std::mutex> lock(notify_mutex);
@@ -110,6 +120,10 @@ class Netlink {
110120
void notify_new_address(int ifindex, const std::string &info_address);
111121
void notify_all(int ifindex, const std::string &iface);
112122

123+
struct nlmsghdr* netlink_alloc();
124+
struct nlmsghdr* netlink_ip_alloc();
125+
int netlink_nl_send(struct nlmsghdr *nlmsg);
126+
113127
std::shared_ptr<spdlog::logger> logger;
114128
std::mutex notify_mutex;
115129

src/polycubed/src/utils/ns.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,13 @@ void Namespace::set_id(int id) {
202202
throw std::runtime_error("Error constructing nlmsg");
203203
}
204204

205+
std::string Namespace::get_name() const {
206+
return name_;
207+
}
208+
int Namespace::get_fd() const {
209+
return fd_;
210+
}
211+
205212
void Namespace::create_ns(const std::string &name) {
206213
std::string netns_path(std::string(NETNS_RUN_DIR) + "/" + name);
207214

src/polycubed/src/utils/ns.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ class Namespace {
3535
void remove();
3636
void set_id(int id);
3737

38+
std::string get_name() const;
39+
int get_fd() const;
40+
3841
~Namespace();
3942

4043
private:

0 commit comments

Comments
 (0)