Skip to content

Commit ae16e79

Browse files
authored
Merge pull request #122 from francescomessina/netlink_extension
Netlink change: Namespace support and event extension
2 parents def7cb5 + 553afa7 commit ae16e79

5 files changed

Lines changed: 169 additions & 39 deletions

File tree

src/polycubed/src/netlink.cpp

Lines changed: 156 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -20,58 +20,77 @@
2020
#include <linux/if.h>
2121
#include <iostream>
2222

23+
#include <arpa/inet.h>
24+
#include <sstream>
25+
#include <sys/socket.h>
26+
2327
#include "exceptions.h"
2428

29+
#ifndef SOL_NETLINK
30+
#define SOL_NETLINK 270
31+
#endif
32+
2533
namespace polycube {
2634
namespace polycubed {
2735

2836
class Netlink::NetlinkNotification {
2937
public:
3038
NetlinkNotification(Netlink *parent) : parent_(parent), running(true) {
3139
/* Allocate a new socket */
32-
sk = nl_socket_alloc();
33-
nl_socket_disable_seq_check(sk);
34-
nl_socket_modify_cb(sk, NL_CB_VALID, NL_CB_CUSTOM, recv_func, parent_);
35-
nl_connect(sk, NETLINK_ROUTE);
36-
nl_socket_add_memberships(sk, RTNLGRP_LINK, 0);
40+
struct sockaddr_nl addr;
41+
int option = 1;
42+
bzero (&addr, sizeof(addr));
3743

38-
parent_->logger->debug("started NetlinkNotification");
44+
sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
45+
addr.nl_family = AF_NETLINK;
46+
addr.nl_groups = (RTNLGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE) ;
3947

40-
thread_ = std::thread(&NetlinkNotification::execute_wait, this);
41-
// TODO: Detaching the thread is not a problem here since we are killing the
42-
// thread when the program terminates
43-
// thread_.detach();
44-
}
48+
if (bind(sock,(struct sockaddr *)&addr,sizeof(addr)) < 0) {
49+
parent_->logger->error("Netlink error bind");
50+
close(sock);
51+
}
4552

46-
void execute() {
47-
while (running) {
48-
nl_recvmsgs_default(sk);
53+
if (setsockopt(sock, SOL_NETLINK, NETLINK_LISTEN_ALL_NSID,(char*)&option,sizeof(option)) < 0) {
54+
parent_->logger->error("Netlink error setsockopt");
55+
close(sock);
4956
}
57+
58+
parent_->logger->debug("Started NetlinkNotification");
59+
60+
thread_ = std::thread(&NetlinkNotification::execute_wait, this);
61+
thread_.detach();
5062
}
5163

5264
void execute_wait() {
5365
int socket_fd, result;
5466
fd_set readset;
5567
struct timeval tv;
5668

57-
socket_fd = nl_socket_get_fd(sk);
69+
tv.tv_sec = NETLINK_TIMEOUT;
70+
tv.tv_usec = 0;
5871

5972
while (running) {
6073
do {
61-
tv.tv_sec = NETLINK_TIMEOUT;
62-
tv.tv_usec = 0;
6374
FD_ZERO(&readset);
64-
FD_SET(socket_fd, &readset);
65-
// The struct tv is decremented every time the select terminates.
66-
// If the value is not updated, the next time select is called uses
67-
// 0 as timeout value, behaving as a non-blocking socket.
68-
result = select(socket_fd + 1, &readset, NULL, NULL, &tv);
75+
FD_SET(sock, &readset);
76+
result = select(sock + 1, &readset, NULL, NULL, &tv);
6977
} while (result < 0 && errno == EINTR && running);
7078

7179
if (result > 0) {
72-
if (FD_ISSET(socket_fd, &readset)) {
73-
/* The socket_fd has data available to be read */
74-
nl_recvmsgs_default(sk);
80+
if (FD_ISSET(sock, &readset)) {
81+
// The socket_fd has data available to be read
82+
int received_bytes = 0;
83+
struct nlmsghdr *nlh;
84+
char buffer[4096];
85+
86+
bzero(buffer, sizeof(buffer));
87+
88+
received_bytes = recv(sock, buffer, sizeof(buffer), 0);
89+
if (received_bytes < 0)
90+
parent_->logger->error("Netlink Notification error received_bytes");
91+
92+
nlh = (struct nlmsghdr *) buffer;
93+
recv_func(sock,nlh, &Netlink::getInstance(),received_bytes);
7594
}
7695
}
7796
}
@@ -82,8 +101,7 @@ class Netlink::NetlinkNotification {
82101
// TODO: I would prefer to avoid the timeout, the destructor for this object
83102
// is called
84103
// only once the program ends and the thread is killed
85-
thread_.join();
86-
nl_socket_free(sk);
104+
close(sock);
87105
}
88106

89107
private:
@@ -92,10 +110,11 @@ class Netlink::NetlinkNotification {
92110
bool running;
93111
std::thread thread_;
94112
static const long int NETLINK_TIMEOUT = 1;
113+
int sock;
95114

96-
static int recv_func(struct nl_msg *msg, void *arg) {
115+
static int recv_func(int socket, struct nlmsghdr *msg, void *arg, int received_bytes) {
97116
Netlink *parent = (Netlink *)arg;
98-
struct nlmsghdr *nlh = nlmsg_hdr(msg);
117+
struct nlmsghdr *nlh = msg;
99118

100119
if (nlh->nlmsg_type == RTM_DELLINK) {
101120
struct ifinfomsg *iface = (struct ifinfomsg *)NLMSG_DATA(nlh);
@@ -106,6 +125,98 @@ class Netlink::NetlinkNotification {
106125
}
107126
}
108127

128+
if (nlh->nlmsg_type == RTM_NEWLINK) {
129+
struct ifinfomsg *iface = (struct ifinfomsg *)NLMSG_DATA(nlh);
130+
struct rtattr *hdr = IFLA_RTA(iface);
131+
if (hdr->rta_type == IFLA_IFNAME) {
132+
parent->notify_link_added(iface->ifi_index,
133+
std::string((char *)RTA_DATA(hdr)));
134+
}
135+
}
136+
137+
if (nlh->nlmsg_type == RTM_NEWADDR) {
138+
struct ifaddrmsg *iface = (struct ifaddrmsg *) NLMSG_DATA(nlh);
139+
struct rtattr *hdr = IFA_RTA(iface);
140+
141+
char address[32];
142+
char netmask[32];
143+
int rtl = IFA_PAYLOAD(nlh);
144+
145+
while (rtl && RTA_OK(hdr, rtl)) {
146+
if (hdr->rta_type == IFA_LOCAL)
147+
inet_ntop(AF_INET, RTA_DATA(hdr), address, sizeof(address));
148+
hdr = RTA_NEXT(hdr, rtl);
149+
}
150+
151+
/* Write the new information to a string (separated by '/').
152+
This string will be passed to the notify method */
153+
int netmask_len = iface->ifa_prefixlen;
154+
std::ostringstream info_new_address;
155+
info_new_address << address << "/" << netmask_len;
156+
std::string info_address = info_new_address.str();
157+
158+
parent->notify_new_address(iface->ifa_index, info_address);
159+
}
160+
161+
if (nlh->nlmsg_type == RTM_NEWROUTE || nlh->nlmsg_type == RTM_DELROUTE) {
162+
/* manage the routing table */
163+
struct rtmsg *route_entry; /* This struct represent a route entry in the
164+
routing table */
165+
struct rtattr *route_attribute; /* This struct contain route attributes
166+
(route type) */
167+
int route_attribute_len = 0;
168+
unsigned char route_netmask = 0;
169+
unsigned char route_protocol = 0;
170+
char destination_address[32];
171+
char gateway_address[32] = "-";
172+
int index = 0;
173+
int metrics = 0;
174+
175+
route_entry = (struct rtmsg *)NLMSG_DATA(nlh);
176+
177+
route_netmask = route_entry->rtm_dst_len;
178+
route_protocol = route_entry->rtm_protocol;
179+
route_attribute = (struct rtattr *)RTM_RTA(route_entry);
180+
181+
/* Get the len route attribute */
182+
route_attribute_len = RTM_PAYLOAD(nlh);
183+
184+
/* Loop through all attributes */
185+
for (; RTA_OK(route_attribute, route_attribute_len);
186+
route_attribute = RTA_NEXT(route_attribute, route_attribute_len)) {
187+
/* Route destination address */
188+
if (route_attribute->rta_type == RTA_DST) {
189+
inet_ntop(AF_INET, RTA_DATA(route_attribute), destination_address,
190+
sizeof(destination_address));
191+
}
192+
193+
/* The gateway of the route */
194+
if (route_attribute->rta_type == RTA_GATEWAY) {
195+
inet_ntop(AF_INET, RTA_DATA(route_attribute), gateway_address,
196+
sizeof(gateway_address));
197+
}
198+
199+
/* Output interface index */
200+
if (route_attribute->rta_type == RTA_OIF) {
201+
int *in = (int *)RTA_DATA(route_attribute);
202+
index = (int)*in;
203+
}
204+
}
205+
206+
/* Write the route information to a string (separated by '/').
207+
This string will be passed to the notify method */
208+
std::ostringstream infoRoute;
209+
int net_len = route_netmask;
210+
infoRoute << destination_address << "/" << net_len << "/" << gateway_address;
211+
std::string info_route = infoRoute.str();
212+
213+
if (nlh->nlmsg_type == RTM_DELROUTE) {
214+
parent->notify_route_deleted(index, info_route);
215+
} else if (nlh->nlmsg_type == RTM_NEWROUTE) {
216+
parent->notify_route_added(index, info_route);
217+
}
218+
}
219+
109220
parent->notify_all(0, "");
110221

111222
return NL_OK;
@@ -451,14 +562,26 @@ std::map<std::string, ExtIfaceInfo> Netlink::get_available_ifaces() {
451562
}
452563

453564
void Netlink::notify_link_deleted(int ifindex, const std::string &iface) {
454-
logger->debug(
455-
"received notification link deleted with ifindex {0} and name {1}",
456-
ifindex, iface);
457565
notify(Netlink::Event::LINK_DELETED, ifindex, iface);
458566
}
459567

568+
void Netlink::notify_link_added(int ifindex, const std::string &iface) {
569+
notify(Netlink::Event::LINK_ADDED, ifindex, iface);
570+
}
571+
572+
void Netlink::notify_route_added(int ifindex, const std::string &info_route) {
573+
notify(Netlink::Event::ROUTE_ADDED, ifindex, info_route);
574+
}
575+
576+
void Netlink::notify_route_deleted(int ifindex, const std::string &info_route) {
577+
notify(Netlink::Event::ROUTE_DELETED, ifindex, info_route);
578+
}
579+
580+
void Netlink::notify_new_address(int ifindex, const std::string &info_address) {
581+
notify(Netlink::Event::NEW_ADDRESS, ifindex, info_address);
582+
}
583+
460584
void Netlink::notify_all(int ifindex, const std::string &iface) {
461-
logger->debug("received netlink notification");
462585
notify(Netlink::Event::ALL, ifindex, iface);
463586
}
464587

src/polycubed/src/netlink.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,10 @@ class Observer; // a passible subscriber callback class
4848

4949
class Netlink {
5050
public:
51-
Netlink();
5251
~Netlink();
5352

5453
// TODO: Add here new events needed for the future
55-
enum Event { LINK_DELETED, ALL };
54+
enum Event { LINK_ADDED, LINK_DELETED, ROUTE_ADDED, ROUTE_DELETED, NEW_ADDRESS, ALL };
5655
// enum Event { LINK_DELETED };
5756
static Netlink &getInstance() {
5857
static Netlink instance;
@@ -103,7 +102,12 @@ class Netlink {
103102
}
104103

105104
private:
105+
Netlink();
106106
void notify_link_deleted(int ifindex, const std::string &iface);
107+
void notify_link_added(int ifindex, const std::string &iface);
108+
void notify_route_added(int ifindex, const std::string &info_route);
109+
void notify_route_deleted(int ifindex, const std::string &info_route);
110+
void notify_new_address(int ifindex, const std::string &info_address);
107111
void notify_all(int ifindex, const std::string &iface);
108112

109113
std::shared_ptr<spdlog::logger> logger;

src/services/pcn-iptables/src/Iptables.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
#include "Iptables_dp.h"
2121

2222
Iptables::Iptables(const std::string name, const IptablesJsonObject &conf)
23-
: Cube(conf.getBase(), {iptables_code_ingress}, {iptables_code_egress}) {
23+
: Cube(conf.getBase(), {iptables_code_ingress}, {iptables_code_egress}),
24+
netlink_instance_iptables_(polycube::polycubed::Netlink::getInstance()) {
2425
logger()->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [Iptables] [%n] [%l] %v");
2526
logger()->info("Creating Iptables instance");
2627

src/services/pcn-iptables/src/Iptables.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ class Iptables : public polycube::service::Cube<Ports>,
175175
std::mutex mutex_iptables_;
176176

177177
int netlink_notification_index_;
178-
polycube::polycubed::Netlink netlink_instance_iptables_;
178+
polycube::polycubed::Netlink &netlink_instance_iptables_;
179179

180180
// interactive mode
181181
bool interactive_ = true;
@@ -319,7 +319,7 @@ class Iptables : public polycube::service::Cube<Ports>,
319319

320320
// use a new instance of netlink for each chainselector
321321
// prevent deadlocks with main instance present in polycubed
322-
polycube::polycubed::Netlink netlink_instance_chainselector_;
322+
polycube::polycubed::Netlink &netlink_instance_chainselector_;
323323
int netlink_notification_index_chainselector_;
324324
};
325325

src/services/pcn-iptables/src/modules/ChainSelector.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ Iptables::ChainSelector::ChainSelector(const int &index, Iptables &outer,
2424
(t == ProgramType::INGRESS)
2525
? ChainNameEnum::INVALID_INGRESS
2626
: ChainNameEnum::INVALID_EGRESS,
27-
outer, t) {
27+
outer, t) ,
28+
netlink_instance_chainselector_(
29+
polycube::polycubed::Netlink::getInstance()) {
2830
load();
2931

3032
updateLocalIps();

0 commit comments

Comments
 (0)