Merge pull request #16982 from yuwata/socket-buffer-size

Fixes for socket buffer size
This commit is contained in:
Lennart Poettering 2020-09-09 16:28:21 +02:00 committed by GitHub
commit 39c4e2c1a1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 75 additions and 50 deletions

View file

@ -617,40 +617,62 @@ bool sockaddr_equal(const union sockaddr_union *a, const union sockaddr_union *b
return false;
}
int fd_inc_sndbuf(int fd, size_t n) {
int fd_set_sndbuf(int fd, size_t n, bool increase) {
int r, value;
socklen_t l = sizeof(value);
if (n > INT_MAX)
return -ERANGE;
r = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, &l);
if (r >= 0 && l == sizeof(value) && (size_t) value >= n*2)
if (r >= 0 && l == sizeof(value) && increase ? (size_t) value >= n*2 : (size_t) value == n*2)
return 0;
/* If we have the privileges we will ignore the kernel limit. */
/* First, try to set the buffer size with SO_SNDBUF. */
r = setsockopt_int(fd, SOL_SOCKET, SO_SNDBUF, n);
if (r < 0)
return r;
if (setsockopt_int(fd, SOL_SOCKET, SO_SNDBUF, n) < 0) {
r = setsockopt_int(fd, SOL_SOCKET, SO_SNDBUFFORCE, n);
if (r < 0)
return r;
}
/* SO_SNDBUF above may set to the kernel limit, instead of the requested size.
* So, we need to check the actual buffer size here. */
r = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, &l);
if (r >= 0 && l == sizeof(value) && increase ? (size_t) value >= n*2 : (size_t) value == n*2)
return 1;
/* If we have the privileges we will ignore the kernel limit. */
r = setsockopt_int(fd, SOL_SOCKET, SO_SNDBUFFORCE, n);
if (r < 0)
return r;
return 1;
}
int fd_inc_rcvbuf(int fd, size_t n) {
int fd_set_rcvbuf(int fd, size_t n, bool increase) {
int r, value;
socklen_t l = sizeof(value);
if (n > INT_MAX)
return -ERANGE;
r = getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, &l);
if (r >= 0 && l == sizeof(value) && (size_t) value >= n*2)
if (r >= 0 && l == sizeof(value) && increase ? (size_t) value >= n*2 : (size_t) value == n*2)
return 0;
/* If we have the privileges we will ignore the kernel limit. */
/* First, try to set the buffer size with SO_RCVBUF. */
r = setsockopt_int(fd, SOL_SOCKET, SO_RCVBUF, n);
if (r < 0)
return r;
if (setsockopt_int(fd, SOL_SOCKET, SO_RCVBUF, n) < 0) {
r = setsockopt_int(fd, SOL_SOCKET, SO_RCVBUFFORCE, n);
if (r < 0)
return r;
}
/* SO_RCVBUF above may set to the kernel limit, instead of the requested size.
* So, we need to check the actual buffer size here. */
r = getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, &l);
if (r >= 0 && l == sizeof(value) && increase ? (size_t) value >= n*2 : (size_t) value == n*2)
return 1;
/* If we have the privileges we will ignore the kernel limit. */
r = setsockopt_int(fd, SOL_SOCKET, SO_RCVBUFFORCE, n);
if (r < 0)
return r;
return 1;
}

View file

@ -118,8 +118,14 @@ int netlink_family_from_string(const char *s) _pure_;
bool sockaddr_equal(const union sockaddr_union *a, const union sockaddr_union *b);
int fd_inc_sndbuf(int fd, size_t n);
int fd_inc_rcvbuf(int fd, size_t n);
int fd_set_sndbuf(int fd, size_t n, bool increase);
static inline int fd_inc_sndbuf(int fd, size_t n) {
return fd_set_sndbuf(fd, n, true);
}
int fd_set_rcvbuf(int fd, size_t n, bool increase);
static inline int fd_inc_rcvbuf(int fd, size_t n) {
return fd_set_rcvbuf(fd, n, true);
}
int ip_tos_to_string_alloc(int i, char **s);
int ip_tos_from_string(const char *s);

View file

