From 6bb2d871d3fce58f84dae079f6470f38762f686a Mon Sep 17 00:00:00 2001
From: Daniel Salzman <daniel.salzman@nic.cz>
Date: Fri, 27 Aug 2021 08:48:44 +0200
Subject: [PATCH] xdp: don't increase RLIMIT_MEMLOCK on Linux >= 5.11, not
 needed

---
 Knot.files               |  1 +
 doc/man/kxdpgun.8in      |  2 +-
 doc/man_kxdpgun.rst      |  2 +-
 doc/operation.rst        |  2 ++
 src/contrib/Makefile.inc |  1 +
 src/contrib/os.h         | 37 +++++++++++++++++++++++++++++++++++++
 src/knot/server/server.c |  3 ++-
 src/utils/kxdpgun/main.c | 18 ++++++++++++------
 8 files changed, 57 insertions(+), 9 deletions(-)
 create mode 100644 src/contrib/os.h

diff --git a/Knot.files b/Knot.files
index 60cab572ba..7bee1b2ef7 100644
--- a/Knot.files
+++ b/Knot.files
@@ -73,6 +73,7 @@ src/contrib/openbsd/strlcat.c
 src/contrib/openbsd/strlcat.h
 src/contrib/openbsd/strlcpy.c
 src/contrib/openbsd/strlcpy.h
+src/contrib/os.h
 src/contrib/qp-trie/trie.c
 src/contrib/qp-trie/trie.h
 src/contrib/semaphore.c
diff --git a/doc/man/kxdpgun.8in b/doc/man/kxdpgun.8in
index c6cec46cd3..202d9b907a 100644
--- a/doc/man/kxdpgun.8in
+++ b/doc/man/kxdpgun.8in
@@ -113,7 +113,7 @@ Linux kernel 4.18+ is required.
 .sp
 The utility has to be executed under root or with these capabilities:
 CAP_NET_RAW, CAP_NET_ADMIN, CAP_SYS_ADMIN, and CAP_SYS_RESOURCE if maximum
-locked memory limit is too low.
+locked memory limit is too low on Linux < 5.11.
 .sp
 Sending USR1 signal to a running process triggers current statistics dump
 to the standard output.
diff --git a/doc/man_kxdpgun.rst b/doc/man_kxdpgun.rst
index fd2eccbe6c..6ecb35c98d 100644
--- a/doc/man_kxdpgun.rst
+++ b/doc/man_kxdpgun.rst
@@ -93,7 +93,7 @@ Linux kernel 4.18+ is required.
 
 The utility has to be executed under root or with these capabilities:
 CAP_NET_RAW, CAP_NET_ADMIN, CAP_SYS_ADMIN, and CAP_SYS_RESOURCE if maximum
-locked memory limit is too low.
+locked memory limit is too low on Linux < 5.11.
 
 Sending USR1 signal to a running process triggers current statistics dump
 to the standard output.
diff --git a/doc/operation.rst b/doc/operation.rst
index ac04df4ff1..2202b42ce7 100644
--- a/doc/operation.rst
+++ b/doc/operation.rst
@@ -1109,6 +1109,8 @@ Pre-requisites
     CapabilityBoundingSet=CAP_NET_RAW CAP_NET_ADMIN CAP_SYS_ADMIN CAP_SYS_RESOURCE
     AmbientCapabilities=CAP_NET_RAW CAP_NET_ADMIN CAP_SYS_ADMIN CAP_SYS_RESOURCE
 
+  The `CAP_SYS_RESOURCE` is needed on Linux < 5.11.
+
 Optimizations
 -------------
 
diff --git a/src/contrib/Makefile.inc b/src/contrib/Makefile.inc
index b7aaecbd47..ee987071d8 100644
--- a/src/contrib/Makefile.inc
+++ b/src/contrib/Makefile.inc
@@ -40,6 +40,7 @@ libcontrib_la_SOURCES = \
 	contrib/mempattern.h			\
 	contrib/net.c				\
 	contrib/net.h				\
