Blame SOURCES/0010-rh1249158-local-port-EADDRINUSE.patch

50bdc6
From 2b7b4ae45f5171231b562ba51be256d1e2c40401 Mon Sep 17 00:00:00 2001
50bdc6
From: Thomas Graf <tgraf@suug.ch>
50bdc6
Date: Mon, 31 Mar 2014 13:21:06 +0200
50bdc6
Subject: [PATCH 01/11] link: Catch missing io_free() implementations
50bdc6
50bdc6
Signed-off-by: Thomas Graf <tgraf@suug.ch>
50bdc6
Signed-off-by: Thomas Haller <thaller@redhat.com>
50bdc6
(cherry picked from commit 34bfce62150d07cf9894f2d9cbd0c989a203ea52)
50bdc6
---
50bdc6
 include/netlink-private/netlink.h | 7 +++++++
50bdc6
 lib/route/link.c                  | 4 ++++
50bdc6
 2 files changed, 11 insertions(+)
50bdc6
50bdc6
diff --git a/include/netlink-private/netlink.h b/include/netlink-private/netlink.h
50bdc6
index 6ae6d17..83eefad 100644
50bdc6
--- a/include/netlink-private/netlink.h
50bdc6
+++ b/include/netlink-private/netlink.h
50bdc6
@@ -95,6 +95,13 @@ struct trans_list {
50bdc6
 		assert(0);						\
50bdc6
 	} while (0)
50bdc6
 
50bdc6
+#define BUG_ON(condition)						\
50bdc6
+	do {								\
50bdc6
+		if (condition)						\
50bdc6
+			BUG();						\
50bdc6
+	} while (0)
50bdc6
+
50bdc6
+
50bdc6
 #define APPBUG(msg)							\
50bdc6
 	do {								\
50bdc6
 		NL_DBG(1, "APPLICATION BUG: %s:%d:%s: %s\n",		\
50bdc6
diff --git a/lib/route/link.c b/lib/route/link.c
50bdc6
index 8fe3376..1f27247 100644
50bdc6
--- a/lib/route/link.c
50bdc6
+++ b/lib/route/link.c
50bdc6
@@ -184,6 +184,10 @@ static void release_link_info(struct rtnl_link *link)
50bdc6
 	if (io != NULL) {
50bdc6
 		if (io->io_free)
50bdc6
 			io->io_free(link);
50bdc6
+		else {
50bdc6
+			/* Catch missing io_free() implementations */
50bdc6
+			BUG_ON(link->l_info);
50bdc6
+		}
50bdc6
 		rtnl_link_info_ops_put(io);
50bdc6
 		link->l_info_ops = NULL;
50bdc6
 	}
50bdc6
-- 
50bdc6
2.4.3
50bdc6
50bdc6
50bdc6
From 369857fcf8d6c2783be8c1d225ad192363245098 Mon Sep 17 00:00:00 2001
50bdc6
From: Thomas Graf <tgraf@suug.ch>
50bdc6
Date: Fri, 28 Jun 2013 18:53:16 +0200
50bdc6
Subject: [PATCH 02/11] socket: Warn via debug message if local port namespace
50bdc6
 is exhausted
50bdc6
50bdc6
Signed-off-by: Thomas Graf <tgraf@suug.ch>
50bdc6
(cherry picked from commit 2d0810eb93704defb2375d9861892d6041da4623)
50bdc6
---
50bdc6
 lib/socket.c | 1 +
50bdc6
 1 file changed, 1 insertion(+)
50bdc6
50bdc6
diff --git a/lib/socket.c b/lib/socket.c
50bdc6
index d3e636e..f3171f5 100644
50bdc6
--- a/lib/socket.c
50bdc6
+++ b/lib/socket.c
50bdc6
@@ -89,6 +89,7 @@ static uint32_t generate_local_port(void)
50bdc6
 	nl_write_unlock(&port_map_lock);
50bdc6
 
50bdc6
 	/* Out of sockets in our own PID namespace, what to do? FIXME */
50bdc6
+	NL_DBG(1, "Warning: Ran out of unique local port namespace\n");
50bdc6
 	return UINT_MAX;
50bdc6
 }
50bdc6
 
50bdc6
-- 
50bdc6
2.4.3
50bdc6
50bdc6
50bdc6
From bba9ce1426728f00eccc5aa97d6d6c954d383481 Mon Sep 17 00:00:00 2001
50bdc6
From: Thomas Haller <thaller@redhat.com>
50bdc6
Date: Wed, 9 Apr 2014 12:08:50 +0200
50bdc6
Subject: [PATCH 03/11] lib/socket: use proper typed constant UINT32_MAX for
50bdc6
 uint32_t typed port
50bdc6
50bdc6
This was a bug on architectures with native int type less then 32 bit.
50bdc6
50bdc6
Acked-by: Thomas Graf <tgraf@suug.ch>
50bdc6
Signed-off-by: Thomas Haller <thaller@redhat.com>
50bdc6
(cherry picked from commit 0fd510b3673f479637a6376db3d66dcb9f8911d0)
50bdc6
---
50bdc6
 lib/socket.c | 8 ++++----
50bdc6
 1 file changed, 4 insertions(+), 4 deletions(-)
50bdc6
50bdc6
diff --git a/lib/socket.c b/lib/socket.c
50bdc6
index f3171f5..fa12e25 100644
50bdc6
--- a/lib/socket.c
50bdc6
+++ b/lib/socket.c
50bdc6
@@ -82,7 +82,7 @@ static uint32_t generate_local_port(void)
50bdc6
 
50bdc6
 			nl_write_unlock(&port_map_lock);
50bdc6
 
50bdc6
-			return pid + (n << 22);
50bdc6
+			return pid + (((uint32_t)n) << 22);
50bdc6
 		}
50bdc6
 	}
50bdc6
 
50bdc6
@@ -90,14 +90,14 @@ static uint32_t generate_local_port(void)
50bdc6
 
50bdc6
 	/* Out of sockets in our own PID namespace, what to do? FIXME */
50bdc6
 	NL_DBG(1, "Warning: Ran out of unique local port namespace\n");
50bdc6
-	return UINT_MAX;
50bdc6
+	return UINT32_MAX;
50bdc6
 }
50bdc6
 
50bdc6
 static void release_local_port(uint32_t port)