@ -1058,20 +1058,15 @@ static void socket_apply_socket_options(Socket *s, int fd) {
}
if (s->receive_buffer > 0) {
/* We first try with SO_RCVBUFFORCE, in case we have the perms for that */
if (setsockopt_int(fd, SOL_SOCKET, SO_RCVBUFFORCE, s->receive_buffer) < 0) {
r = setsockopt_int(fd, SOL_SOCKET, SO_RCVBUF, s->receive_buffer);
if (r < 0)
log_unit_warning_errno(UNIT(s), r, "SO_RCVBUF failed: %m");
}
r = fd_set_rcvbuf(fd, s->receive_buffer, false);
if (r < 0)
log_unit_warning_errno(UNIT(s), r, "SO_RCVBUF/SO_RCVBUFFORCE failed: %m");
}
if (s->send_buffer > 0) {
if (setsockopt_int(fd, SOL_SOCKET, SO_SNDBUFFORCE, s->send_buffer) < 0) {
r = setsockopt_int(fd, SOL_SOCKET, SO_SNDBUF, s->send_buffer);
if (r < 0)
log_unit_warning_errno(UNIT(s), r, "SO_SNDBUF failed: %m");
}
r = fd_set_sndbuf(fd, s->receive_buffer, false);
if (r < 0)
log_unit_warning_errno(UNIT(s), r, "SO_SNDBUF/SO_SNDBUFFORCE failed: %m");
}
if (s->mark >= 0) {

View file

@ -91,18 +91,9 @@ int device_monitor_allow_unicast_sender(sd_device_monitor *m, sd_device_monitor
}
_public_ int sd_device_monitor_set_receive_buffer_size(sd_device_monitor *m, size_t size) {
int r, n = (int) size;
assert_return(m, -EINVAL);
assert_return((size_t) n == size, -EINVAL);
if (setsockopt_int(m->sock, SOL_SOCKET, SO_RCVBUFFORCE, n) < 0) {
r = setsockopt_int(m->sock, SOL_SOCKET, SO_RCVBUF, n);
if (r < 0)
return r;
}
return 0;
return fd_set_rcvbuf(m->sock, size, false);
}
int device_monitor_disconnect(sd_device_monitor *m) {

View file

@ -36,11 +36,11 @@
#include "path-util.h"
#include "set.h"
#include "signal-util.h"
#include "stat-util.h"
#include "strv.h"
#include "sysctl-util.h"
#include "tmpfile-util.h"
#include "udev-util.h"
#include "virt.h"
/* use 128 MB for receive socket kernel queue. */
#define RCVBUF_SIZE (128*1024*1024)
@ -261,16 +261,19 @@ static int manager_udev_process_link(sd_device_monitor *monitor, sd_device *devi
static int manager_connect_udev(Manager *m) {
int r;
/* udev does not initialize devices inside containers,
* so we rely on them being already initialized before
* entering the container */
if (detect_container() > 0)
/* udev does not initialize devices inside containers, so we rely on them being already
* initialized before entering the container. */
if (path_is_read_only_fs("/sys") > 0)
return 0;
r = sd_device_monitor_new(&m->device_monitor);
if (r < 0)
return log_error_errno(r, "Failed to initialize device monitor: %m");
r = sd_device_monitor_set_receive_buffer_size(m->device_monitor, RCVBUF_SIZE);
if (r < 0)
log_warning_errno(r, "Failed to increase buffer size for device monitor, ignoring: %m");
r = sd_device_monitor_filter_add_match_subsystem_devtype(m->device_monitor, "net", NULL);
if (r < 0)
return log_error_errno(r, "Could not add device monitor filter: %m");
@ -1347,7 +1350,7 @@ static int manager_connect_genl(Manager *m) {
r = sd_netlink_inc_rcvbuf(m->genl, RCVBUF_SIZE);
if (r < 0)
return r;
log_warning_errno(r, "Failed to increase receive buffer size for general netlink socket, ignoring: %m");
r = sd_netlink_attach_event(m->genl, m->event, 0);
if (r < 0)
@ -1369,9 +1372,14 @@ static int manager_connect_rtnl(Manager *m) {
if (r < 0)
return r;
r = sd_netlink_inc_rcvbuf(m->rtnl, RCVBUF_SIZE);
if (r < 0)
return r;
/* Bump receiver buffer, but only if we are not called via socket activation, as in that
* case systemd sets the receive buffer size for us, and the value in the .socket unit
* should take full effect. */
if (fd < 0) {
r = sd_netlink_inc_rcvbuf(m->rtnl, RCVBUF_SIZE);
if (r < 0)
log_warning_errno(r, "Failed to increase receive buffer size for rtnl socket, ignoring: %m");
}
r = sd_netlink_attach_event(m->rtnl, m->event, 0);
if (r < 0)

View file

@ -1686,8 +1686,11 @@ static int manager_new(Manager **ret, int fd_ctrl, int fd_uevent, const char *cg
/* Bump receiver buffer, but only if we are not called via socket activation, as in that
* case systemd sets the receive buffer size for us, and the value in the .socket unit
* should take full effect. */
if (fd_uevent < 0)
(void) sd_device_monitor_set_receive_buffer_size(manager->monitor, 128 * 1024 * 1024);
if (fd_uevent < 0) {
r = sd_device_monitor_set_receive_buffer_size(manager->monitor, 128 * 1024 * 1024);
if (r < 0)
log_warning_errno(r, "Failed to set receive buffer size for device monitor, ignoring: %m");
}
r = device_monitor_enable_receiving(manager->monitor);
if (r < 0)