With --echo option, regular commands may receive large replies just like
'nft monitor' does. Avoid buffer overruns and message loss by maximizing
the global nf_sock's receive buffer size upon creating, not just when
calling mnl_nft_event_listener.

Error reporting is tricky in nft_mnl_socket_open(), also being warned
about failures during receive buffer increase adds little value to the
user. So just fail silently instead.

Signed-off-by: Phil Sutter <p...@nwl.cc>
---
 src/mnl.c | 41 +++++++++++++++++++++--------------------
 1 file changed, 21 insertions(+), 20 deletions(-)

diff --git a/src/mnl.c b/src/mnl.c
index 9bb712adfa3b5..2c5a26a5e3465 100644
--- a/src/mnl.c
+++ b/src/mnl.c
@@ -33,6 +33,26 @@
 #include <utils.h>
 #include <nftables.h>
 
+#define NFTABLES_NLEVENT_BUFSIZ        (1 << 24)
+
+static void maximize_recv_buffer(struct mnl_socket *nf_sock)
+{
+       unsigned int bufsiz = NFTABLES_NLEVENT_BUFSIZ;
+       int fd = mnl_socket_get_fd(nf_sock);
+
+       /* Set netlink socket buffer size to 16 Mbytes to reduce chances of
+        * message loss due to ENOBUFS.
+        */
+       if (setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE,
+                      &bufsiz, sizeof(socklen_t)) < 0) {
+               /* If this doesn't work, try to reach the system wide maximum
+                * (or whatever the user requested).
+                */
+               setsockopt(fd, SOL_SOCKET, SO_RCVBUF,
+                          &bufsiz, sizeof(socklen_t));
+       }
+}
+
 struct mnl_socket *nft_mnl_socket_open(void)
 {
        struct mnl_socket *nf_sock;
@@ -44,6 +64,7 @@ struct mnl_socket *nft_mnl_socket_open(void)
        if (fcntl(mnl_socket_get_fd(nf_sock), F_SETFL, O_NONBLOCK))
                netlink_init_error();
 
+       maximize_recv_buffer(nf_sock);
        return nf_sock;
 }
 
@@ -1379,37 +1400,17 @@ int mnl_nft_flowtable_del(struct netlink_ctx *ctx, 
const struct cmd *cmd)
 /*
  * events
  */
-#define NFTABLES_NLEVENT_BUFSIZ        (1 << 24)
 
 int mnl_nft_event_listener(struct mnl_socket *nf_sock, unsigned int debug_mask,
                           struct output_ctx *octx,
                           int (*cb)(const struct nlmsghdr *nlh, void *data),
                           void *cb_data)
 {
-       /* Set netlink socket buffer size to 16 Mbytes to reduce chances of
-        * message loss due to ENOBUFS.
-        */
-       unsigned int bufsiz = NFTABLES_NLEVENT_BUFSIZ;
        int fd = mnl_socket_get_fd(nf_sock);
        char buf[NFT_NLMSG_MAXSIZE];
        fd_set readfds;
        int ret;
 
-       ret = setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, &bufsiz,
-                        sizeof(socklen_t));
-       if (ret < 0) {
-               /* If this doesn't work, try to reach the system wide maximum
-                * (or whatever the user requested).
-                */
-               ret = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bufsiz,
-                                sizeof(socklen_t));
-               if (ret < 0)
-                       nft_print(octx, "# Cannot increase netlink socket 
buffer size, expect message loss\n");
-               else
-                       nft_print(octx, "# Cannot set up netlink socket buffer 
size to %u bytes, falling back to %u bytes\n",
-                                 NFTABLES_NLEVENT_BUFSIZ, bufsiz);
-       }
-
        while (1) {
                FD_ZERO(&readfds);
                FD_SET(fd, &readfds);
-- 
2.21.0

Reply via email to