50bdc6
 {
50bdc6
 	int nr;
50bdc6
 
50bdc6
-	if (port == UINT_MAX)
50bdc6
+	if (port == UINT32_MAX)
50bdc6
 		return;
50bdc6
 	
50bdc6
 	nr = port >> 22;
50bdc6
@@ -126,7 +126,7 @@ static struct nl_sock *__alloc_socket(struct nl_cb *cb)
50bdc6
 	sk->s_peer.nl_family = AF_NETLINK;
50bdc6
 	sk->s_seq_expect = sk->s_seq_next = time(0);
50bdc6
 	sk->s_local.nl_pid = generate_local_port();
50bdc6
-	if (sk->s_local.nl_pid == UINT_MAX) {
50bdc6
+	if (sk->s_local.nl_pid == UINT32_MAX) {
50bdc6
 		nl_socket_free(sk);
50bdc6
 		return NULL;
50bdc6
 	}
50bdc6
-- 
50bdc6
2.4.3
50bdc6
50bdc6
50bdc6
From b4c09ead0b289a74d86dd47fbf1081daafcd4826 Mon Sep 17 00:00:00 2001
50bdc6
From: Thomas Haller <thaller@redhat.com>
50bdc6
Date: Wed, 9 Apr 2014 12:08:51 +0200
50bdc6
Subject: [PATCH 04/11] lib/socket: don't fail if no more local ports can be
50bdc6
 assigned in nl_socket_alloc
50bdc6
50bdc6
By failing inside of nl_socket_alloc(), the user can not even work around
50bdc6
when running out of local ports. This patch changes that if there are no more
50bdc6
local ports, we set the port to UINT32_MAX. This is a consistent behavior
50bdc6
to calling nl_socket_set_local_port(sk, 0).
50bdc6
50bdc6
In general, since nl_socket_set_local_port() does not restict the generated
50bdc6
ports in any way we cannot assume to have a valid port. So the check in
50bdc6
the constructor was harmful and users who ever encountered it (because they
50bdc6
created 1024 libnl3 sockets) could not even work around it.
50bdc6
50bdc6
Acked-by: Thomas Graf <tgraf@suug.ch>
50bdc6
Signed-off-by: Thomas Haller <thaller@redhat.com>
50bdc6
(cherry picked from commit 0271578987088210d7d2d68addbd5e8fe27d4383)
50bdc6
---
50bdc6
 lib/socket.c | 4 ----
50bdc6
 1 file changed, 4 deletions(-)
50bdc6
50bdc6
diff --git a/lib/socket.c b/lib/socket.c
50bdc6
index fa12e25..f9e68ff 100644
50bdc6
--- a/lib/socket.c
50bdc6
+++ b/lib/socket.c
50bdc6
@@ -126,10 +126,6 @@ static struct nl_sock *__alloc_socket(struct nl_cb *cb)
50bdc6
 	sk->s_peer.nl_family = AF_NETLINK;
50bdc6
 	sk->s_seq_expect = sk->s_seq_next = time(0);
50bdc6
 	sk->s_local.nl_pid = generate_local_port();
50bdc6
-	if (sk->s_local.nl_pid == UINT32_MAX) {
50bdc6
-		nl_socket_free(sk);
50bdc6
-		return NULL;
50bdc6
-	}
50bdc6
 
50bdc6
 	return sk;
50bdc6
 }
50bdc6
-- 
50bdc6
2.4.3
50bdc6
50bdc6
50bdc6
From 5de5c84c094fd178216accd2c29f32bfe5f7f67b Mon Sep 17 00:00:00 2001
50bdc6
From: Thomas Haller <thaller@redhat.com>
50bdc6
Date: Wed, 9 Apr 2014 12:08:52 +0200
50bdc6
Subject: [PATCH 05/11] lib/socket: retry generate local port in nl_connect on
50bdc6
 ADDRINUSE
50bdc6
50bdc6
It can easily happen that the generated local netlink port is alrady in
50bdc6
use. In that case bind will fail with ADDRINUSE.
50bdc6
50bdc6
Users of libnl3 could workaround this, by managing the local ports
50bdc6
themselves, but sometimes these users are libraries too and they also
50bdc6
don't know which ports might be used by other components.
50bdc6
50bdc6
This patch changes that nl_socket_alloc() no longer initilizes the local
50bdc6
port id immediately. Instead it will be initialized when the user calls
50bdc6
nl_socket_get_local_port() the first time and thereby shows interest in
50bdc6
the value.
50bdc6
50bdc6
If bind() fails with ADDRINUSE, check if the user ever cared about the
50bdc6
local port, i.e. whether the local port is still unset. If it is still
50bdc6
unset, assume that libnl should choose a suitable port and retry until
50bdc6
an unused port can be found.
50bdc6
50bdc6
Signed-off-by: Thomas Haller <thaller@redhat.com>
50bdc6
50bdc6
[thaller@redhat.com: modify original patch to use explicit gcc attribute
50bdc6
to hide private symbols instead of "libnl.sym"]
50bdc6
50bdc6
(cherry picked from commit 4dd5fdd0af2c0b7ffe1dbc49313f263dbb2e906f)
50bdc6
---
50bdc6
 include/Makefile.am              |   1 +
50bdc6
 include/netlink-private/socket.h |  31 +++++++++++
50bdc6
 include/netlink/utils.h          |   9 +++
50bdc6
 lib/nl.c                         |  62 ++++++++++++++++++---
50bdc6
 lib/socket.c                     | 116 ++++++++++++++++++++++++++++++++-------
50bdc6
 lib/utils.c                      |   2 +-
50bdc6
 6 files changed, 192 insertions(+), 29 deletions(-)
50bdc6
 create mode 100644 include/netlink-private/socket.h
50bdc6
50bdc6
diff --git a/include/Makefile.am b/include/Makefile.am
50bdc6
index b9487e0..d0ed008 100644
50bdc6
--- a/include/Makefile.am
50bdc6
+++ b/include/Makefile.am
50bdc6
@@ -125,6 +125,7 @@ noinst_HEADERS = \
50bdc6
 	linux/tc_ematch/tc_em_meta.h \
50bdc6
 	netlink-private/genl.h \
50bdc6
 	netlink-private/netlink.h \
50bdc6
+	netlink-private/socket.h \
50bdc6
 	netlink-private/tc.h \
50bdc6
 	netlink-private/types.h \
50bdc6
 	netlink-private/cache-api.h \
50bdc6
diff --git a/include/netlink-private/socket.h b/include/netlink-private/socket.h
50bdc6
new file mode 100644
50bdc6
index 0000000..86a440c
50bdc6
--- /dev/null
50bdc6
+++ b/include/netlink-private/socket.h
50bdc6
@@ -0,0 +1,31 @@
50bdc6
+/*
50bdc6
+ * netlink-private/socket.h		Private declarations for socket
50bdc6
+ *
50bdc6
+ *	This library is free software; you can redistribute it and/or
50bdc6
+ *	modify it under the terms of the GNU Lesser General Public
50bdc6
+ *	License as published by the Free Software Foundation version 2.1
50bdc6
+ *	of the License.
50bdc6
+ *
50bdc6
+ * Copyright (c) 2014 Thomas Graf <tgraf@suug.ch>
50bdc6
+ */
50bdc6
+
50bdc6
+#ifndef NETLINK_SOCKET_PRIV_H_
50bdc6
+#define NETLINK_SOCKET_PRIV_H_
50bdc6
+
50bdc6
+#include <netlink-private/netlink.h>
50bdc6
+
50bdc6
+#ifdef __cplusplus
50bdc6
+extern "C" {
50bdc6
+#endif
50bdc6
+
50bdc6
+int _nl_socket_is_local_port_unspecified (struct nl_sock *sk);
50bdc6
+uint32_t _nl_socket_generate_local_port_no_release(struct nl_sock *sk);
50bdc6
+
50bdc6
+void _nl_socket_used_ports_release_all(const uint32_t *used_ports);
50bdc6
+void _nl_socket_used_ports_set(uint32_t *used_ports, uint32_t port);
50bdc6
+
50bdc6
+#ifdef __cplusplus
50bdc6
+}
50bdc6
+#endif
50bdc6
+
50bdc6
+#endif
50bdc6
diff --git a/include/netlink/utils.h b/include/netlink/utils.h
50bdc6
index 2094bb4..5b0d275 100644
50bdc6
--- a/include/netlink/utils.h
50bdc6
+++ b/include/netlink/utils.h
50bdc6
@@ -90,6 +90,15 @@ enum {
50bdc6
 	NL_CAPABILITY_ROUTE_BUILD_MSG_SET_SCOPE         = 1,
50bdc6
 #define NL_CAPABILITY_ROUTE_BUILD_MSG_SET_SCOPE NL_CAPABILITY_ROUTE_BUILD_MSG_SET_SCOPE
50bdc6
 
50bdc6
+	/**
50bdc6
+	 * Indicate that the local port is unspecified until the user accesses
50bdc6
+	 * it (via nl_socket_get_local_port()) or until nl_connect(). More importantly,
50bdc6
+	 * if the port is left unspecified, nl_connect() will retry generating another
50bdc6
+	 * port when bind() fails with ADDRINUSE.
50bdc6
+	 */
50bdc6
+	NL_CAPABILITY_NL_CONNECT_RETRY_GENERATE_PORT_ON_ADDRINUSE = 4,
50bdc6
+#define NL_CAPABILITY_NL_CONNECT_RETRY_GENERATE_PORT_ON_ADDRINUSE NL_CAPABILITY_NL_CONNECT_RETRY_GENERATE_PORT_ON_ADDRINUSE
50bdc6
+
50bdc6
 	__NL_CAPABILITY_MAX
50bdc6
 #define NL_CAPABILITY_MAX                               (__NL_CAPABILITY_MAX - 1)
50bdc6
 };
50bdc6
diff --git a/lib/nl.c b/lib/nl.c
50bdc6
index 565747a..37065d4 100644
50bdc6
--- a/lib/nl.c
50bdc6
+++ b/lib/nl.c
50bdc6
@@ -26,6 +26,7 @@
50bdc6
  */
50bdc6
 
50bdc6
 #include <netlink-private/netlink.h>
50bdc6
+#include <netlink-private/socket.h>
50bdc6
 #include <netlink/netlink.h>
50bdc6
 #include <netlink/utils.h>
50bdc6
 #include <netlink/handlers.h>
50bdc6
@@ -75,6 +76,16 @@
50bdc6
  *       be closed automatically if any of the `exec` family functions succeed.
50bdc6
  *       This is essential for multi threaded programs.
50bdc6
  *
50bdc6
+ * @note The local port (`nl_socket_get_local_port()`) is unspecified after
50bdc6
+ *       creating a new socket. It only gets determined when accessing the
50bdc6
+ *       port the first time or during `nl_connect()`. When nl_connect()
50bdc6
+ *       fails during `bind()` due to `ADDRINUSE`, it will retry with
50bdc6
+ *       different ports if the port is unspecified. Unless you want to enforce
50bdc6
+ *       the use of a specific local port, don't access the local port (or
50bdc6
+ *       reset it to `unspecified` by calling `nl_socket_set_local_port(sk, 0)`).
50bdc6
+ *       This capability is indicated by
50bdc6
+ *       `%NL_CAPABILITY_NL_CONNECT_RETRY_GENERATE_PORT_ON_ADDRINUSE`.
50bdc6
+ *
50bdc6
  * @see nl_socket_alloc()
