End operator is reporting that they are receiving buffer overruns
when attempting to read from the kernel receive socket. It is
possible to adjust this size to more modern levels especially
for when the system is under load. Modify the code base
so that *BSD operators can use the zebra `-s XXX` option
to specify a read buffer.
Additionally setup the default receive buffer size on *BSD
to be 128k instead of the 8k so that FRR does not run into
this issue again.
Fixes: #10666
Signed-off-by: Donald Sharp <sharpd@nvidia.com>
(cherry picked from commit
9fb83b55066e5cafa344d6a049e363fb631683f6)
{0}};
extern struct thread_master *master;
-extern uint32_t nl_rcvbufsize;
extern struct zebra_privs_t zserv_privs;
/* Try force option (linux >= 2.6.14) and fall back to normal set */
frr_with_privs(&zserv_privs) {
ret = setsockopt(nl->sock, SOL_SOCKET, SO_RCVBUFFORCE,
- &nl_rcvbufsize,
- sizeof(nl_rcvbufsize));
+ &rcvbufsize, sizeof(rcvbufsize));
}
if (ret < 0)
- ret = setsockopt(nl->sock, SOL_SOCKET, SO_RCVBUF,
- &nl_rcvbufsize, sizeof(nl_rcvbufsize));
+ ret = setsockopt(nl->sock, SOL_SOCKET, SO_RCVBUF, &rcvbufsize,
+ sizeof(rcvbufsize));
if (ret < 0) {
flog_err_sys(EC_LIB_SOCKET,
"Can't set %s receive buffer size: %s", nl->name,
errno);
/* Set receive buffer size if it's set from command line */
- if (nl_rcvbufsize) {
- netlink_recvbuf(&zns->netlink, nl_rcvbufsize);
- netlink_recvbuf(&zns->netlink_cmd, nl_rcvbufsize);
- netlink_recvbuf(&zns->netlink_dplane_out, nl_rcvbufsize);
- netlink_recvbuf(&zns->netlink_dplane_in, nl_rcvbufsize);
+ if (rcvbufsize) {
+ netlink_recvbuf(&zns->netlink, rcvbufsize);
+ netlink_recvbuf(&zns->netlink_cmd, rcvbufsize);
+ netlink_recvbuf(&zns->netlink_dplane_out, rcvbufsize);
+ netlink_recvbuf(&zns->netlink_dplane_in, rcvbufsize);
}
/* Set filter for inbound sockets, to exclude events we've generated
/* Make routing socket. */
static void routing_socket(struct zebra_ns *zns)
{
+ uint32_t default_rcvbuf;
+ socklen_t optlen;
+
frr_with_privs(&zserv_privs) {
routing_sock = ns_socket(AF_ROUTE, SOCK_RAW, 0, zns->ns_id);
/*if (fcntl (routing_sock, F_SETFL, O_NONBLOCK) < 0)
zlog_warn ("Can't set O_NONBLOCK to routing socket");*/
+ /*
+ * Attempt to set a more useful receive buffer size
+ */
+ optlen = sizeof(default_rcvbuf);
+ if (getsockopt(routing_sock, SOL_SOCKET, SO_RCVBUF, &default_rcvbuf,
+ &optlen) == -1)
+ flog_err_sys(EC_LIB_SOCKET,
+ "routing_sock sockopt SOL_SOCKET SO_RCVBUF");
+ else {
+ for (; rcvbufsize > default_rcvbuf &&
+ setsockopt(routing_sock, SOL_SOCKET, SO_RCVBUF,
+ &rcvbufsize, sizeof(rcvbufsize)) == -1 &&
+ errno == ENOBUFS;
+ rcvbufsize /= 2)
+ ;
+ }
+
/* kernel_read needs rewrite. */
thread_add_read(zrouter.master, kernel_read, NULL, routing_sock, NULL);
}
bool v6_rr_semantics = false;
+/* Receive buffer size for kernel control sockets */
#ifdef HAVE_NETLINK
-/* Receive buffer size for netlink socket */
-uint32_t nl_rcvbufsize = 4194304;
-#endif /* HAVE_NETLINK */
+uint32_t rcvbufsize = 4194304;
+#else
+uint32_t rcvbufsize = 128 * 1024;
+#endif
#define OPTION_V6_RR_SEMANTICS 2000
#define OPTION_ASIC_OFFLOAD 2001
frr_preinit(&zebra_di, argc, argv);
frr_opt_add(
- "baz:e:rK:"
+ "baz:e:rK:s:"
#ifdef HAVE_NETLINK
- "s:n"
+ "n"
#endif
,
longopts,
" -K, --graceful_restart Graceful restart at the kernel level, timer in seconds for expiration\n"
" -A, --asic-offload FRR is interacting with an asic underneath the linux kernel\n"
#ifdef HAVE_NETLINK
- " -n, --vrfwnetns Use NetNS as VRF backend\n"
" -s, --nl-bufsize Set netlink receive buffer size\n"
+ " -n, --vrfwnetns Use NetNS as VRF backend\n"
" --v6-rr-semantics Use v6 RR semantics\n"
+#else
+ " -s, Set kernel socket receive buffer size\n"
#endif /* HAVE_NETLINK */
);
case 'K':
graceful_restart = atoi(optarg);
break;
-#ifdef HAVE_NETLINK
case 's':
- nl_rcvbufsize = atoi(optarg);
+ rcvbufsize = atoi(optarg);
break;
+#ifdef HAVE_NETLINK
case 'n':
vrf_configure_backend(VRF_BACKEND_NETNS);
break;
#define GRACEFUL_RESTART_TIME 60
extern struct zebra_router zrouter;
+extern uint32_t rcvbufsize;
extern void zebra_router_init(bool asic_offload, bool notify_on_ack);
extern void zebra_router_cleanup(void);