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+
2533namespace polycube {
2634namespace polycubed {
2735
2836class 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
453564void 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+
460584void Netlink::notify_all (int ifindex, const std::string &iface) {
461- logger->debug (" received netlink notification" );
462585 notify (Netlink::Event::ALL, ifindex, iface);
463586}
464587
0 commit comments