50bdc6
  * @see nl_close()
50bdc6
  *
50bdc6
@@ -85,6 +96,7 @@
50bdc6
 int nl_connect(struct nl_sock *sk, int protocol)
50bdc6
 {
50bdc6
 	int err, flags = 0;
50bdc6
+	int errsv;
50bdc6
 	socklen_t addrlen;
50bdc6
 
50bdc6
 #ifdef SOCK_CLOEXEC
50bdc6
@@ -96,7 +108,9 @@ int nl_connect(struct nl_sock *sk, int protocol)
50bdc6
 
50bdc6
 	sk->s_fd = socket(AF_NETLINK, SOCK_RAW | flags, protocol);
50bdc6
 	if (sk->s_fd < 0) {
50bdc6
-		err = -nl_syserr2nlerr(errno);
50bdc6
+		errsv = errno;
50bdc6
+		NL_DBG(4, "nl_connect(%p): socket() failed with %d\n", sk, errsv);
50bdc6
+		err = -nl_syserr2nlerr(errsv);
50bdc6
 		goto errout;
50bdc6
 	}
50bdc6
 
50bdc6
@@ -106,11 +120,45 @@ int nl_connect(struct nl_sock *sk, int protocol)
50bdc6
 			goto errout;
50bdc6
 	}
50bdc6
 
50bdc6
-	err = bind(sk->s_fd, (struct sockaddr*) &sk->s_local,
50bdc6
-		   sizeof(sk->s_local));
50bdc6
-	if (err < 0) {
50bdc6
-		err = -nl_syserr2nlerr(errno);
50bdc6
-		goto errout;
50bdc6
+	if (_nl_socket_is_local_port_unspecified (sk)) {
50bdc6
+		uint32_t port;
50bdc6
+		uint32_t used_ports[32] = { 0 };
50bdc6
+
50bdc6
+		while (1) {
50bdc6
+			port = _nl_socket_generate_local_port_no_release(sk);
50bdc6
+
50bdc6
+			if (port == UINT32_MAX) {
50bdc6
+				NL_DBG(4, "nl_connect(%p): no more unused local ports.\n", sk);
50bdc6
+				_nl_socket_used_ports_release_all(used_ports);
50bdc6
+				err = -NLE_EXIST;
50bdc6
+				goto errout;
50bdc6
+			}
50bdc6
+			err = bind(sk->s_fd, (struct sockaddr*) &sk->s_local,
50bdc6
+				   sizeof(sk->s_local));
50bdc6
+			if (err == 0)
50bdc6
+				break;
50bdc6
+
50bdc6
+			errsv = errno;
50bdc6
+			if (errsv == EADDRINUSE) {
50bdc6
+				NL_DBG(4, "nl_connect(%p): local port %u already in use. Retry.\n", sk, (unsigned) port);
50bdc6
+				_nl_socket_used_ports_set(used_ports, port);
50bdc6
+			} else {
50bdc6
+				NL_DBG(4, "nl_connect(%p): bind() for port %u failed with %d\n", sk, (unsigned) port, errsv);
50bdc6
+				_nl_socket_used_ports_release_all(used_ports);
50bdc6
+				err = -nl_syserr2nlerr(errsv);
50bdc6
+				goto errout;
50bdc6
+			}
50bdc6
+		}
50bdc6
+		_nl_socket_used_ports_release_all(used_ports);
50bdc6
+	} else {
50bdc6
+		err = bind(sk->s_fd, (struct sockaddr*) &sk->s_local,
50bdc6
+			   sizeof(sk->s_local));
50bdc6
+		if (err != 0) {
50bdc6
+			errsv = errno;
50bdc6
+			NL_DBG(4, "nl_connect(%p): bind() failed with %d\n", sk, errsv);
50bdc6
+			err = -nl_syserr2nlerr(errsv);
50bdc6
+			goto errout;
50bdc6
+		}
50bdc6
 	}
50bdc6
 
50bdc6
 	addrlen = sizeof(sk->s_local);
50bdc6
@@ -405,7 +453,7 @@ void nl_complete_msg(struct nl_sock *sk, struct nl_msg *msg)
50bdc6
 
50bdc6
 	nlh = nlmsg_hdr(msg);
50bdc6
 	if (nlh->nlmsg_pid == NL_AUTO_PORT)
50bdc6
-		nlh->nlmsg_pid = sk->s_local.nl_pid;
50bdc6
+		nlh->nlmsg_pid = nl_socket_get_local_port(sk);
50bdc6
 
50bdc6
 	if (nlh->nlmsg_seq == NL_AUTO_SEQ)
50bdc6
 		nlh->nlmsg_seq = sk->s_seq_next++;
50bdc6
diff --git a/lib/socket.c b/lib/socket.c
50bdc6
index f9e68ff..2d6a2d3 100644
50bdc6
--- a/lib/socket.c
50bdc6
+++ b/lib/socket.c
50bdc6
@@ -30,12 +30,15 @@
50bdc6
 #include "defs.h"
50bdc6
 
50bdc6
 #include <netlink-private/netlink.h>
50bdc6
+#include <netlink-private/socket.h>
50bdc6
 #include <netlink/netlink.h>
50bdc6
 #include <netlink/utils.h>
50bdc6
 #include <netlink/handlers.h>
50bdc6
 #include <netlink/msg.h>
50bdc6
 #include <netlink/attr.h>
50bdc6
 
50bdc6
+#define NOEXPORT    __attribute__ ((visibility ("hidden")))
50bdc6
+
50bdc6
 static int default_cb = NL_CB_DEFAULT;
50bdc6
 
50bdc6
 static void __init init_default_cb(void)
50bdc6
@@ -96,17 +99,61 @@ static uint32_t generate_local_port(void)
50bdc6
 static void release_local_port(uint32_t port)
50bdc6
 {
50bdc6
 	int nr;
50bdc6
+	uint32_t mask;
50bdc6
 
50bdc6
 	if (port == UINT32_MAX)
50bdc6
 		return;
50bdc6
-	
50bdc6
+
50bdc6
+	BUG_ON(port == 0);
50bdc6
+
50bdc6
 	nr = port >> 22;
50bdc6
+	mask = 1UL << (nr % 32);
50bdc6
+	nr /= 32;
50bdc6
 
50bdc6
 	nl_write_lock(&port_map_lock);
50bdc6
-	used_ports_map[nr / 32] &= ~(1 << (nr % 32));
50bdc6
+	BUG_ON((used_ports_map[nr] & mask) != mask);
50bdc6
+	used_ports_map[nr] &= ~mask;
50bdc6
 	nl_write_unlock(&port_map_lock);
50bdc6
 }
50bdc6
 
50bdc6
+/** \cond skip */
50bdc6
+NOEXPORT
50bdc6
+void _nl_socket_used_ports_release_all(const uint32_t *used_ports)
50bdc6
+{
50bdc6
+	int i;
50bdc6
+
50bdc6
+	for (i = 0; i < 32; i++) {
50bdc6
+		if (used_ports[i] != 0) {
50bdc6
+			nl_write_lock(&port_map_lock);
50bdc6
+			for (; i < 32; i++) {
50bdc6
+				BUG_ON((used_ports_map[i] & used_ports[i]) != used_ports[i]);
50bdc6
+				used_ports_map[i] &= ~(used_ports[i]);
50bdc6
+			}
50bdc6
+			nl_write_unlock(&port_map_lock);
50bdc6
+			return;
50bdc6
+		}
50bdc6
+	}
50bdc6
+}
50bdc6
+
50bdc6
+NOEXPORT
50bdc6
+void _nl_socket_used_ports_set(uint32_t *used_ports, uint32_t port)
50bdc6
+{
50bdc6
+	int nr;
50bdc6
+	int32_t mask;
50bdc6
+
50bdc6
+	nr = port >> 22;
50bdc6
+	mask = 1UL << (nr % 32);
50bdc6
+	nr /= 32;
50bdc6
+
50bdc6
+	/*
50bdc6
+	BUG_ON(port == UINT32_MAX || port == 0 || (getpid() & 0x3FFFFF) != (port & 0x3FFFFF));
50bdc6
+	BUG_ON(used_ports[nr] & mask);
50bdc6
+	*/
50bdc6
+
50bdc6
+	used_ports[nr] |= mask;
50bdc6
+}
50bdc6
+/** \endcond */
50bdc6
+
50bdc6
 /**
50bdc6
  * @name Allocation
50bdc6
  * @{
50bdc6
@@ -125,7 +172,9 @@ static struct nl_sock *__alloc_socket(struct nl_cb *cb)
50bdc6
 	sk->s_local.nl_family = AF_NETLINK;
50bdc6
 	sk->s_peer.nl_family = AF_NETLINK;
50bdc6
 	sk->s_seq_expect = sk->s_seq_next = time(0);
50bdc6
-	sk->s_local.nl_pid = generate_local_port();
50bdc6
+
50bdc6
+	/* the port is 0 (unspecified), meaning NL_OWN_PORT */
50bdc6
+	sk->s_flags = NL_OWN_PORT;
50bdc6
 
50bdc6
 	return sk;
50bdc6
 }
