mirror of
https://github.com/troglobit/finit.git
synced 2026-09-30 13:02:37 +07:00
plugins: netlink: refactor and reduce recv() buffer
This patch adds support for calling recv() repeatedly to get the netlink response from the kernel. As a result, the recv() buffer can be reduced down to 4k again. Both the regular flow and the resync flow now follow the exact same code path, except for the ENOBUFS handling. If we get ENOBUFS in resync, we are screwed anyway. Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
+66
-64
@@ -32,8 +32,7 @@
|
||||
#include "plugin.h"
|
||||
#include "service.h"
|
||||
|
||||
/* Used on resync, when we potentially read ALL interfaces in the system */
|
||||
#define NL_BUFSZ 65536
|
||||
#define NL_BUFSZ 4096
|
||||
|
||||
struct nl_request {
|
||||
struct nlmsghdr nh;
|
||||
@@ -48,24 +47,6 @@ static int nl_ifdown;
|
||||
static char *nl_buf;
|
||||
|
||||
|
||||
static int nlmsg_validate(struct nlmsghdr *nh, size_t len)
|
||||
{
|
||||
if (!NLMSG_OK(nh, len))
|
||||
return 1;
|
||||
|
||||
if (nh->nlmsg_type == NLMSG_DONE) {
|
||||
_d("Done with netlink messages.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (nh->nlmsg_type == NLMSG_ERROR) {
|
||||
_d("Netlink reports error.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void nl_route(struct nlmsghdr *nlmsg, ssize_t len)
|
||||
{
|
||||
char daddr[INET_ADDRSTRLEN];
|
||||
@@ -245,34 +226,70 @@ static void nl_link(struct nlmsghdr *nlmsg, ssize_t len)
|
||||
}
|
||||
}
|
||||
|
||||
static int nl_parse(struct nlmsghdr *nh, ssize_t len)
|
||||
static int nl_parse(int sd)
|
||||
{
|
||||
for (; !nlmsg_validate(nh, len); nh = NLMSG_NEXT(nh, len)) {
|
||||
// _d("netlink message, type %d ...", nh->nlmsg_type);
|
||||
switch (nh->nlmsg_type) {
|
||||
case RTM_NEWROUTE:
|
||||
case RTM_DELROUTE:
|
||||
nl_route(nh, len);
|
||||
break;
|
||||
while (1) {
|
||||
struct nlmsghdr *nh;
|
||||
ssize_t len;
|
||||
|
||||
case RTM_NEWLINK:
|
||||
case RTM_DELLINK:
|
||||
nl_link(nh, len);
|
||||
break;
|
||||
while ((len = recv(sd, nl_buf, NL_BUFSZ, 0)) < 0) {
|
||||
switch (errno) {
|
||||
case EINTR: /* Signal */
|
||||
continue;
|
||||
|
||||
default:
|
||||
_w("unhandled netlink message, type %d", nh->nlmsg_type);
|
||||
break;
|
||||
case ENOBUFS: /* netlink(7) */
|
||||
break;
|
||||
|
||||
default:
|
||||
_pe("recv()");
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
_d("recv %lld bytes", len);
|
||||
|
||||
for (nh = (struct nlmsghdr *)nl_buf; NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len)) {
|
||||
struct nlmsgerr *nle;
|
||||
|
||||
switch (nh->nlmsg_type) {
|
||||
case NLMSG_DONE:
|
||||
_d("Done with netlink messages.");
|
||||
return 0;
|
||||
|
||||
case NLMSG_ERROR:
|
||||
_d("Kernel netlink comm. error.");
|
||||
nle = NLMSG_DATA(nh);
|
||||
if (nle) {
|
||||
errno = -nle->error;
|
||||
_pe("Kernel netlink error %d", errno);
|
||||
}
|
||||
return -1;
|
||||
|
||||
case RTM_NEWROUTE:
|
||||
case RTM_DELROUTE:
|
||||
_d("Netlink route ...");
|
||||
nl_route(nh, len);
|
||||
break;
|
||||
|
||||
case RTM_NEWLINK:
|
||||
case RTM_DELLINK:
|
||||
_d("Netlink link ...");
|
||||
nl_link(nh, len);
|
||||
break;
|
||||
|
||||
default:
|
||||
_w("unhandled netlink message, type %d", nh->nlmsg_type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nl_resync_act(int sd, unsigned int seq, int type)
|
||||
static int nl_request(int sd, unsigned int seq, int type)
|
||||
{
|
||||
struct nl_request *nlr = (struct nl_request *)nl_buf;
|
||||
ssize_t len;
|
||||
|
||||
memset(nlr, 0, sizeof(struct nl_request));
|
||||
nlr->nh.nlmsg_type = type;
|
||||
@@ -282,12 +299,14 @@ static int nl_resync_act(int sd, unsigned int seq, int type)
|
||||
|
||||
switch (type) {
|
||||
case RTM_GETROUTE:
|
||||
_d("RTM_GETROUTE");
|
||||
nlr->rtm.rtm_family = AF_INET;
|
||||
nlr->rtm.rtm_table = RT_TABLE_MAIN;
|
||||
nlr->nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
|
||||
break;
|
||||
|
||||
case RTM_GETLINK:
|
||||
_d("RTM_GETLINK");
|
||||
nlr->ifi.ifi_family = AF_UNSPEC;
|
||||
nlr->ifi.ifi_change = 0xFFFFFFFF;
|
||||
nlr->nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
|
||||
@@ -301,23 +320,18 @@ static int nl_resync_act(int sd, unsigned int seq, int type)
|
||||
if (send(sd, nlr, nlr->nh.nlmsg_len, 0) < 0)
|
||||
return 1;
|
||||
|
||||
len = recv(sd, nl_buf, NL_BUFSZ, 0);
|
||||
if (len < 0)
|
||||
return -1;
|
||||
|
||||
_d("recv %lld bytes in resync path", len);
|
||||
return nl_parse((struct nlmsghdr *)nl_buf, len);
|
||||
return nl_parse(sd);
|
||||
}
|
||||
|
||||
static void nl_resync_routes(int sd, unsigned int seq)
|
||||
{
|
||||
if (nl_resync_act(sd, seq, RTM_GETROUTE))
|
||||
if (nl_request(sd, seq, RTM_GETROUTE))
|
||||
_pe("Failed netlink route request");
|
||||
}
|
||||
|
||||
static void nl_resync_ifaces(int sd, unsigned int seq)
|
||||
{
|
||||
if (nl_resync_act(sd, seq, RTM_GETLINK))
|
||||
if (nl_request(sd, seq, RTM_GETLINK))
|
||||
_pe("Failed netlink link request");
|
||||
}
|
||||
|
||||
@@ -336,6 +350,7 @@ static void nl_resync(int all)
|
||||
}
|
||||
|
||||
if (all) {
|
||||
_d("============================ RESYNC =================================");
|
||||
/* this doesn't update condtions, and thus does not stop services */
|
||||
cond_deassert("net/");
|
||||
|
||||
@@ -344,6 +359,7 @@ static void nl_resync(int all)
|
||||
|
||||
/* delayed update after we've corrected things */
|
||||
service_step_all(SVC_TYPE_ANY);
|
||||
_d("=========================== RESYNCED ================================");
|
||||
} else
|
||||
nl_resync_routes(sd, seq++);
|
||||
|
||||
@@ -352,29 +368,15 @@ static void nl_resync(int all)
|
||||
|
||||
static void nl_callback(void *arg, int sd, int events)
|
||||
{
|
||||
ssize_t len;
|
||||
|
||||
len = recv(sd, nl_buf, NL_BUFSZ, 0);
|
||||
if (len < 0) {
|
||||
switch (errno) {
|
||||
case EINTR: /* Signal */
|
||||
break;
|
||||
|
||||
case ENOBUFS: /* netlink(7) */
|
||||
if (nl_parse(sd) < 0) {
|
||||
if (errno == ENOBUFS) { /* netlink(7) */
|
||||
_w("busy system, resynchronizing with kernel.");
|
||||
nl_resync(1);
|
||||
break;
|
||||
|
||||
default:
|
||||
_pe("recv()");
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
_d("recv %lld bytes in regular path", len);
|
||||
nl_parse((struct nlmsghdr *)nl_buf, len);
|
||||
|
||||
/*
|
||||
* Linux doesn't send route changes when interfaces go down, so
|
||||
* we need to check ourselves, e.g. for loss of default route.
|
||||
|
||||
Reference in New Issue
Block a user