+	contrib/os.h				\
 	contrib/qp-trie/trie.c			\
 	contrib/qp-trie/trie.h			\
 	contrib/semaphore.c			\
diff --git a/src/contrib/os.h b/src/contrib/os.h
new file mode 100644
index 0000000000..8d4a2e21d9
--- /dev/null
+++ b/src/contrib/os.h
@@ -0,0 +1,37 @@
+/*  Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <sys/utsname.h>
+
+inline static bool linux_at_least(unsigned version_first, unsigned version_second)
+{
+#if defined(__linux__)
+	struct utsname info;
+	unsigned first, second;
+	if (uname(&info) != 0 || sscanf(info.release, "%u.%u.", &first, &second) != 2) {
+		return false;
+	} else {
+		return first > version_first ||
+		       (first = version_first && second >= version_second);
+	}
+#else
+	return false;
+#endif
+}
diff --git a/src/knot/server/server.c b/src/knot/server/server.c
index 02e166c54f..bac00a9dbe 100644
--- a/src/knot/server/server.c
+++ b/src/knot/server/server.c
@@ -40,6 +40,7 @@
 #include "knot/worker/pool.h"
 #include "contrib/net.h"
 #include "contrib/openbsd/strlcat.h"
+#include "contrib/os.h"
 #include "contrib/sockaddr.h"
 #include "contrib/trim.h"
 
@@ -511,7 +512,7 @@ static int configure_sockets(conf_t *conf, server_t *s)
 	}
 
 #ifdef ENABLE_XDP
-	if (lisxdp_val.code == KNOT_EOK) {
+	if (lisxdp_val.code == KNOT_EOK && !linux_at_least(5, 11)) {
 		struct rlimit min_limit = { RLIM_INFINITY, RLIM_INFINITY };
 		struct rlimit cur_limit = { 0 };
 		if (getrlimit(RLIMIT_MEMLOCK, &cur_limit) != 0 ||
diff --git a/src/utils/kxdpgun/main.c b/src/utils/kxdpgun/main.c
index 0a453c7727..2ccf0efb0b 100644
--- a/src/utils/kxdpgun/main.c
+++ b/src/utils/kxdpgun/main.c
@@ -43,6 +43,7 @@
 #include "contrib/mempattern.h"
 #include "contrib/openbsd/strlcat.h"
 #include "contrib/openbsd/strlcpy.h"
+#include "contrib/os.h"
 #include "contrib/sockaddr.h"
 #include "contrib/ucw/mempool.h"
 #include "utils/common/params.h"
@@ -794,14 +795,19 @@ int main(int argc, char *argv[])
 		thread_ctxs[i].thread_id = i;
 	}
 
-	struct rlimit min_limit = { RLIM_INFINITY, RLIM_INFINITY }, cur_limit = { 0 };
-	if (getrlimit(RLIMIT_MEMLOCK, &cur_limit) != 0 ||
-	    cur_limit.rlim_cur != min_limit.rlim_cur || cur_limit.rlim_max != min_limit.rlim_max) {
-		int ret = setrlimit(RLIMIT_MEMLOCK, &min_limit);
-		if (ret != 0) {
-			printf("warning: unable to increase RLIMIT_MEMLOCK: %s\n", strerror(errno));
+	if (!linux_at_least(5, 11)) {
+		struct rlimit min_limit = { RLIM_INFINITY, RLIM_INFINITY }, cur_limit = { 0 };
+		if (getrlimit(RLIMIT_MEMLOCK, &cur_limit) != 0 ||
+		    cur_limit.rlim_cur != min_limit.rlim_cur ||
+		    cur_limit.rlim_max != min_limit.rlim_max) {
+			int ret = setrlimit(RLIMIT_MEMLOCK, &min_limit);
+			if (ret != 0) {
+				printf("warning: unable to increase RLIMIT_MEMLOCK: %s\n",
+				       strerror(errno));
+			}
 		}
 	}
+
 	pthread_mutex_init(&global_stats.mutex, NULL);
 
 	struct sigaction stop_action = { .sa_handler = sigterm_handler };
-- 
GitLab