50bdc6
@@ -255,6 +304,28 @@ void nl_socket_enable_auto_ack(struct nl_sock *sk)
50bdc6
 
50bdc6
 /** @} */
50bdc6
 
50bdc6
+/** \cond skip */
50bdc6
+NOEXPORT
50bdc6
+int _nl_socket_is_local_port_unspecified(struct nl_sock *sk)
50bdc6
+{
50bdc6
+	return (sk->s_local.nl_pid == 0);
50bdc6
+}
50bdc6
+
50bdc6
+NOEXPORT
50bdc6
+uint32_t _nl_socket_generate_local_port_no_release(struct nl_sock *sk)
50bdc6
+{
50bdc6
+	uint32_t port;
50bdc6
+
50bdc6
+	/* reset the port to generate_local_port(), but do not release
50bdc6
+	 * the previously generated port. */
50bdc6
+
50bdc6
+	port = generate_local_port();
50bdc6
+	sk->s_flags &= ~NL_OWN_PORT;
50bdc6
+	sk->s_local.nl_pid = port;
50bdc6
+	return port;
50bdc6
+}
50bdc6
+/** \endcond */
50bdc6
+
50bdc6
 /**
50bdc6
  * @name Source Idenficiation
50bdc6
  * @{
50bdc6
@@ -262,6 +333,18 @@ void nl_socket_enable_auto_ack(struct nl_sock *sk)
50bdc6
 
50bdc6
 uint32_t nl_socket_get_local_port(const struct nl_sock *sk)
50bdc6
 {
50bdc6
+	if (sk->s_local.nl_pid == 0) {
50bdc6
+		/* modify the const argument sk. This is justified, because
50bdc6
+		 * nobody ever saw the local_port from externally. So, we
50bdc6
+		 * initilize it on first use.
50bdc6
+		 *
50bdc6
+		 * Note that this also means that you cannot call this function
50bdc6
+		 * from multiple threads without synchronization. But nl_sock
50bdc6
+		 * is not automatically threadsafe anyway, so the user is not
50bdc6
+		 * allowed to do that.
50bdc6
+		 */
50bdc6
+		return _nl_socket_generate_local_port_no_release((struct nl_sock *) sk);
50bdc6
+	}
50bdc6
 	return sk->s_local.nl_pid;
50bdc6
 }
50bdc6
 
50bdc6
@@ -270,27 +353,18 @@ uint32_t nl_socket_get_local_port(const struct nl_sock *sk)
50bdc6
  * @arg sk		Netlink socket.
50bdc6
  * @arg port		Local port identifier
50bdc6
  *
50bdc6
- * Assigns a local port identifier to the socket. If port is 0
50bdc6
- * a unique port identifier will be generated automatically.
50bdc6
+ * Assigns a local port identifier to the socket.
50bdc6
+ *
50bdc6
+ * If port is 0, the port is reset to 'unspecified' as it is after newly
50bdc6
+ * calling nl_socket_alloc().
50bdc6
+ * Unspecified means, that the port will be generated automatically later
50bdc6
+ * on first use (either on nl_socket_get_local_port() or nl_connect()).
50bdc6
  */
50bdc6
 void nl_socket_set_local_port(struct nl_sock *sk, uint32_t port)
50bdc6
 {
50bdc6
-	if (port == 0) {
50bdc6
-		port = generate_local_port(); 
50bdc6
-		/*
50bdc6
-		 * Release local port after generation of a new one to be
50bdc6
-		 * able to change local port using nl_socket_set_local_port(, 0)
50bdc6
-		 */
50bdc6
-		if (!(sk->s_flags & NL_OWN_PORT))
50bdc6
-			release_local_port(sk->s_local.nl_pid);
50bdc6
-		else
50bdc6
-			sk->s_flags &= ~NL_OWN_PORT;
50bdc6
-	} else  {
50bdc6
-		if (!(sk->s_flags & NL_OWN_PORT))
50bdc6
-			release_local_port(sk->s_local.nl_pid);
50bdc6
-		sk->s_flags |= NL_OWN_PORT;
50bdc6
-	}
50bdc6
-
50bdc6
+	if (!(sk->s_flags & NL_OWN_PORT))
50bdc6
+		release_local_port(sk->s_local.nl_pid);
50bdc6
+	sk->s_flags |= NL_OWN_PORT;
50bdc6
 	sk->s_local.nl_pid = port;
50bdc6
 }
50bdc6
 
50bdc6
diff --git a/lib/utils.c b/lib/utils.c
50bdc6
index 44350c3..5149e07 100644
50bdc6
--- a/lib/utils.c
50bdc6
+++ b/lib/utils.c
50bdc6
@@ -1138,7 +1138,7 @@ int nl_has_capability (int capability)
50bdc6
 			NL_CAPABILITY_ROUTE_BUILD_MSG_SET_SCOPE,
50bdc6
 			0,
50bdc6
 			0,
50bdc6
-			0,
50bdc6
+			NL_CAPABILITY_NL_CONNECT_RETRY_GENERATE_PORT_ON_ADDRINUSE,
50bdc6
 			0,
50bdc6
 			0,
50bdc6
 			0,
50bdc6
-- 
50bdc6
2.4.3
50bdc6
50bdc6
50bdc6
From 4177e716532b3263abb90c5a2afa6c60f37937e3 Mon Sep 17 00:00:00 2001
50bdc6
From: Thomas Haller <thaller@redhat.com>
50bdc6
Date: Wed, 9 Apr 2014 12:08:53 +0200
50bdc6
Subject: [PATCH 06/11] lib/socket: randomize the generated local port
50bdc6
50bdc6
Instead of always trying the same order of ports when
50bdc6
looking for an unused port, randomize the order (naively).
50bdc6
50bdc6
As libnl-1 uses the same function, it is likely that two applications
50bdc6
that are using both libraries generate the same ports. By chosing a
50bdc6
different order how to select the local port, the chances are smaller
50bdc6
for this to happen (however, it cannot avoid it entirely. The user
50bdc6
and/or libnl3 still has to cope with the situation, that somebody
50bdc6
else might already use the port).
50bdc6
50bdc6
Signed-off-by: Thomas Haller <thaller@redhat.com>
50bdc6
(cherry picked from commit 1f734a8f892abcd3f81637df4a089155aca1b66a)
50bdc6
---
50bdc6
 lib/socket.c | 29 ++++++++++++++++++++++++++---
50bdc6
 1 file changed, 26 insertions(+), 3 deletions(-)
50bdc6
50bdc6
diff --git a/lib/socket.c b/lib/socket.c
50bdc6
index 2d6a2d3..01cf2a2 100644
50bdc6
--- a/lib/socket.c
50bdc6
+++ b/lib/socket.c
50bdc6
@@ -64,16 +64,39 @@ static NL_RW_LOCK(port_map_lock);
50bdc6
 
50bdc6
 static uint32_t generate_local_port(void)
50bdc6
 {
50bdc6
-	int i, n;
50bdc6
+	int i, j, n, m;
50bdc6
+	static uint16_t idx_state = 0;
50bdc6
 	uint32_t pid = getpid() & 0x3FFFFF;
50bdc6
 
50bdc6
 	nl_write_lock(&port_map_lock);
50bdc6
 
50bdc6
-	for (i = 0; i < 32; i++) {
50bdc6
+	if (idx_state == 0) {
50bdc6
+		uint32_t t = time(NULL);
50bdc6
+
50bdc6
+		/* from time to time (on average each 2^15 calls), the idx_state will
50bdc6
+		 * be zero again. No problem, just "seed" anew with time(). */
50bdc6
+		idx_state = t ^ (t >> 16) ^ 0x3047;
50bdc6
+	} else
50bdc6
+		idx_state = idx_state + 20011; /* add prime number */
50bdc6
+
50bdc6
+	i = idx_state >> 5;
50bdc6
+	n = idx_state;
50bdc6
+	for (j = 0; j < 32; j++) {
50bdc6
+		/* walk the index somewhat randomized, with always leaving the block
50bdc6
+		 * #0 as last. The reason is that libnl-1 will start at block #0,
50bdc6
+		 * so just leave the first 32 ports preferably for libnl-1 owned sockets
50bdc6
+		 * (this is relevant only if the applications ends up using both versions
50bdc6
+		 * of the library and doesn't hurt otherwise). */
50bdc6
+		if (j == 31)
50bdc6
+			i = 0;
50bdc6
+		else
50bdc6
+			i = (((i-1) + 7) % 31) + 1;
50bdc6
+
50bdc6
 		if (used_ports_map[i] == 0xFFFFFFFF)
50bdc6
 			continue;
50bdc6
 
50bdc6
-		for (n = 0; n < 32; n++) {
50bdc6
+		for (m = 0; m < 32; m++) {
50bdc6
+			n = (n + 13) % 32;
50bdc6
 			if (1UL & (used_ports_map[i] >> n))
50bdc6
 				continue;
50bdc6
 
50bdc6
-- 
50bdc6
2.4.3
50bdc6
50bdc6
50bdc6
From 1e7b7e5472fd3ee2ba69d2029bac02e4cf4148a1 Mon Sep 17 00:00:00 2001
50bdc6
From: Thomas Haller <thaller@redhat.com>
50bdc6
Date: Thu, 5 Mar 2015 08:46:31 +0100
50bdc6
Subject: [PATCH 07/11] lib/socket: remove NL_SOCK_BUFSIZE_SET socket flag
50bdc6
50bdc6
The flag was not actually used.
50bdc6
50bdc6
NL_SOCK_BUFSIZE_SET was only set by nl_socket_set_buffer_size().
50bdc6
Note that you can only call nl_socket_set_buffer_size() on a socket that
50bdc6
is already connected via nl_connect().
50bdc6
50bdc6
On first call, nl_connect() would always see NL_SOCK_BUFSIZE_SET unset, and
50bdc6
call nl_socket_set_buffer_size().
50bdc6
50bdc6
Since the flag was never unset, when trying to connect a socket a second
50bdc6
time, we would not set the buffer size again. Which was a bug.
50bdc6
50bdc6
Signed-off-by: Thomas Haller <thaller@redhat.com>
50bdc6
(cherry picked from commit 15824e42730980132a9e52d0c9d6929808e5ae78)
50bdc6
---
50bdc6
 include/netlink-private/types.h | 1 -
50bdc6
 lib/nl.c                        | 8 +++-----
50bdc6
 lib/socket.c                    | 2 --
50bdc6
 3 files changed, 3 insertions(+), 8 deletions(-)
50bdc6
50bdc6
diff --git a/include/netlink-private/types.h b/include/netlink-private/types.h
50bdc6
index 72570c4..70b95c1 100644
50bdc6
--- a/include/netlink-private/types.h
50bdc6
+++ b/include/netlink-private/types.h
50bdc6
@@ -19,7 +19,6 @@
50bdc6
 #include <netlink/route/route.h>
50bdc6
 #include <netlink-private/route/tc-api.h>
50bdc6
 
50bdc6
-#define NL_SOCK_BUFSIZE_SET	(1<<0)
50bdc6
 #define NL_SOCK_PASSCRED	(1<<1)
50bdc6
 #define NL_OWN_PORT		(1<<2)
50bdc6
 #define NL_MSG_PEEK		(1<<3)
50bdc6
diff --git a/lib/nl.c b/lib/nl.c
50bdc6
index 37065d4..69d5f8f 100644
50bdc6
--- a/lib/nl.c
50bdc6
+++ b/lib/nl.c
50bdc6
@@ -114,11 +114,9 @@ int nl_connect(struct nl_sock *sk, int protocol)
50bdc6
 		goto errout;
50bdc6
 	}
50bdc6
 
50bdc6
-	if (!(sk->s_flags & NL_SOCK_BUFSIZE_SET)) {
50bdc6
-		err = nl_socket_set_buffer_size(sk, 0, 0);
50bdc6
-		if (err < 0)
50bdc6
-			goto errout;
50bdc6
-	}
50bdc6
+	err = nl_socket_set_buffer_size(sk, 0, 0);
50bdc6
+	if (err < 0)
50bdc6
+		goto errout;
50bdc6
 
50bdc6
 	if (_nl_socket_is_local_port_unspecified (sk)) {
50bdc6
 		uint32_t port;
50bdc6
diff --git a/lib/socket.c b/lib/socket.c
50bdc6
index 01cf2a2..4741719 100644
50bdc6
--- a/lib/socket.c
50bdc6
+++ b/lib/socket.c
50bdc6
@@ -692,8 +692,6 @@ int nl_socket_set_buffer_size(struct nl_sock *sk, int rxbuf, int txbuf)
50bdc6
 	if (err < 0)
50bdc6
 		return -nl_syserr2nlerr(errno);
50bdc6
 
50bdc6
-	sk->s_flags |= NL_SOCK_BUFSIZE_SET;
50bdc6
-
50bdc6
 	return 0;
50bdc6
 }
50bdc6
 
50bdc6
-- 
50bdc6
2.4.3
50bdc6
50bdc6
50bdc6
From 38a6d5589e7d0cfe44331687ad76271f35ab7e12 Mon Sep 17 00:00:00 2001
50bdc6
From: Thomas Haller <thaller@redhat.com>
50bdc6
Date: Thu, 5 Mar 2015 10:50:04 +0100
50bdc6
Subject: [PATCH 08/11] lib/nl: preserve s_local if nl_connect() fails
50bdc6
50bdc6
s_local.nl_pid is used to track the generated port unless NL_OWN_PORT is set.
50bdc6
Ensure that getsockname() doesn't overwrite the value and possibly reset
50bdc6
the local port manually to release the generated port.
50bdc6
50bdc6
Signed-off-by: Thomas Haller <thaller@redhat.com>
50bdc6
(cherry picked from commit 9614acf4c4354892b5b734cace4778acfc019999)
50bdc6
---
50bdc6
 lib/nl.c | 24 ++++++++++++++++--------
50bdc6
 1 file changed, 16 insertions(+), 8 deletions(-)
50bdc6
50bdc6
diff --git a/lib/nl.c b/lib/nl.c
50bdc6
index 69d5f8f..b7a9ab4 100644
50bdc6
--- a/lib/nl.c
50bdc6
+++ b/lib/nl.c
50bdc6
@@ -98,6 +98,7 @@ int nl_connect(struct nl_sock *sk, int protocol)
50bdc6
 	int err, flags = 0;
50bdc6
 	int errsv;
50bdc6
 	socklen_t addrlen;
50bdc6
+	struct sockaddr_nl local = { 0 };
50bdc6
 
50bdc6
 #ifdef SOCK_CLOEXEC
50bdc6
 	flags |= SOCK_CLOEXEC;
50bdc6
@@ -159,32 +160,39 @@ int nl_connect(struct nl_sock *sk, int protocol)
50bdc6
 		}
50bdc6
 	}
50bdc6
 
50bdc6
-	addrlen = sizeof(sk->s_local);
50bdc6
-	err = getsockname(sk->s_fd, (struct sockaddr *) &sk->s_local,
50bdc6
+	addrlen = sizeof(local);
50bdc6
+	err = getsockname(sk->s_fd, (struct sockaddr *) &local,
50bdc6
 			  &addrlen);
50bdc6
 	if (err < 0) {
50bdc6
 		err = -nl_syserr2nlerr(errno);
50bdc6
 		goto errout;
50bdc6
 	}
50bdc6
 
50bdc6
-	if (addrlen != sizeof(sk->s_local)) {
50bdc6
+	if (addrlen != sizeof(local)) {
50bdc6
 		err = -NLE_NOADDR;
50bdc6
 		goto errout;
50bdc6
 	}
50bdc6
 
50bdc6
-	if (sk->s_local.nl_family != AF_NETLINK) {
50bdc6
+	if (local.nl_family != AF_NETLINK) {
50bdc6
 		err = -NLE_AF_NOSUPPORT;
50bdc6
 		goto errout;
50bdc6
 	}
50bdc6
 
50bdc6
+	if (sk->s_local.nl_pid != local.nl_pid) {
50bdc6
+		/* strange, the port id is not as expected. Set the local
50bdc6
+		 * port id to release a possibly generated port and un-own
50bdc6
+		 * it. */
50bdc6
+		nl_socket_set_local_port (sk, local.nl_pid);
50bdc6
+	}
50bdc6
+	sk->s_local = local;
50bdc6
 	sk->s_proto = protocol;
50bdc6
 
50bdc6
 	return 0;
50bdc6
 errout:
50bdc6
-        if (sk->s_fd != -1) {
50bdc6
-    		close(sk->s_fd);
50bdc6
-    		sk->s_fd = -1;
50bdc6
-        }
50bdc6
+	if (sk->s_fd != -1) {
50bdc6
+		close(sk->s_fd);
50bdc6
+		sk->s_fd = -1;
50bdc6
+	}
50bdc6
 
50bdc6
 	return err;
50bdc6
 }
50bdc6
-- 
50bdc6
2.4.3
50bdc6
50bdc6
50bdc6
From 3c00a3b7d518cee0ac2092487f38ff2e75b8728e Mon Sep 17 00:00:00 2001
50bdc6
From: Thomas Haller <thaller@redhat.com>
50bdc6
Date: Fri, 10 Jul 2015 14:58:50 +0200
50bdc6
Subject: [PATCH 09/11] socket: clear port when unable to generate local port
50bdc6
50bdc6
When running out of local ports, _nl_socket_generate_local_port_no_release()
50bdc6
would leave the socket with port UINT32_MAX. That means if nl_connect()
50bdc6
fails due to out-of-ports, it would leave the port id assigned to an
50bdc6
invalid port and the socket instance was not re-usable until the user
50bdc6
called nl_socket_set_local_port(). Fix that by resetting the local port
50bdc6
to zero.
50bdc6
50bdc6
Thereby, also change generate_local_port() to return zero when
50bdc6
running out of ports. zero is a more natural value for ~no port found~.
50bdc6
It also matches the port that _nl_socket_generate_local_port_no_release()
50bdc6
uses when failing to generate a port.
50bdc6
50bdc6
Also ensure that zero cannot be returned as valid port by generate_local_port().
50bdc6
Arguably, that would only be possible if (getpid() & 0x3FFFFF)
50bdc6
returns zero. Just be extra cautious.
50bdc6
50bdc6
Signed-off-by: Thomas Haller <thaller@redhat.com>
50bdc6
(cherry picked from commit f78c3e82398a505ccf7e297b4021f23559ad8977)
50bdc6
---
50bdc6
 lib/nl.c     |  2 +-
50bdc6
 lib/socket.c | 30 ++++++++++++++++++++++--------
50bdc6
 2 files changed, 23 insertions(+), 9 deletions(-)
50bdc6
50bdc6
diff --git a/lib/nl.c b/lib/nl.c
50bdc6
index b7a9ab4..20de342 100644
50bdc6
--- a/lib/nl.c
50bdc6
+++ b/lib/nl.c
50bdc6
@@ -126,7 +126,7 @@ int nl_connect(struct nl_sock *sk, int protocol)
50bdc6
 		while (1) {
50bdc6
 			port = _nl_socket_generate_local_port_no_release(sk);
50bdc6
 
50bdc6
-			if (port == UINT32_MAX) {
50bdc6
+			if (port == 0) {
50bdc6
 				NL_DBG(4, "nl_connect(%p): no more unused local ports.\n", sk);
50bdc6
 				_nl_socket_used_ports_release_all(used_ports);
50bdc6
 				err = -NLE_EXIST;
50bdc6
diff --git a/lib/socket.c b/lib/socket.c
50bdc6
index 4741719..4f05d09 100644
50bdc6
--- a/lib/socket.c
50bdc6
+++ b/lib/socket.c
50bdc6
@@ -108,7 +108,9 @@ static uint32_t generate_local_port(void)
50bdc6
 
50bdc6
 			nl_write_unlock(&port_map_lock);
50bdc6
 
50bdc6
-			return pid + (((uint32_t)n) << 22);
50bdc6
+			/* ensure we don't return zero. */
50bdc6
+			pid = pid + (((uint32_t)n) << 22);
50bdc6
+			return pid ? pid : 1024;
50bdc6
 		}
50bdc6
 	}
50bdc6
 
50bdc6
@@ -116,7 +118,7 @@ static uint32_t generate_local_port(void)
50bdc6
 
50bdc6
 	/* Out of sockets in our own PID namespace, what to do? FIXME */
50bdc6
 	NL_DBG(1, "Warning: Ran out of unique local port namespace\n");
50bdc6
-	return UINT32_MAX;
50bdc6
+	return 0;
50bdc6
 }
50bdc6
 
50bdc6
 static void release_local_port(uint32_t port)
50bdc6
@@ -124,9 +126,6 @@ static void release_local_port(uint32_t port)
50bdc6
 	int nr;
50bdc6
 	uint32_t mask;
50bdc6
 
50bdc6
-	if (port == UINT32_MAX)
50bdc6
-		return;
50bdc6
-
50bdc6
 	BUG_ON(port == 0);
50bdc6
 
50bdc6
 	nr = port >> 22;
50bdc6
@@ -169,7 +168,7 @@ void _nl_socket_used_ports_set(uint32_t *used_ports, uint32_t port)
50bdc6
 	nr /= 32;
50bdc6
 
50bdc6
 	/*
50bdc6
-	BUG_ON(port == UINT32_MAX || port == 0 || (getpid() & 0x3FFFFF) != (port & 0x3FFFFF));
50bdc6
+	BUG_ON(port == 0 || (getpid() & 0x3FFFFF) != (port & 0x3FFFFF));
50bdc6
 	BUG_ON(used_ports[nr] & mask);
50bdc6
 	*/
50bdc6
 
50bdc6
@@ -343,8 +342,13 @@ uint32_t _nl_socket_generate_local_port_no_release(struct nl_sock *sk)
50bdc6
 	 * the previously generated port. */
50bdc6
 
50bdc6
 	port = generate_local_port();
50bdc6
-	sk->s_flags &= ~NL_OWN_PORT;
50bdc6
 	sk->s_local.nl_pid = port;
50bdc6
+	if (port == 0) {
50bdc6
+		/* failed to find an unsed port. Restore the socket to have an
50bdc6
+		 * unspecified port. */
50bdc6
+		sk->s_flags |= NL_OWN_PORT;
50bdc6
+	} else
50bdc6
+		sk->s_flags &= ~NL_OWN_PORT;
50bdc6
 	return port;
50bdc6
 }
50bdc6
 /** \endcond */
50bdc6
@@ -357,6 +361,8 @@ uint32_t _nl_socket_generate_local_port_no_release(struct nl_sock *sk)
50bdc6
 uint32_t nl_socket_get_local_port(const struct nl_sock *sk)
50bdc6
 {
50bdc6
 	if (sk->s_local.nl_pid == 0) {
50bdc6
+		struct nl_sock *sk_mutable = (struct nl_sock *) sk;
50bdc6
+
50bdc6
 		/* modify the const argument sk. This is justified, because
50bdc6
 		 * nobody ever saw the local_port from externally. So, we
50bdc6
 		 * initilize it on first use.
50bdc6
@@ -366,7 +372,15 @@ uint32_t nl_socket_get_local_port(const struct nl_sock *sk)
50bdc6
 		 * is not automatically threadsafe anyway, so the user is not
50bdc6
 		 * allowed to do that.
50bdc6
 		 */
50bdc6
-		return _nl_socket_generate_local_port_no_release((struct nl_sock *) sk);
50bdc6
+		sk_mutable->s_local.nl_pid = generate_local_port();
50bdc6
+		if (sk_mutable->s_local.nl_pid == 0) {
50bdc6
+			/* could not generate a local port. Assign UINT32_MAX to preserve
50bdc6
+			 * backward compatibility. A user who cares can clear that anyway
50bdc6
+			 * with nl_socket_set_local_port(). */
50bdc6
+			sk_mutable->s_local.nl_pid = UINT32_MAX;
50bdc6
+			sk_mutable->s_flags |= NL_OWN_PORT;
50bdc6
+		} else
50bdc6
+			sk_mutable->s_flags &= ~NL_OWN_PORT;
50bdc6
 	}
50bdc6
 	return sk->s_local.nl_pid;
50bdc6
 }
50bdc6
-- 
50bdc6
2.4.3
50bdc6
50bdc6
50bdc6
From eb5e052347de18e1133d3cbf507e31d05cd5db6e Mon Sep 17 00:00:00 2001
50bdc6
From: Thomas Haller <thaller@redhat.com>
50bdc6
Date: Fri, 10 Jul 2015 14:58:51 +0200
50bdc6
Subject: [PATCH 10/11] socket: add fallback for nl_connect() by trying to bind
50bdc6
 to unspecified local port
50bdc6
50bdc6
libnl allows the user to explicitly set the local port before connecting
50bdc6
the socket. A more convenient way is to leave the local port unspecified
50bdc6
and let libnl generate a port id.
50bdc6
50bdc6
As it is, generate_local_port() would try at most 1024 ports, that
50bdc6
means if a user tries to connect more sockets, the automatism will
50bdc6
fail.
50bdc6
50bdc6
Kernel also supports choosing the local port itself (via netlink_autobind()).
50bdc6
So, this could be fixed by always leaving the port unspecified and let
50bdc6
kernel decide on the port. For that we could entirely drop generate_local_port().
50bdc6
50bdc6
There are however problems with that:
50bdc6
50bdc6
  - it is unclear why generate_local_port() was even introduced in the
50bdc6
    first place instead of always relying kernel. This code already
50bdc6
    appeared in libnl-1, so maybe there was a good reason for it or
50bdc6
    it is necessary on some kernel versions.
50bdc6
50bdc6
  - The deprecated libnl-1 library also uses a form of generate_local_port().
50bdc6
    Its first guess would always be getpid(), but the problem is that
50bdc6
    it would not retry on EADDRINUSE. Currently libnl-3 generates ports in
50bdc6
    a different sequence and will not generate a conflicting port (until it
50bdc6
    already exhausted 1016 other ports).
50bdc6
    Hence, currently if your application uses libnl1 and libnl3
50bdc6
    together, the automatism might just work without conflicts
50bdc6
    (commit 1f734a8f892abcd3f81637df4a089155aca1b66a).
50bdc6
    Accidently, kernel/netlink_autobind() also first tries the process
50bdc6
    id as port. That means, if we change libnl-3 to leave the decision
50bdc6
    to kernel, and
50bdc6
      - the application connects sockets both via libnl-1 and libnl-3
50bdc6
      - and the libnl-3 socket happens to connect first
50bdc6
    then the libnl-1 socket would fail to connect without retrying
50bdc6
    another port.
50bdc6
50bdc6
  - Removing generate_local_port() entirely changes behavior in the
50bdc6
    following case:
50bdc6
50bdc6
        sk = nl_socket_alloc();
50bdc6
        /* accessing local port before connecting the socket used to
50bdc6
         * freeze the local port to the generated value. */
50bdc6
        port = nl_socket_get_local_port(sk);
50bdc6
        nl_connect(sk, NETLINK_...);
50bdc6
50bdc6
Maybe the issues are minor and it would simplify the code just to get
50bdc6
rid of the cruft. But instead fix the issue without changing behavior.
50bdc6
Just keep trying with generate_local_port() first, before fallback to
50bdc6
kernel.
50bdc6
50bdc6
Reported-by: Julien Courtat <julien.courtat@6wind.com>
50bdc6
Signed-off-by: Thomas Haller <thaller@redhat.com>
50bdc6
50bdc6
http://lists.infradead.org/pipermail/libnl/2015-June/001889.html
50bdc6
(cherry picked from commit 96e1e5bdc2e803700055395cc3c428fa2525d1ca)
50bdc6
---
50bdc6
 lib/nl.c     | 29 ++++++++++++++++++-----------
50bdc6
 lib/socket.c |  3 ---
50bdc6
 2 files changed, 18 insertions(+), 14 deletions(-)
50bdc6
50bdc6
diff --git a/lib/nl.c b/lib/nl.c
50bdc6
index 20de342..bbd1c14 100644
50bdc6
--- a/lib/nl.c
50bdc6
+++ b/lib/nl.c
50bdc6
@@ -99,6 +99,7 @@ int nl_connect(struct nl_sock *sk, int protocol)
50bdc6
 	int errsv;
50bdc6
 	socklen_t addrlen;
50bdc6
 	struct sockaddr_nl local = { 0 };
50bdc6
+	int try_bind = 1;
50bdc6
 
50bdc6
 #ifdef SOCK_CLOEXEC
50bdc6
 	flags |= SOCK_CLOEXEC;
50bdc6
@@ -122,20 +123,26 @@ int nl_connect(struct nl_sock *sk, int protocol)
50bdc6
 	if (_nl_socket_is_local_port_unspecified (sk)) {
50bdc6
 		uint32_t port;
50bdc6
 		uint32_t used_ports[32] = { 0 };
50bdc6
+		int ntries = 0;
50bdc6
 
50bdc6
 		while (1) {
50bdc6
+			if (ntries++ > 5) {
50bdc6
+				/* try only a few times. We hit this only if many ports are already in
50bdc6
+				 * use but allocated *outside* libnl/generate_local_port(). */
50bdc6
+				nl_socket_set_local_port (sk, 0);
50bdc6
+				break;
50bdc6
+			}
50bdc6
+
50bdc6
 			port = _nl_socket_generate_local_port_no_release(sk);
50bdc6
+			if (port == 0)
50bdc6
+				break;
50bdc6
 
50bdc6
-			if (port == 0) {
50bdc6
-				NL_DBG(4, "nl_connect(%p): no more unused local ports.\n", sk);
50bdc6
-				_nl_socket_used_ports_release_all(used_ports);
50bdc6
-				err = -NLE_EXIST;
50bdc6
-				goto errout;
50bdc6
-			}
50bdc6
 			err = bind(sk->s_fd, (struct sockaddr*) &sk->s_local,
50bdc6
 				   sizeof(sk->s_local));
50bdc6
-			if (err == 0)
50bdc6
+			if (err == 0) {
50bdc6
+				try_bind = 0;
50bdc6
 				break;
50bdc6
+			}
50bdc6
 
50bdc6
 			errsv = errno;
50bdc6
 			if (errsv == EADDRINUSE) {
50bdc6
@@ -149,7 +156,8 @@ int nl_connect(struct nl_sock *sk, int protocol)
50bdc6
 			}
50bdc6
 		}
50bdc6
 		_nl_socket_used_ports_release_all(used_ports);
50bdc6
-	} else {
50bdc6
+	}
50bdc6
+	if (try_bind) {
50bdc6
 		err = bind(sk->s_fd, (struct sockaddr*) &sk->s_local,
50bdc6
 			   sizeof(sk->s_local));
50bdc6
 		if (err != 0) {
50bdc6
@@ -179,9 +187,8 @@ int nl_connect(struct nl_sock *sk, int protocol)
50bdc6
 	}
50bdc6
 
50bdc6
 	if (sk->s_local.nl_pid != local.nl_pid) {
50bdc6
-		/* strange, the port id is not as expected. Set the local
50bdc6
-		 * port id to release a possibly generated port and un-own
50bdc6
-		 * it. */
50bdc6
+		/* The port id is different. That can happen if the port id was zero
50bdc6
+		 * and kernel assigned a local port. */
50bdc6
 		nl_socket_set_local_port (sk, local.nl_pid);
50bdc6
 	}
50bdc6
 	sk->s_local = local;
50bdc6
diff --git a/lib/socket.c b/lib/socket.c
50bdc6
index 4f05d09..6e2aaf5 100644
50bdc6
--- a/lib/socket.c
50bdc6
+++ b/lib/socket.c
50bdc6
@@ -115,9 +115,6 @@ static uint32_t generate_local_port(void)
50bdc6
 	}
50bdc6
 
50bdc6
 	nl_write_unlock(&port_map_lock);
50bdc6
-
50bdc6
-	/* Out of sockets in our own PID namespace, what to do? FIXME */
50bdc6
-	NL_DBG(1, "Warning: Ran out of unique local port namespace\n");
50bdc6
 	return 0;
50bdc6
 }
50bdc6
 
50bdc6
-- 
50bdc6
2.4.3
50bdc6
50bdc6
50bdc6
From 9d7d3895fe979ccffab350d2f71793982b060c8b Mon Sep 17 00:00:00 2001
50bdc6
From: Thomas Haller <thaller@redhat.com>
50bdc6
Date: Mon, 24 Aug 2015 17:57:16 +0200
50bdc6
Subject: [PATCH 11/11] socket: fix assertion in nl_connect() when all ports
50bdc6
 are already in use
50bdc6
50bdc6
When generating a port fails a few times (because they are already in used
50bdc6
outside of libnl's knowledge), we would back off generating a local
50bdc6
port and instead let kernel decide.
50bdc6
50bdc6
There was however a bug in nl_connect() that caused an assertion:
50bdc6
50bdc6
    BUG at file position socket.c:147:_nl_socket_used_ports_release_all
50bdc6
    app: socket.c:147: _nl_socket_used_ports_release_all: Assertion `0' failed.
50bdc6
50bdc6
Fixes: 96e1e5bdc2e803700055395cc3c428fa2525d1ca
50bdc6
(cherry picked from commit eaa75b7c7d3e6a4df1a2e7591ae295acfae3f73e)
50bdc6
---
50bdc6
 include/netlink-private/socket.h | 2 +-
50bdc6
 lib/nl.c                         | 4 ++--
50bdc6
 lib/socket.c                     | 7 +++++--
50bdc6
 3 files changed, 8 insertions(+), 5 deletions(-)
50bdc6
50bdc6
diff --git a/include/netlink-private/socket.h b/include/netlink-private/socket.h
50bdc6
index 86a440c..9ceecfd 100644
50bdc6
--- a/include/netlink-private/socket.h
50bdc6
+++ b/include/netlink-private/socket.h
50bdc6
@@ -19,7 +19,7 @@ extern "C" {
50bdc6
 #endif
50bdc6
 
50bdc6
 int _nl_socket_is_local_port_unspecified (struct nl_sock *sk);
50bdc6
-uint32_t _nl_socket_generate_local_port_no_release(struct nl_sock *sk);
50bdc6
+uint32_t _nl_socket_set_local_port_no_release(struct nl_sock *sk, int generate_other);
50bdc6
 
50bdc6
 void _nl_socket_used_ports_release_all(const uint32_t *used_ports);
50bdc6
 void _nl_socket_used_ports_set(uint32_t *used_ports, uint32_t port);
50bdc6
diff --git a/lib/nl.c b/lib/nl.c
50bdc6
index bbd1c14..db000a3 100644
50bdc6
--- a/lib/nl.c
50bdc6
+++ b/lib/nl.c
50bdc6
@@ -129,11 +129,11 @@ int nl_connect(struct nl_sock *sk, int protocol)
50bdc6
 			if (ntries++ > 5) {
50bdc6
 				/* try only a few times. We hit this only if many ports are already in
50bdc6
 				 * use but allocated *outside* libnl/generate_local_port(). */
50bdc6
-				nl_socket_set_local_port (sk, 0);
50bdc6
+				_nl_socket_set_local_port_no_release (sk, 0);
50bdc6
 				break;
50bdc6
 			}
50bdc6
 
50bdc6
-			port = _nl_socket_generate_local_port_no_release(sk);
50bdc6
+			port = _nl_socket_set_local_port_no_release(sk, 1);
50bdc6
 			if (port == 0)
50bdc6
 				break;
50bdc6
 
50bdc6
diff --git a/lib/socket.c b/lib/socket.c
50bdc6
index 6e2aaf5..d3eab60 100644
50bdc6
--- a/lib/socket.c
50bdc6
+++ b/lib/socket.c
50bdc6
@@ -331,14 +331,17 @@ int _nl_socket_is_local_port_unspecified(struct nl_sock *sk)
50bdc6
 }
50bdc6
 
50bdc6
 NOEXPORT
50bdc6
-uint32_t _nl_socket_generate_local_port_no_release(struct nl_sock *sk)
50bdc6
+uint32_t _nl_socket_set_local_port_no_release(struct nl_sock *sk, int generate_other)
50bdc6
 {
50bdc6
 	uint32_t port;
50bdc6
 
50bdc6
 	/* reset the port to generate_local_port(), but do not release
50bdc6
 	 * the previously generated port. */
50bdc6
 
50bdc6
-	port = generate_local_port();
50bdc6
+	if (generate_other)
50bdc6
+		port = generate_local_port();
50bdc6
+	else
50bdc6
+		port = 0;
50bdc6
 	sk->s_local.nl_pid = port;
50bdc6
 	if (port == 0) {
50bdc6
 		/* failed to find an unsed port. Restore the socket to have an
50bdc6
-- 
50bdc6
2.4.3
50bdc6