From sergiy.lozovsky at gmail.com  Mon Jun  1 17:58:50 2015
From: sergiy.lozovsky at gmail.com (Sergiy Lozovsky)
Date: Mon, 1 Jun 2015 17:58:50 -0700
Subject: message attribute mismatch
Message-ID: <CAK-1WHiMSJ_0K1GUXYbRv4UjgB8emNoEWd2aAeT58SXHD6W6iw@mail.gmail.com>

Hi,

it looks like libnl-3.2.25 doesn't support following attribute types:
NLA_NUL_STRING and NLA_BINARY. These types are supported by kernel,
Python Netlink packages, etc.

We have a kernel module and Python scripts that use these types. Is
there any workaround? What is the best way to handle that?

Thanks,

Sergiy.


From sebastian.kricner at tuxwave.net  Wed Jun  3 16:19:54 2015
From: sebastian.kricner at tuxwave.net (Sebastian Kricner)
Date: Thu, 4 Jun 2015 01:19:54 +0200
Subject: Weird problem IP change monitoring
Message-ID: <20150603231954.GA14584@cluster-node1.tuxwave.net>


Hello,

i have written a small C program to monitor IPv4 address changes with
libnl and generally it works. But sometimes it delivers the IP address
of a different interface alltough i do a strcmp() on interface name.

Attached the program.

What might cause the problem?

Regards

Sebastian Kricner


-- 
http://tuxwave.net -- the difference to think makes it real!
-------------- next part --------------
A non-text attachment was scrubbed...
Name: ipchange.c
Type: text/x-c
Size: 2841 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/libnl/attachments/20150604/4ecd0b5b/attachment.bin>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/libnl/attachments/20150604/4ecd0b5b/attachment.sig>

From hakke_007 at gmx.de  Thu Jun  4 05:43:58 2015
From: hakke_007 at gmx.de (Thomas Egerer)
Date: Thu, 04 Jun 2015 14:43:58 +0200
Subject: [PATCH] lib: Return error if an incomplete message was read
Message-ID: <5570480E.6070804@gmx.de>


If recvmsg indicates that the message read was truncated libnl retries
to read the complete message after increasing the message buffer. This
only works if the message flags MSG_PEEK | MSG_TRUNC are set. If
NL_MSG_PEEK is not enabled on the nl_sock structure, flags are left
empty and the rest of the truncated message is discarded, hence a
subsequent recvmsg returns the next message (in case of a multipart
message, the NLMSG_DONE) is read and returned.
This patch aborts message processing if the message was truncated and
teh NL_MSG_PEEK flags was not activated for the nl_sock structure.

Signed-off-by: Thomas Egerer <hakke_007 at gmx.de>
---
Hello *,

I recently discovered a flaw in your library when reading large amounts
of data (larger than the 4096 byte buffer) without the NL_MSG_PEEK flag
set on the nl-socket. In this case the whole message is discarded while
the code suggests a reread. Example code for reproduction can be found
in [1].

[1] http://pastebin.com/hB1SAPrX

 lib/nl.c | 7 +++++++
 1 file changed, 7 insertions(+)


-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0001-lib-Return-error-if-an-incomplete-message-was-read.patch
Type: text/x-patch
Size: 482 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/libnl/attachments/20150604/7657a621/attachment.bin>

From julien.courtat at 6wind.com  Thu Jun  4 08:07:15 2015
From: julien.courtat at 6wind.com (Julien Courtat)
Date: Thu,  4 Jun 2015 17:07:15 +0200
Subject: [PATCH 0/2] increase maximum number of possible opened sockets per
 application
Message-ID: <1433430437-19376-1-git-send-email-julien.courtat@6wind.com>


Hello,

The current libnl 3.2.26 allows to create 1024 sockets at maximum per application.
This value is too short on systems using lots of netns.
For example, a program that needs 8 sockets per netns is limited to 128 netns.

The following two patches propose to increase the maximum number of possible opened
socket per program with a single parameter NL_BITS_FOR_PID.
Since a portid is a bitmask split between a pid and a random number, number of bits
dedicated to pid should be decreased to allow more bits for the possible random value
and de facto increase the possible number of opened sockets per application.

First patch proposes to separate values that handle the size of the used_port_map[]
from the values inside each entry of this table, which were a bit messy since they were
both hardcoded to 32.
The second patch, only set the proposed value for NL_BITS_FOR_PID to 18, which allows
16384 opened sockets on systems with max pid of 262144.

Julien


From julien.courtat at 6wind.com  Thu Jun  4 08:07:17 2015
From: julien.courtat at 6wind.com (Julien Courtat)
Date: Thu,  4 Jun 2015 17:07:17 +0200
Subject: [PATCH 2/2] socket: increase number of opened ports per application
In-Reply-To: <1433430437-19376-1-git-send-email-julien.courtat@6wind.com>
References: <1433430437-19376-1-git-send-email-julien.courtat@6wind.com>
Message-ID: <1433430437-19376-3-git-send-email-julien.courtat@6wind.com>

Decrease number of bits allocated to pid in port bitfield has the
consequence to increase maximum number of ports opened per application.
As a consequence, used_port_map[] table size is increased
accordingly.

Signed-off-by: Julien Courtat <julien.courtat at 6wind.com>
---
 include/netlink-private/socket.h |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/netlink-private/socket.h b/include/netlink-private/socket.h
index 62c7d4b..6c374cc 100644
--- a/include/netlink-private/socket.h
+++ b/include/netlink-private/socket.h
@@ -18,7 +18,7 @@
 extern "C" {
 #endif
 
-#define NL_BITS_FOR_PID 22
+#define NL_BITS_FOR_PID 18
 /* there are 32 - NL_BITS_FOR_PID left for the port id per application,
  * divided by 32 (>>5) to get used_port_map max table size */
 #define NL_MAX_USED_PORT (1 << (32 - NL_BITS_FOR_PID - 5))
-- 
1.7.10.4



From julien.courtat at 6wind.com  Thu Jun  4 08:07:16 2015
From: julien.courtat at 6wind.com (Julien Courtat)
Date: Thu,  4 Jun 2015 17:07:16 +0200
Subject: [PATCH 1/2] socket: set NL_MAX_USED_PORT,
 NL_BITS_FOR_PID and NR_BITS macros
In-Reply-To: <1433430437-19376-1-git-send-email-julien.courtat@6wind.com>
References: <1433430437-19376-1-git-send-email-julien.courtat@6wind.com>
Message-ID: <1433430437-19376-2-git-send-email-julien.courtat@6wind.com>

Instead of setting hardcoded value 22 for masking pid bits, use macro
NL_BITS_FOR_PID everywhere needed and automatically compute pid mask
with it.
Compute size of open port array in macro NL_MAX_USED_PORT using
NL_BITS_FOR_PID, which is more flexible.
Additionnaly, a third macro NR_BITS is defined to get number of bits of
any structure.

Those macros are useful in port mask computation in order to ease
understanding of what is related with index in used_port_map table, and
the bitfield within an entry of this table.

Signed-off-by: Julien Courtat <julien.courtat at 6wind.com>
---
 include/netlink-private/socket.h |    5 +++++
 lib/nl.c                         |    2 +-
 lib/socket.c                     |   45 +++++++++++++++++++++-----------------
 3 files changed, 31 insertions(+), 21 deletions(-)

diff --git a/include/netlink-private/socket.h b/include/netlink-private/socket.h
index 86a440c..62c7d4b 100644
--- a/include/netlink-private/socket.h
+++ b/include/netlink-private/socket.h
@@ -18,6 +18,11 @@
 extern "C" {
 #endif
 
+#define NL_BITS_FOR_PID 22
+/* there are 32 - NL_BITS_FOR_PID left for the port id per application,
+ * divided by 32 (>>5) to get used_port_map max table size */
+#define NL_MAX_USED_PORT (1 << (32 - NL_BITS_FOR_PID - 5))
+
 int _nl_socket_is_local_port_unspecified (struct nl_sock *sk);
 uint32_t _nl_socket_generate_local_port_no_release(struct nl_sock *sk);
 
diff --git a/lib/nl.c b/lib/nl.c
index 8fc9ec1..05fe29d 100644
--- a/lib/nl.c
+++ b/lib/nl.c
@@ -128,7 +128,7 @@ int nl_connect(struct nl_sock *sk, int protocol)
 
 	if (_nl_socket_is_local_port_unspecified (sk)) {
 		uint32_t port;
-		uint32_t used_ports[32] = { 0 };
+		uint32_t used_ports[NL_MAX_USED_PORT] = { 0 };
 
 		while (1) {
 			port = _nl_socket_generate_local_port_no_release(sk);
diff --git a/lib/socket.c b/lib/socket.c
index b29d1da..b1e9de9 100644
--- a/lib/socket.c
+++ b/lib/socket.c
@@ -41,6 +41,10 @@
 
 static int default_cb = NL_CB_DEFAULT;
 
+#define BIT(n)          (1 << (n))
+#define BIT_MASK(len)   (BIT(len) - 1)
+#define NR_BITS(t)      (8 * sizeof(t))
+
 static void __init init_default_cb(void)
 {
 	char *nlcb;
@@ -59,14 +63,14 @@ static void __init init_default_cb(void)
 	}
 }
 
-static uint32_t used_ports_map[32];
+static uint32_t used_ports_map[NL_MAX_USED_PORT];
 static NL_RW_LOCK(port_map_lock);
 
 static uint32_t generate_local_port(void)
 {
 	int i, j, n, m;
 	static uint16_t idx_state = 0;
-	uint32_t pid = getpid() & 0x3FFFFF;
+	uint32_t pid = getpid() & BIT_MASK(NL_BITS_FOR_PID);
 
 	nl_write_lock(&port_map_lock);
 
@@ -81,34 +85,35 @@ static uint32_t generate_local_port(void)
 
 	i = idx_state >> 5;
 	n = idx_state;
-	for (j = 0; j < 32; j++) {
+	for (j = 0; j < NL_MAX_USED_PORT; j++) {
 		/* walk the index somewhat randomized, with always leaving the block
 		 * #0 as last. The reason is that libnl-1 will start at block #0,
-		 * so just leave the first 32 ports preferably for libnl-1 owned sockets
+		 * so just leave the first NL_MAX_USED_PORT ports preferably for libnl-1 owned sockets
 		 * (this is relevant only if the applications ends up using both versions
 		 * of the library and doesn't hurt otherwise). */
-		if (j == 31)
+		if (j == NL_MAX_USED_PORT-1)
 			i = 0;
 		else
-			i = (((i-1) + 7) % 31) + 1;
+			i = (((i-1) + 7) % (NL_MAX_USED_PORT-1)) + 1;
 
 		if (used_ports_map[i] == 0xFFFFFFFF)
 			continue;
 
-		for (m = 0; m < 32; m++) {
-			n = (n + 13) % 32;
+		for (m = 0; m < NR_BITS(uint32_t); m++) {
+			n = (n + 13) % NR_BITS(uint32_t);
 			if (1UL & (used_ports_map[i] >> n))
 				continue;
 
 			used_ports_map[i] |= (1UL << n);
-			n += (i * 32);
+			n += (i * NR_BITS(uint32_t));
 
-			/* PID_MAX_LIMIT is currently at 2^22, leaving 10 bit
-			 * to, i.e. 1024 unique ports per application. */
+			/* PID_MAX_LIMIT is currently at 2^NL_BITS_FOR_PID, leaving
+			 * (32 - NL_BITS_FOR_PID) bits to,
+			 * i.e. (32 - NL_BITS_FOR_PID)^2 unique ports per application. */
 
 			nl_write_unlock(&port_map_lock);
 
-			return pid + (((uint32_t)n) << 22);
+			return pid + (((uint32_t)n) << NL_BITS_FOR_PID);
 		}
 	}
 
@@ -129,9 +134,9 @@ static void release_local_port(uint32_t port)
 
 	BUG_ON(port == 0);
 
-	nr = port >> 22;
-	mask = 1UL << (nr % 32);
-	nr /= 32;
+	nr = port >> NL_BITS_FOR_PID;
+	mask = 1UL << (nr % NR_BITS(uint32_t));
+	nr /= NR_BITS(uint32_t);
 
 	nl_write_lock(&port_map_lock);
 	BUG_ON((used_ports_map[nr] & mask) != mask);
@@ -144,10 +149,10 @@ void _nl_socket_used_ports_release_all(const uint32_t *used_ports)
 {
 	int i;
 
-	for (i = 0; i < 32; i++) {
+	for (i = 0; i < NL_MAX_USED_PORT; i++) {
 		if (used_ports[i] != 0) {
 			nl_write_lock(&port_map_lock);
-			for (; i < 32; i++) {
+			for (; i < NL_MAX_USED_PORT; i++) {
 				BUG_ON((used_ports_map[i] & used_ports[i]) != used_ports[i]);
 				used_ports_map[i] &= ~(used_ports[i]);
 			}
@@ -162,9 +167,9 @@ void _nl_socket_used_ports_set(uint32_t *used_ports, uint32_t port)
 	int nr;
 	int32_t mask;
 
-	nr = port >> 22;
-	mask = 1UL << (nr % 32);
-	nr /= 32;
+	nr = port >> NL_BITS_FOR_PID;
+	mask = 1UL << (nr % NR_BITS(uint32_t));
+	nr /= NR_BITS(uint32_t);
 
 	/*
 	BUG_ON(port == UINT32_MAX || port == 0 || (getpid() & 0x3FFFFF) != (port & 0x3FFFFF));
-- 
1.7.10.4



From thaller at redhat.com  Thu Jun  4 13:52:41 2015
From: thaller at redhat.com (Thomas Haller)
Date: Thu, 04 Jun 2015 22:52:41 +0200
Subject: [PATCH 1/1] route/link: fix memleaks in link_msg_parser()
In-Reply-To: <1431521168-27484-1-git-send-email-thaller@redhat.com>
References: <1431521168-27484-1-git-send-email-thaller@redhat.com>
Message-ID: <1433451161.5221.0.camel@redhat.com>

On Mi, 2015-05-13 at 14:46 +0200, Thomas Haller wrote:
> Signed-off-by: Thomas Haller <thaller at redhat.com>
> ---
>  lib/route/link.c | 10 ++++++----
>  1 file changed, 6 insertions(+), 4 deletions(-)
> 

merged as
https://github.com/thom311/libnl/commit/75dcd01756716ba68f4733fc1cab3bf
3a91f3b49
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/libnl/attachments/20150604/08393d81/attachment.sig>

From thaller at redhat.com  Thu Jun  4 14:09:08 2015
From: thaller at redhat.com (Thomas Haller)
Date: Thu, 04 Jun 2015 23:09:08 +0200
Subject: [PATCH] utils: Update link layer protocol translations
In-Reply-To: <1432035624-4613-1-git-send-email-tklauser@distanz.ch>
References: <1432035624-4613-1-git-send-email-tklauser@distanz.ch>
Message-ID: <1433452148.5221.1.camel@redhat.com>

On Di, 2015-05-19 at 13:40 +0200, Tobias Klauser wrote:
> Update the private copy of linux/if_arp.h and hook up the not yet
> defined ARPHRD_* types in the llprotos translation table. Reorder the
> entries such that they correspond to the order they're defined in
> linux/if_arp.h. Also remove the #ifdef guards since these are
> unnecessary given that the private copy of the kernel header is used.
> 
> Signed-off-by: Tobias Klauser <tklauser at distanz.ch>
> ---

Hi Tobias,


applied as
  https://github.com/thom311/libnl/commit/1dbe738e1e45d97c5829569e3eedc
d1c2a42f781

also a minor fix afterwards:
  https://github.com/thom311/libnl/commit/e206c255d8fff8b51938945c8f575
750c418a95e


Thank you!!
Thomas
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/libnl/attachments/20150604/3ed2a1c6/attachment.sig>

From thaller at redhat.com  Thu Jun  4 22:13:26 2015
From: thaller at redhat.com (Thomas Haller)
Date: Fri, 05 Jun 2015 07:13:26 +0200
Subject: [PATCH 0/2] increase maximum number of possible opened sockets
 per application
In-Reply-To: <1433430437-19376-1-git-send-email-julien.courtat@6wind.com>
References: <1433430437-19376-1-git-send-email-julien.courtat@6wind.com>
Message-ID: <1433481206.5221.29.camel@redhat.com>

On Do, 2015-06-04 at 17:07 +0200, Julien Courtat wrote:
> Hello,

Hi Julien,


> The current libnl 3.2.26 allows to create 1024 sockets at maximum per 
> application.
> This value is too short on systems using lots of netns.
> For example, a program that needs 8 sockets per netns is limited to 
> 128 netns.

as you probably are aware, an application can work around that
limitation by setting the port itself (nl_socket_set_local_port()),
or by even injecting an already bound socket (nl_socket_set_fd()).

I agree it would be nice to handle it better inside libnl.



> The following two patches propose to increase the maximum number of 
> possible opened
> socket per program with a single parameter NL_BITS_FOR_PID.
> Since a portid is a bitmask split between a pid and a random number, 
> number of bits
> dedicated to pid should be decreased to allow more bits for the 
> possible random value
> and de facto increase the possible number of opened sockets per 
> application.

If you call bind() with nl_pid=0, then kernel will try to autoassign a
port. See netlink_autobind(). This will first try to use
the PID, and afterwards search for an unused u32 number with the
highest bit set.


Depending on the kernel configuration, pids can be up to 22 bits.

If you reserve less then 22 bits, then libnl might generate a port that
gets used by another process. Well, actually, another process always
could already use the same port, so not sure that is a good reasoning
for anything.


> First patch proposes to separate values that handle the size of the 
> used_port_map[]
> from the values inside each entry of this table, which were a bit 
> messy since they were
> both hardcoded to 32.
> The second patch, only set the proposed value for NL_BITS_FOR_PID to 
> 18, which allows
> 16384 opened sockets on systems with max pid of 262144.

How about instead of failing if we cannot find a local-port, just try
to connect with pid=0 and let kernel choose?

        if (port == UINT32_MAX) {
               NL_DBG(4, "nl_connect(%p): no more unused local ports.\n", sk);
                     _nl_socket_used_ports_release_all(used_ports);
+               /* TRY with nl_pid=0... */
                err = -NLE_EXIST;
                goto errout;
        }



Or maybe better, always skip trying to generate our own ports all-together:

   if (_nl_socket_is_local_port_unspecified (sk)) {
      /* try port 0 and don't generate local_port */


Does anybody know why we even try to generate local ports in the first
place?



Thomas
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/libnl/attachments/20150605/75fec42b/attachment.sig>

From thaller at redhat.com  Thu Jun  4 22:50:50 2015
From: thaller at redhat.com (Thomas Haller)
Date: Fri, 05 Jun 2015 07:50:50 +0200
Subject: message attribute mismatch
In-Reply-To: <CAK-1WHiMSJ_0K1GUXYbRv4UjgB8emNoEWd2aAeT58SXHD6W6iw@mail.gmail.com>
References: <CAK-1WHiMSJ_0K1GUXYbRv4UjgB8emNoEWd2aAeT58SXHD6W6iw@mail.gmail.com>
Message-ID: <1433483450.10617.19.camel@redhat.com>

On Mo, 2015-06-01 at 17:58 -0700, Sergiy Lozovsky wrote:
> Hi,
> 
> it looks like libnl-3.2.25 doesn't support following attribute types:
> NLA_NUL_STRING and NLA_BINARY. These types are supported by kernel,
> Python Netlink packages, etc.
> 
> We have a kernel module and Python scripts that use these types. Is
> there any workaround? What is the best way to handle that?

Hi Sergiy,


Usually, you can use libnl to create libnl objects of certain known
types. For example libnl3-route can create 'struct rtnl_route' objects
via:
  rtnl_route_parse().
Obviously, as libnl doesn't know about these attributes, none of its
known types will make use of those attributes. I.e. there is no libnl
object for your the objects from your kernel module.



In your case, you would anyway parse your messages generically with:

    int nlmsg_parse(struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[],
                    int maxtype, struct nla_policy *policy);
    int nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head, int len,
                  struct nla_policy *policy);

if you now try to pass a policy argument like:

struct nla_policy my_type_policy[IFLA_MY_TYPE_MAX + 1] = {
    [IFLA_MY_TYPE_DATA] = { .type = NLA_BINARY },
};

libnl will barf on the unknown type. But the @policy argument is only there to validate
the message. You can pass %NULL and it will do no validation at all. Obviously, you must then
somehow validate the message youself.


You could still use nlmsg_parse() to fill the @tb argument without
validation. Afterwards, you validate the message yourself by
reimplementing validate_nla() to support the new message types:
  https://github.com/thom311/libnl/blob/e206c255d8fff8b51938945c8f57575
0c418a95e/lib/attr.c#L188



Not very satisfying. Patches very welcome!! ;-)


Thomas
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/libnl/attachments/20150605/a2a050a6/attachment.sig>

From thaller at redhat.com  Thu Jun  4 23:43:25 2015
From: thaller at redhat.com (Thomas Haller)
Date: Fri, 05 Jun 2015 08:43:25 +0200
Subject: [PATCH] lib: Return error if an incomplete message was read
In-Reply-To: <5570480E.6070804@gmx.de>
References: <5570480E.6070804@gmx.de>
Message-ID: <1433486605.10617.21.camel@redhat.com>

On Do, 2015-06-04 at 14:43 +0200, Thomas Egerer wrote:
> If recvmsg indicates that the message read was truncated libnl 
> retries
> to read the complete message after increasing the message buffer. 
> This
> only works if the message flags MSG_PEEK | MSG_TRUNC are set. If
> NL_MSG_PEEK is not enabled on the nl_sock structure, flags are left
> empty and the rest of the truncated message is discarded, hence a
> subsequent recvmsg returns the next message (in case of a multipart
> message, the NLMSG_DONE) is read and returned.
> This patch aborts message processing if the message was truncated and
> teh NL_MSG_PEEK flags was not activated for the nl_sock structure.
> 
> Signed-off-by: Thomas Egerer <hakke_007 at gmx.de>
> ---

Hi Thomas,

this fix looks right to me and its a pretty bad bug.

Applied as
 https://github.com/thom311/libnl/commit/bbdcaea9a779885fedc04817dcc119
53a377bfd5


I added NL_CAPABILITY_NL_RECV_FAIL_TRUNK_NO_PEEK to your patch.


Thank you.
Thomas
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/libnl/attachments/20150605/e567c882/attachment.sig>

From thaller at redhat.com  Thu Jun  4 23:59:42 2015
From: thaller at redhat.com (Thomas Haller)
Date: Fri, 05 Jun 2015 08:59:42 +0200
Subject: Weird problem IP change monitoring
In-Reply-To: <20150603231954.GA14584@cluster-node1.tuxwave.net>
References: <20150603231954.GA14584@cluster-node1.tuxwave.net>
Message-ID: <1433487582.10617.24.camel@redhat.com>

On Do, 2015-06-04 at 01:19 +0200, Sebastian Kricner wrote:
> Hello,
> 
> i have written a small C program to monitor IPv4 address changes with
> libnl and generally it works. But sometimes it delivers the IP 
> address
> of a different interface alltough i do a strcmp() on interface name.
> 
> Attached the program.
> 
> What might cause the problem?
> 

Hi Sebastian,

maybe you must check whether 
  if_indextoname(ifindex, s_ifname);
succeeds?


Thomas
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/libnl/attachments/20150605/745825c6/attachment.sig>

From thaller at redhat.com  Fri Jun  5 02:30:50 2015
From: thaller at redhat.com (Thomas Haller)
Date: Fri, 05 Jun 2015 11:30:50 +0200
Subject: [PATCH] lib: Return error if an incomplete message was read
In-Reply-To: <1433486605.10617.21.camel@redhat.com>
References: <5570480E.6070804@gmx.de> <1433486605.10617.21.camel@redhat.com>
Message-ID: <1433496650.4125.0.camel@redhat.com>

On Fr, 2015-06-05 at 08:43 +0200, Thomas Haller wrote:
> On Do, 2015-06-04 at 14:43 +0200, Thomas Egerer wrote:
> > If recvmsg indicates that the message read was truncated libnl 
> > retries
> > to read the complete message after increasing the message buffer. 
> > This
> > only works if the message flags MSG_PEEK | MSG_TRUNC are set. If
> > NL_MSG_PEEK is not enabled on the nl_sock structure, flags are left
> > empty and the rest of the truncated message is discarded, hence a
> > subsequent recvmsg returns the next message (in case of a multipart
> > message, the NLMSG_DONE) is read and returned.
> > This patch aborts message processing if the message was truncated 
> > and
> > teh NL_MSG_PEEK flags was not activated for the nl_sock structure.
> > 
> > Signed-off-by: Thomas Egerer <hakke_007 at gmx.de>
> > ---
> 


> I added NL_CAPABILITY_NL_RECV_FAIL_TRUNK_NO_PEEK to your patch.

should be NL_CAPABILITY_NL_RECV_FAIL_TRUNC_NO_PEEK.


https://github.com/thom311/libnl/commit/a9c789ccd4e24db3b14ffaf3f57ee3e
3a57f6fca


Thomas


-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/libnl/attachments/20150605/9ffd658c/attachment-0001.sig>

From hakke_007 at gmx.de  Fri Jun  5 02:42:54 2015
From: hakke_007 at gmx.de (Thomas Egerer)
Date: Fri, 05 Jun 2015 11:42:54 +0200
Subject: [PATCH] lib: Return error if an incomplete message was read
In-Reply-To: <1433496650.4125.0.camel@redhat.com>
References: <5570480E.6070804@gmx.de> <1433486605.10617.21.camel@redhat.com>
 <1433496650.4125.0.camel@redhat.com>
Message-ID: <55716F1E.7050508@gmx.de>

On 06/05/2015 11:30 AM, Thomas Haller wrote:
> On Fr, 2015-06-05 at 08:43 +0200, Thomas Haller wrote:
>> On Do, 2015-06-04 at 14:43 +0200, Thomas Egerer wrote:
>>> If recvmsg indicates that the message read was truncated libnl 
>>> retries
>>> to read the complete message after increasing the message buffer. 
>>> This
>>> only works if the message flags MSG_PEEK | MSG_TRUNC are set. If
>>> NL_MSG_PEEK is not enabled on the nl_sock structure, flags are left
>>> empty and the rest of the truncated message is discarded, hence a
>>> subsequent recvmsg returns the next message (in case of a multipart
>>> message, the NLMSG_DONE) is read and returned.
>>> This patch aborts message processing if the message was truncated 
>>> and
>>> teh NL_MSG_PEEK flags was not activated for the nl_sock structure.
>>>
>>> Signed-off-by: Thomas Egerer <hakke_007 at gmx.de>
>>> ---
>>
> 
> 
>> I added NL_CAPABILITY_NL_RECV_FAIL_TRUNK_NO_PEEK to your patch.
> 
> should be NL_CAPABILITY_NL_RECV_FAIL_TRUNC_NO_PEEK.
You're right, wasn't the first time, I introduced a typo to a project ;)

> 
> https://github.com/thom311/libnl/commit/a9c789ccd4e24db3b14ffaf3f57ee3e
> 3a57f6fca
> 
> 
Cheers,
Thomas
> 
> 


-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 181 bytes
Desc: OpenPGP digital signature
URL: <http://lists.infradead.org/pipermail/libnl/attachments/20150605/32e9b66e/attachment.sig>

From sergiy.lozovsky at gmail.com  Fri Jun  5 12:53:29 2015
From: sergiy.lozovsky at gmail.com (Sergiy Lozovsky)
Date: Fri, 5 Jun 2015 12:53:29 -0700
Subject: message attribute mismatch
In-Reply-To: <1433483450.10617.19.camel@redhat.com>
References: <CAK-1WHiMSJ_0K1GUXYbRv4UjgB8emNoEWd2aAeT58SXHD6W6iw@mail.gmail.com>
 <1433483450.10617.19.camel@redhat.com>
Message-ID: <CAK-1WHiCN138vMR7A54968wy4ud_wZyaQA1Lw+Q=ToQqo=5N8Q@mail.gmail.com>

Hi Thoms,

thanks for the response. It's bad that libnl attribute types don't
match kernel and other packages attribute types. It is the core idea
of Netlink for all endpoints to have consistent API. IMHO

At the same time after some digging, I figured out that it's not
really critical. I thought that types are transmitted within the
message. I was wrong. Attribute types are used for type verification
and deserialization only.

That means that although other endpoints (kernel, Python, etc.) use
NLA_NUL_STRING and NLA_BINARY. It's ok to use NLA_STRING and
NLA_UNSPEC in application using libnl. This mismatch looks ugly from
software support point of view, but it will work.

NLA_BINARY means that content is not checked and can have variable
length. NLA_UNSPEC is exactly the same.

NLA_STRING - will deserialize attribute encoded as NLA_NUL_STRING just
fine. It will not verify trailing zero and minimal length (1) (as
kernel does), but other than that there are no problems.

I may later work on the patch to add NLA_NUL_STRING and NLA_BINARY to libnl.

There is other problem with libnl - it doesn't directly support server
side of Netlink. It is still possible to implement it, but
nl_recvmsgs_default() will return NLE_SEQ_MISMATCH as server doesn't
know what sequence number will be sent by a client. It's easy to just
ignore these errors and use NL_CB_MSG_IN callback skipping all
nl_recvmsgs verifications though.

Thanks,

Sergiy.




On Thu, Jun 4, 2015 at 10:50 PM, Thomas Haller <thaller at redhat.com> wrote:
> On Mo, 2015-06-01 at 17:58 -0700, Sergiy Lozovsky wrote:
>> Hi,
>>
>> it looks like libnl-3.2.25 doesn't support following attribute types:
>> NLA_NUL_STRING and NLA_BINARY. These types are supported by kernel,
>> Python Netlink packages, etc.
>>
>> We have a kernel module and Python scripts that use these types. Is
>> there any workaround? What is the best way to handle that?
>
> Hi Sergiy,
>
>
> Usually, you can use libnl to create libnl objects of certain known
> types. For example libnl3-route can create 'struct rtnl_route' objects
> via:
>   rtnl_route_parse().
> Obviously, as libnl doesn't know about these attributes, none of its
> known types will make use of those attributes. I.e. there is no libnl
> object for your the objects from your kernel module.
>
>
>
> In your case, you would anyway parse your messages generically with:
>
>     int nlmsg_parse(struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[],
>                     int maxtype, struct nla_policy *policy);
>     int nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head, int len,
>                   struct nla_policy *policy);
>
> if you now try to pass a policy argument like:
>
> struct nla_policy my_type_policy[IFLA_MY_TYPE_MAX + 1] = {
>     [IFLA_MY_TYPE_DATA] = { .type = NLA_BINARY },
> };
>
> libnl will barf on the unknown type. But the @policy argument is only there to validate
> the message. You can pass %NULL and it will do no validation at all. Obviously, you must then
> somehow validate the message youself.
>
>
> You could still use nlmsg_parse() to fill the @tb argument without
> validation. Afterwards, you validate the message yourself by
> reimplementing validate_nla() to support the new message types:
>   https://github.com/thom311/libnl/blob/e206c255d8fff8b51938945c8f57575
> 0c418a95e/lib/attr.c#L188
>
>
>
> Not very satisfying. Patches very welcome!! ;-)
>
>
> Thomas


From tklauser at distanz.ch  Mon Jun  8 00:32:29 2015
From: tklauser at distanz.ch (Tobias Klauser)
Date: Mon, 8 Jun 2015 09:32:29 +0200
Subject: [PATCH] utils: Update link layer protocol translations
In-Reply-To: <1433452148.5221.1.camel@redhat.com>
References: <1432035624-4613-1-git-send-email-tklauser@distanz.ch>
 <1433452148.5221.1.camel@redhat.com>
Message-ID: <20150608073229.GA4745@distanz.ch>

Hi Thomas,

On 2015-06-04 at 23:09:08 +0200, Thomas Haller <thaller at redhat.com> wrote:
> On Di, 2015-05-19 at 13:40 +0200, Tobias Klauser wrote:
> > Update the private copy of linux/if_arp.h and hook up the not yet
> > defined ARPHRD_* types in the llprotos translation table. Reorder the
> > entries such that they correspond to the order they're defined in
> > linux/if_arp.h. Also remove the #ifdef guards since these are
> > unnecessary given that the private copy of the kernel header is used.
> > 
> > Signed-off-by: Tobias Klauser <tklauser at distanz.ch>
> > ---
> 
> Hi Tobias,
> 
> 
> applied as
>   https://github.com/thom311/libnl/commit/1dbe738e1e45d97c5829569e3eedc
> d1c2a42f781
> 
> also a minor fix afterwards:
>   https://github.com/thom311/libnl/commit/e206c255d8fff8b51938945c8f575
> 750c418a95e

Thanks for applying and for the follow-up fix.

Cheers
Tobias


From xiyou.wangcong at gmail.com  Tue Jun  9 21:53:09 2015
From: xiyou.wangcong at gmail.com (Cong Wang)
Date: Tue,  9 Jun 2015 21:53:09 -0700
Subject: [PATCH 1/2] Add ipvlan support
Message-ID: <1433911990-14569-1-git-send-email-xiyou.wangcong@gmail.com>

Signed-off-by: Cong Wang <xiyou.wangcong at gmail.com>
---
 include/Makefile.am                   |   1 +
 include/linux-private/linux/if_link.h |  15 ++
 include/netlink/route/link/ipvlan.h   |  37 +++++
 lib/Makefile.am                       |   2 +-
 lib/route/link/ipvlan.c               | 279 ++++++++++++++++++++++++++++++++++
 libnl-route-3.sym                     |  10 ++
 6 files changed, 343 insertions(+), 1 deletion(-)
 create mode 100644 include/netlink/route/link/ipvlan.h
 create mode 100644 lib/route/link/ipvlan.c

diff --git a/include/Makefile.am b/include/Makefile.am
index bf86ed1..ffaa9a5 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -60,6 +60,7 @@ nobase_libnlinclude_HEADERS = \
 	netlink/route/link/ipip.h \
 	netlink/route/link/ipvti.h \
 	netlink/route/link/sit.h \
+	netlink/route/link/ipvlan.h \
 	netlink/route/qdisc/cbq.h \
 	netlink/route/qdisc/dsmark.h \
 	netlink/route/qdisc/fifo.h \
diff --git a/include/linux-private/linux/if_link.h b/include/linux-private/linux/if_link.h
index ff95760..69e30d0 100644
--- a/include/linux-private/linux/if_link.h
+++ b/include/linux-private/linux/if_link.h
@@ -305,6 +305,21 @@ enum macvlan_mode {
 
 #define MACVLAN_FLAG_NOPROMISC	1
 
+/* IPVLAN section */
+enum {
+	IFLA_IPVLAN_UNSPEC,
+	IFLA_IPVLAN_MODE,
+	__IFLA_IPVLAN_MAX
+};
+
+#define IFLA_IPVLAN_MAX (__IFLA_IPVLAN_MAX - 1)
+
+enum ipvlan_mode {
+	IPVLAN_MODE_L2 = 0,
+	IPVLAN_MODE_L3,
+	IPVLAN_MODE_MAX
+};
+
 /* VXLAN section */
 enum {
 	IFLA_VXLAN_UNSPEC,
diff --git a/include/netlink/route/link/ipvlan.h b/include/netlink/route/link/ipvlan.h
new file mode 100644
index 0000000..21cce85
--- /dev/null
+++ b/include/netlink/route/link/ipvlan.h
@@ -0,0 +1,37 @@
+/*
+ * netlink/route/link/ipvlan.h		IPVLAN interface
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2015 Cong Wang <cwang at twopensource.com>
+ */
+
+#ifndef NETLINK_LINK_IPVLAN_H_
+#define NETLINK_LINK_IPVLAN_H_
+
+#include <netlink/netlink.h>
+#include <netlink/route/link.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern struct rtnl_link *rtnl_link_ipvlan_alloc(void);
+
+extern int		rtnl_link_is_ipvlan(struct rtnl_link *);
+
+extern char *		rtnl_link_ipvlan_mode2str(int, char *, size_t);
+extern int		rtnl_link_ipvlan_str2mode(const char *);
+
+extern int		rtnl_link_ipvlan_set_mode(struct rtnl_link *,
+			                           uint16_t);
+extern uint16_t		rtnl_link_ipvlan_get_mode(struct rtnl_link *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 92f812c..1474c8d 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -110,7 +110,7 @@ libnl_route_3_la_SOURCES = \
 	route/link/bonding.c route/link/can.c route/link/macvlan.c \
 	route/link/vxlan.c route/link/veth.c route/link/ipip.c \
 	route/link/ipgre.c route/link/sit.c route/link/ipvti.c \
-	route/link/ip6tnl.c route/link/ifb.c \
+	route/link/ip6tnl.c route/link/ifb.c route/link/ipvlan.c \
 	\
 	route/qdisc/blackhole.c route/qdisc/cbq.c route/qdisc/dsmark.c \
 	route/qdisc/fifo.c route/qdisc/htb.c route/qdisc/netem.c \
diff --git a/lib/route/link/ipvlan.c b/lib/route/link/ipvlan.c
new file mode 100644
index 0000000..2ad56f8
--- /dev/null
+++ b/lib/route/link/ipvlan.c
@@ -0,0 +1,279 @@
+/*
+ * lib/route/link/ipvlan.c	IPVLAN Link Info
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2015 Cong Wang <cwang at twopensource.com>
+ */
+
+/**
+ * @ingroup link
+ * @defgroup ipvlan IPVLAN
+ * IP-based Virtual LAN link module
+ *
+ * @details
+ * \b Link Type Name: "ipvlan"
+ *
+ * @route_doc{link_ipvlan, IPVLAN Documentation}
+ *
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink/netlink.h>
+#include <netlink/attr.h>
+#include <netlink/utils.h>
+#include <netlink/object.h>
+#include <netlink/route/rtnl.h>
+#include <netlink-private/route/link/api.h>
+#include <netlink/route/link/ipvlan.h>
+
+#include <linux/if_link.h>
+
+/** @cond SKIP */
+#define IPVLAN_HAS_MODE	(1<<0)
+
+struct ipvlan_info
+{
+	uint16_t		ipi_mode;
+	uint32_t		ipi_mask;
+};
+
+/** @endcond */
+
+static struct nla_policy ipvlan_policy[IFLA_IPVLAN_MAX+1] = {
+	[IFLA_IPVLAN_MODE]	= { .type = NLA_U16 },
+};
+
+static int ipvlan_alloc(struct rtnl_link *link)
+{
+	struct ipvlan_info *ipi;
+
+	if (link->l_info)
+		memset(link->l_info, 0, sizeof(*ipi));
+	else {
+		if ((ipi = calloc(1, sizeof(*ipi))) == NULL)
+			return -NLE_NOMEM;
+
+		link->l_info = ipi;
+	}
+
+	return 0;
+}
+
+static int ipvlan_parse(struct rtnl_link *link, struct nlattr *data,
+                         struct nlattr *xstats)
+{
+	struct nlattr *tb[IFLA_IPVLAN_MAX+1];
+	struct ipvlan_info *ipi;
+	int err;
+
+	NL_DBG(3, "Parsing IPVLAN link info");
+
+	if ((err = nla_parse_nested(tb, IFLA_IPVLAN_MAX, data, ipvlan_policy)) < 0)
+		goto errout;
+
+	if ((err = ipvlan_alloc(link)) < 0)
+		goto errout;
+
+	ipi = link->l_info;
+
+	if (tb[IFLA_IPVLAN_MODE]) {
+		ipi->ipi_mode = nla_get_u16(tb[IFLA_IPVLAN_MODE]);
+		ipi->ipi_mask |= IPVLAN_HAS_MODE;
+	}
+
+	err = 0;
+errout:
+	return err;
+}
+
+static void ipvlan_free(struct rtnl_link *link)
+{
+	free(link->l_info);
+	link->l_info = NULL;
+}
+
+static void ipvlan_dump(struct rtnl_link *link, struct nl_dump_params *p)
+{
+	char buf[64];
+	struct ipvlan_info *ipi = link->l_info;
+
+	if (ipi->ipi_mask & IPVLAN_HAS_MODE) {
+		rtnl_link_ipvlan_mode2str(ipi->ipi_mode, buf, sizeof(buf));
+		nl_dump(p, "ipvlan-mode %s", buf);
+	}
+}
+
+static int ipvlan_clone(struct rtnl_link *dst, struct rtnl_link *src)
+{
+	struct ipvlan_info *vdst, *vsrc = src->l_info;
+	int err;
+
+	dst->l_info = NULL;
+	if ((err = rtnl_link_set_type(dst, "ipvlan")) < 0)
+		return err;
+	vdst = dst->l_info;
+
+	if (!vdst || !vsrc)
+		return -NLE_NOMEM;
+
+	memcpy(vdst, vsrc, sizeof(struct ipvlan_info));
+
+	return 0;
+}
+
+static int ipvlan_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
+{
+	struct ipvlan_info *ipi = link->l_info;
+	struct nlattr *data;
+
+	if (!(data = nla_nest_start(msg, IFLA_INFO_DATA)))
+		return -NLE_MSGSIZE;
+
+	if (ipi->ipi_mask & IPVLAN_HAS_MODE)
+		NLA_PUT_U16(msg, IFLA_IPVLAN_MODE, ipi->ipi_mode);
+
+	nla_nest_end(msg, data);
+
+nla_put_failure:
+
+	return 0;
+}
+
+static struct rtnl_link_info_ops ipvlan_info_ops = {
+	.io_name		= "ipvlan",
+	.io_alloc		= ipvlan_alloc,
+	.io_parse		= ipvlan_parse,
+	.io_dump = {
+	    [NL_DUMP_LINE]	= ipvlan_dump,
+	    [NL_DUMP_DETAILS]	= ipvlan_dump,
+	},
+	.io_clone		= ipvlan_clone,
+	.io_put_attrs		= ipvlan_put_attrs,
+	.io_free		= ipvlan_free,
+};
+
+/** @cond SKIP */
+#define IS_IPVLAN_LINK_ASSERT(link) \
+	if ((link)->l_info_ops != &ipvlan_info_ops) { \
+		APPBUG("Link is not a ipvlan link. set type \"ipvlan\" first."); \
+		return -NLE_OPNOTSUPP; \
+	}
+/** @endcond */
+
+/**
+ * @name IPVLAN Object
+ * @{
+ */
+
+/**
+ * Allocate link object of type IPVLAN
+ *
+ * @return Allocated link object or NULL.
+ */
+struct rtnl_link *rtnl_link_ipvlan_alloc(void)
+{
+	struct rtnl_link *link;
+	int err;
+
+	if (!(link = rtnl_link_alloc()))
+		return NULL;
+
+	if ((err = rtnl_link_set_type(link, "ipvlan")) < 0) {
+		rtnl_link_put(link);
+		return NULL;
+	}
+
+	return link;
+}
+
+/**
+ * Check if link is a IPVLAN link
+ * @arg link		Link object
+ *
+ * @return True if link is a IPVLAN link, otherwise false is returned.
+ */
+int rtnl_link_is_ipvlan(struct rtnl_link *link)
+{
+	return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "ipvlan");
+}
+
+/**
+ * Set IPVLAN MODE
+ * @arg link		Link object
+ * @arg mode		IPVLAN mode
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_ipvlan_set_mode(struct rtnl_link *link, uint16_t mode)
+{
+	struct ipvlan_info *ipi = link->l_info;
+
+	IS_IPVLAN_LINK_ASSERT(link);
+
+	if (mode != IPVLAN_MODE_L2 && mode != IPVLAN_MODE_L3)
+		return -NLE_INVAL;
+
+	ipi->ipi_mode = mode;
+	ipi->ipi_mask |= IPVLAN_HAS_MODE;
+
+	return 0;
+}
+
+/**
+ * Get IPVLAN Mode
+ * @arg link		Link object
+ *
+ * @return IPVLAN mode, 0 if not set or a negative error code.
+ */
+uint16_t rtnl_link_ipvlan_get_mode(struct rtnl_link *link)
+{
+	struct ipvlan_info *ipi = link->l_info;
+
+	IS_IPVLAN_LINK_ASSERT(link);
+
+	if (ipi->ipi_mask & IPVLAN_HAS_MODE)
+		return ipi->ipi_mode;
+	else
+		return 0;
+}
+
+/** @} */
+
+static const struct trans_tbl ipvlan_modes[] = {
+	__ADD(IPVLAN_MODE_L2, l2),
+	__ADD(IPVLAN_MODE_L3, l3),
+};
+
+/**
+ * @name Mode Translation
+ * @{
+ */
+
+char *rtnl_link_ipvlan_mode2str(int mode, char *buf, size_t len)
+{
+	return __type2str(mode, buf, len, ipvlan_modes, ARRAY_SIZE(ipvlan_modes));
+}
+
+int rtnl_link_ipvlan_str2mode(const char *name)
+{
+	return __str2type(name, ipvlan_modes, ARRAY_SIZE(ipvlan_modes));
+}
+
+/** @} */
+
+static void __init ipvlan_init(void)
+{
+	rtnl_link_register_info(&ipvlan_info_ops);
+}
+
+static void __exit ipvlan_exit(void)
+{
+	rtnl_link_unregister_info(&ipvlan_info_ops);
+}
+
+/** @} */
diff --git a/libnl-route-3.sym b/libnl-route-3.sym
index ad2ed36..f55a162 100644
--- a/libnl-route-3.sym
+++ b/libnl-route-3.sym
@@ -872,3 +872,13 @@ global:
 	rtnl_tc_str2stat;
 	rtnl_u32_get_classid;
 } libnl_3;
+
+libnl_3_2_27 {
+global:
+	rtnl_link_ipvlan_alloc;
+	rtnl_link_is_ipvlan;
+	rtnl_link_ipvlan_mode2str;
+	rtnl_link_ipvlan_str2mode;
+	rtnl_link_ipvlan_set_mode;
+	rtnl_link_ipvlan_get_mode;
+} libnl_3_2_26;
-- 
1.8.1.4



From xiyou.wangcong at gmail.com  Tue Jun  9 21:53:10 2015
From: xiyou.wangcong at gmail.com (Cong Wang)
Date: Tue,  9 Jun 2015 21:53:10 -0700
Subject: [PATCH 2/2] Add a testcase for ipvlan
In-Reply-To: <1433911990-14569-1-git-send-email-xiyou.wangcong@gmail.com>
References: <1433911990-14569-1-git-send-email-xiyou.wangcong@gmail.com>
Message-ID: <1433911990-14569-2-git-send-email-xiyou.wangcong@gmail.com>

Signed-off-by: Cong Wang <xiyou.wangcong at gmail.com>
---
 tests/Makefile.am          |  1 +
 tests/test-create-ipvlan.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 46 insertions(+)
 create mode 100644 tests/test-create-ipvlan.c

diff --git a/tests/Makefile.am b/tests/Makefile.am
index 8d1da59..edf2ee5 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -35,6 +35,7 @@ check_PROGRAMS = \
 	test-create-ipip \
 	test-create-ipvti \
 	test-create-macvlan \
+	test-create-ipvlan \
 	test-create-sit \
 	test-create-ifb \
 	test-delete-link \
diff --git a/tests/test-create-ipvlan.c b/tests/test-create-ipvlan.c
new file mode 100644
index 0000000..dd61b80
--- /dev/null
+++ b/tests/test-create-ipvlan.c
@@ -0,0 +1,45 @@
+#include <netlink/netlink.h>
+#include <netlink/route/link.h>
+#include <netlink/route/link/ipvlan.h>
+
+int main(int argc, char *argv[])
+{
+	struct rtnl_link *link;
+	struct nl_cache *link_cache;
+	struct nl_sock *sk;
+	int err, master_index;
+
+	sk = nl_socket_alloc();
+	if ((err = nl_connect(sk, NETLINK_ROUTE)) < 0) {
+		nl_perror(err, "Unable to connect socket");
+		return err;
+	}
+
+	if ((err = rtnl_link_alloc_cache(sk, AF_UNSPEC, &link_cache)) < 0) {
+		nl_perror(err, "Unable to allocate cache");
+		return err;
+	}
+
+	if (!(master_index = rtnl_link_name2i(link_cache, "eth0"))) {
+		fprintf(stderr, "Unable to lookup eth0");
+		return -1;
+	}
+
+	if (!(link = rtnl_link_ipvlan_alloc())) {
+		fprintf(stderr, "Unable to allocate link");
+		return -1;
+	}
+
+	rtnl_link_set_link(link, master_index);
+	rtnl_link_ipvlan_set_mode(link, rtnl_link_ipvlan_str2mode("l2"));
+
+	if ((err = rtnl_link_add(sk, link, NLM_F_CREATE)) < 0) {
+		nl_perror(err, "Unable to add link");
+		return err;
+	}
+
+	rtnl_link_put(link);
+	nl_close(sk);
+
+	return 0;
+}
-- 
1.8.1.4



From ranker72 at gmail.com  Fri Jun 12 08:24:51 2015
From: ranker72 at gmail.com (ferran)
Date: Fri, 12 Jun 2015 17:24:51 +0200
Subject: Resources cleanup upon using received data
Message-ID: <557AF9C3.3060809@gmail.com>

Hello everyone,
I have some issues at managing resources used to query wireless
statistics, I hope you can help me.

Currently I successfully query cfg80211 to get statistics about wireless
devices such as tx bitrate, every 10 seconds. My problem is that I have
been unable to do this without leaking file descriptors and memory. The
code I use is inherited and I am trying to fix it, but I can't manage to
release the resources without losing the retrieved data. Until now, I
have read the documentation, compared with implementation examples found
here and there, and consulted frequently the doxygen reference. However,
I still need some more help.

Issue 1: 'nl_recvmsgs_default()' will block until receiving a message if
socket is configured as blocking (default), but won't wait for the
callback to finish, right? So how could I possibly release the resources
just after nl_recvmsgs if the callback needs the received data?

Issue 2: I have sumarized  the code so that you can check the run flow
and the memory management, it's posted in pastebin:
http://pastebin.com/EYADmDpy
Could you have a look to it, please? It's less than 100 lines, comments
included. How should I release the resources used by the nl socket and
nl message?

Thank you for your time,
Ferran


From dcbw at redhat.com  Fri Jun 12 09:33:23 2015
From: dcbw at redhat.com (Dan Williams)
Date: Fri, 12 Jun 2015 11:33:23 -0500
Subject: Resources cleanup upon using received data
In-Reply-To: <557AF9C3.3060809@gmail.com>
References: <557AF9C3.3060809@gmail.com>
Message-ID: <1434126803.4018.21.camel@redhat.com>

On Fri, 2015-06-12 at 17:24 +0200, ferran wrote:
> Hello everyone,
> I have some issues at managing resources used to query wireless
> statistics, I hope you can help me.
> 
> Currently I successfully query cfg80211 to get statistics about wireless
> devices such as tx bitrate, every 10 seconds. My problem is that I have
> been unable to do this without leaking file descriptors and memory. The
> code I use is inherited and I am trying to fix it, but I can't manage to
> release the resources without losing the retrieved data. Until now, I
> have read the documentation, compared with implementation examples found
> here and there, and consulted frequently the doxygen reference. However,
> I still need some more help.
> 
> Issue 1: 'nl_recvmsgs_default()' will block until receiving a message if
> socket is configured as blocking (default), but won't wait for the
> callback to finish, right? So how could I possibly release the resources
> just after nl_recvmsgs if the callback needs the received data?

nl_recvmsgs_default() will block and process messages as long as (a)
there are messages in the receive buffer and (b) your callback returns
NL_SKIP.  It will wait for your callback to finish before proceeding.

One thing I notice: there isn't a lot of sense in doing all the setup
every 10 seconds.  You might as well just do the setup once and then
every 10s do the nl_msg_alloc/send/recv.  

> Issue 2: I have sumarized  the code so that you can check the run flow
> and the memory management, it's posted in pastebin:
> http://pastebin.com/EYADmDpy
> Could you have a look to it, please? It's less than 100 lines, comments
> included. How should I release the resources used by the nl socket and
> nl message?

The code you've got isn't freeing either 'msg' or 'sk', so you're
leaking both of those every 10 seconds.  How about something like this;
alternatively you can just make sure that both the normal and
nla_put_failure paths in get_wireless_stats() free both 'msg' and 'sk'.

//// ----------- caller.c ------------------
/* includes */
int main ()
    struct wireless_stats ofs;
    struct nl_sock *sk;
    int family_id;
    int err;

    sk = nl_socket_alloc();
    genl_connect(sk);

    // WARNING, the docs say we must call genl_family_put() later and we don't!    
    family_id = genl_ctrl_resolve(sk, "nl80211");
    
    nl_socket_modify_cb(sk, NL_CB_VALID, NL_CB_CUSTOM,
        stats_handler, NULL);

    while (true)
    {
        get_wireless_stats(sk, &ofs);
        /* use retrieved data */
    
        sleep_seconds(10);
    }

    nl_socket_free(sk);
return 0;

//// --------- wireless_stats.c -----------

void get_wireless_stats(struct nl_socket *sk, struct wireless_stats *ofs)
{
    struct nl_msg *msg;
    int err;

    shared_stats = ofs;
    
    msg = nlmsg_alloc();
    genlmsg_put(msg, 0, 0, family_id, 0, NLM_F_DUMP, NL80211_CMD_GET_STATION, 0;
    NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex("mesh0"));
    err = nl_send_auto_complete(sk, msg);
    nl_recvmsgs_default(sk);
    nlsmg_free(msg);
    return 0;
    
    // Not sure who comes here, but it isn't part of the success workflow, and is required at compilation time.
    // -> the NLA_PUT_U32 macro has a 'goto nla_put_failure' in case there isn't enough memory
nla_put_failure:
    nlmsg_free(msg);
    return err;
}

<no changes to stats_handler>



From ranker72 at gmail.com  Mon Jun 15 11:31:54 2015
From: ranker72 at gmail.com (ferran)
Date: Mon, 15 Jun 2015 20:31:54 +0200
Subject: Resources cleanup upon using received data
In-Reply-To: <1434126803.4018.21.camel@redhat.com>
References: <557AF9C3.3060809@gmail.com> <1434126803.4018.21.camel@redhat.com>
Message-ID: <557F1A1A.6080009@gmail.com>

Hi Dan,
Thank you for your kind reply.

I agree that the nice way to go would be to reuse the same socket, but I
can't access to the upper level, in the example, "caller.c". It's part
of a wider project, and I'm afraid that it would break a level of
abstraction.

I have to add information: "get_wireless_stats" is called once per
wireless device each 10 seconds. Therefore, "caller.c", in practice, is
doing:

int main ()
    struct wireless_stats ofs;
    while (true)
    {
        for_each_dev(device)
        {
            get_wireless_stats(device, &ofs);
        }
        sleep_seconds(10);
    }
return 0;

Where "device" is a string that is translated with "if_nametoindex"
inside "get_wireless_stats". Each device is queried one after the other
without threading or alike.

This said, I tried again with more verbose logging and freed the msg and
socket resources before finishing "get_wireless_stats". I get the stats
doing :
...

    nlsmg_free(msg);
    nl_close(sk);
    return 0;
    
nla_put_failure:
    nlmsg_free(msg);
    nl_close(sk);
    return err;
}

But if I do "nl_socket_free(sk)" instead of "nl_close(sk)", then the
callback isn't called, and the stats don't get copied to the target
structure. Does it make any sense to you?

Regards,
Ferran

On 12/06/15 18:33, Dan Williams wrote:
> On Fri, 2015-06-12 at 17:24 +0200, ferran wrote:
>> Hello everyone,
>> I have some issues at managing resources used to query wireless
>> statistics, I hope you can help me.
>>
>> Currently I successfully query cfg80211 to get statistics about wireless
>> devices such as tx bitrate, every 10 seconds. My problem is that I have
>> been unable to do this without leaking file descriptors and memory. The
>> code I use is inherited and I am trying to fix it, but I can't manage to
>> release the resources without losing the retrieved data. Until now, I
>> have read the documentation, compared with implementation examples found
>> here and there, and consulted frequently the doxygen reference. However,
>> I still need some more help.
>>
>> Issue 1: 'nl_recvmsgs_default()' will block until receiving a message if
>> socket is configured as blocking (default), but won't wait for the
>> callback to finish, right? So how could I possibly release the resources
>> just after nl_recvmsgs if the callback needs the received data?
> nl_recvmsgs_default() will block and process messages as long as (a)
> there are messages in the receive buffer and (b) your callback returns
> NL_SKIP.  It will wait for your callback to finish before proceeding.
>
> One thing I notice: there isn't a lot of sense in doing all the setup
> every 10 seconds.  You might as well just do the setup once and then
> every 10s do the nl_msg_alloc/send/recv.  
>
>> Issue 2: I have sumarized  the code so that you can check the run flow
>> and the memory management, it's posted in pastebin:
>> http://pastebin.com/EYADmDpy
>> Could you have a look to it, please? It's less than 100 lines, comments
>> included. How should I release the resources used by the nl socket and
>> nl message?
> The code you've got isn't freeing either 'msg' or 'sk', so you're
> leaking both of those every 10 seconds.  How about something like this;
> alternatively you can just make sure that both the normal and
> nla_put_failure paths in get_wireless_stats() free both 'msg' and 'sk'.
>
> //// ----------- caller.c ------------------
> /* includes */
> int main ()
>     struct wireless_stats ofs;
>     struct nl_sock *sk;
>     int family_id;
>     int err;
>
>     sk = nl_socket_alloc();
>     genl_connect(sk);
>
>     // WARNING, the docs say we must call genl_family_put() later and we don't!    
>     family_id = genl_ctrl_resolve(sk, "nl80211");
>     
>     nl_socket_modify_cb(sk, NL_CB_VALID, NL_CB_CUSTOM,
>         stats_handler, NULL);
>
>     while (true)
>     {
>         get_wireless_stats(sk, &ofs);
>         /* use retrieved data */
>     
>         sleep_seconds(10);
>     }
>
>     nl_socket_free(sk);
> return 0;
>
> //// --------- wireless_stats.c -----------
>
> void get_wireless_stats(struct nl_socket *sk, struct wireless_stats *ofs)
> {
>     struct nl_msg *msg;
>     int err;
>
>     shared_stats = ofs;
>     
>     msg = nlmsg_alloc();
>     genlmsg_put(msg, 0, 0, family_id, 0, NLM_F_DUMP, NL80211_CMD_GET_STATION, 0;
>     NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex("mesh0"));
>     err = nl_send_auto_complete(sk, msg);
>     nl_recvmsgs_default(sk);
>     nlsmg_free(msg);
>     return 0;
>     
>     // Not sure who comes here, but it isn't part of the success workflow, and is required at compilation time.
>     // -> the NLA_PUT_U32 macro has a 'goto nla_put_failure' in case there isn't enough memory
> nla_put_failure:
>     nlmsg_free(msg);
>     return err;
> }
>
> <no changes to stats_handler>
>




From ranker72 at gmail.com  Mon Jun 15 12:16:10 2015
From: ranker72 at gmail.com (ferran)
Date: Mon, 15 Jun 2015 21:16:10 +0200
Subject: Resources cleanup upon using received data
In-Reply-To: <557F1A1A.6080009@gmail.com>
References: <557AF9C3.3060809@gmail.com> <1434126803.4018.21.camel@redhat.com>
 <557F1A1A.6080009@gmail.com>
Message-ID: <557F247A.8030803@gmail.com>

Hi,

I forgot to mention that the callback, when called, is always called
twice. However, I don't free any resource inside the callback, but after it.

I can't figure out how freeing the socket after the callback can prevent
the callback itself to be called.

Regards,
Ferran

On 15/06/15 20:31, ferran wrote:
> Hi Dan,
> Thank you for your kind reply.
>
> I agree that the nice way to go would be to reuse the same socket, but I
> can't access to the upper level, in the example, "caller.c". It's part
> of a wider project, and I'm afraid that it would break a level of
> abstraction.
>
> I have to add information: "get_wireless_stats" is called once per
> wireless device each 10 seconds. Therefore, "caller.c", in practice, is
> doing:
>
> int main ()
>     struct wireless_stats ofs;
>     while (true)
>     {
>         for_each_dev(device)
>         {
>             get_wireless_stats(device, &ofs);
>         }
>         sleep_seconds(10);
>     }
> return 0;
>
> Where "device" is a string that is translated with "if_nametoindex"
> inside "get_wireless_stats". Each device is queried one after the other
> without threading or alike.
>
> This said, I tried again with more verbose logging and freed the msg and
> socket resources before finishing "get_wireless_stats". I get the stats
> doing :
> ...
>
>     nlsmg_free(msg);
>     nl_close(sk);
>     return 0;
>     
> nla_put_failure:
>     nlmsg_free(msg);
>     nl_close(sk);
>     return err;
> }
>
> But if I do "nl_socket_free(sk)" instead of "nl_close(sk)", then the
> callback isn't called, and the stats don't get copied to the target
> structure. Does it make any sense to you?
>
> Regards,
> Ferran
>
> On 12/06/15 18:33, Dan Williams wrote:
>> On Fri, 2015-06-12 at 17:24 +0200, ferran wrote:
>>> Hello everyone,
>>> I have some issues at managing resources used to query wireless
>>> statistics, I hope you can help me.
>>>
>>> Currently I successfully query cfg80211 to get statistics about wireless
>>> devices such as tx bitrate, every 10 seconds. My problem is that I have
>>> been unable to do this without leaking file descriptors and memory. The
>>> code I use is inherited and I am trying to fix it, but I can't manage to
>>> release the resources without losing the retrieved data. Until now, I
>>> have read the documentation, compared with implementation examples found
>>> here and there, and consulted frequently the doxygen reference. However,
>>> I still need some more help.
>>>
>>> Issue 1: 'nl_recvmsgs_default()' will block until receiving a message if
>>> socket is configured as blocking (default), but won't wait for the
>>> callback to finish, right? So how could I possibly release the resources
>>> just after nl_recvmsgs if the callback needs the received data?
>> nl_recvmsgs_default() will block and process messages as long as (a)
>> there are messages in the receive buffer and (b) your callback returns
>> NL_SKIP.  It will wait for your callback to finish before proceeding.
>>
>> One thing I notice: there isn't a lot of sense in doing all the setup
>> every 10 seconds.  You might as well just do the setup once and then
>> every 10s do the nl_msg_alloc/send/recv.  
>>
>>> Issue 2: I have sumarized  the code so that you can check the run flow
>>> and the memory management, it's posted in pastebin:
>>> http://pastebin.com/EYADmDpy
>>> Could you have a look to it, please? It's less than 100 lines, comments
>>> included. How should I release the resources used by the nl socket and
>>> nl message?
>> The code you've got isn't freeing either 'msg' or 'sk', so you're
>> leaking both of those every 10 seconds.  How about something like this;
>> alternatively you can just make sure that both the normal and
>> nla_put_failure paths in get_wireless_stats() free both 'msg' and 'sk'.
>>
>> //// ----------- caller.c ------------------
>> /* includes */
>> int main ()
>>     struct wireless_stats ofs;
>>     struct nl_sock *sk;
>>     int family_id;
>>     int err;
>>
>>     sk = nl_socket_alloc();
>>     genl_connect(sk);
>>
>>     // WARNING, the docs say we must call genl_family_put() later and we don't!    
>>     family_id = genl_ctrl_resolve(sk, "nl80211");
>>     
>>     nl_socket_modify_cb(sk, NL_CB_VALID, NL_CB_CUSTOM,
>>         stats_handler, NULL);
>>
>>     while (true)
>>     {
>>         get_wireless_stats(sk, &ofs);
>>         /* use retrieved data */
>>     
>>         sleep_seconds(10);
>>     }
>>
>>     nl_socket_free(sk);
>> return 0;
>>
>> //// --------- wireless_stats.c -----------
>>
>> void get_wireless_stats(struct nl_socket *sk, struct wireless_stats *ofs)
>> {
>>     struct nl_msg *msg;
>>     int err;
>>
>>     shared_stats = ofs;
>>     
>>     msg = nlmsg_alloc();
>>     genlmsg_put(msg, 0, 0, family_id, 0, NLM_F_DUMP, NL80211_CMD_GET_STATION, 0;
>>     NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex("mesh0"));
>>     err = nl_send_auto_complete(sk, msg);
>>     nl_recvmsgs_default(sk);
>>     nlsmg_free(msg);
>>     return 0;
>>     
>>     // Not sure who comes here, but it isn't part of the success workflow, and is required at compilation time.
>>     // -> the NLA_PUT_U32 macro has a 'goto nla_put_failure' in case there isn't enough memory
>> nla_put_failure:
>>     nlmsg_free(msg);
>>     return err;
>> }
>>
>> <no changes to stats_handler>
>>
>



From julien.courtat at 6wind.com  Wed Jun 17 06:49:55 2015
From: julien.courtat at 6wind.com (Julien Courtat)
Date: Wed, 17 Jun 2015 15:49:55 +0200
Subject: [PATCH v2] remove automatic port id generation
In-Reply-To: <1433481206.5221.29.camel@redhat.com>
References: <1433481206.5221.29.camel@redhat.com>
Message-ID: <1434548995-10175-1-git-send-email-julien.courtat@6wind.com>

Since kernel can automatically set a unique portid to each socket any
application would bind with, there is no use to keep the portid generation
procedure made of 22 bits for the pid and 10 bits left for a pseudo
random value.
Remove this procedure and let kernel choose a port id for the socket.
It is still possible for an application to set the port id manually via
nl_socket_set_local_port().

Signed-off-by: Julien Courtat <julien.courtat at 6wind.com>
---
 lib/nl.c     |   47 +++---------------
 lib/socket.c |  153 ----------------------------------------------------------
 2 files changed, 7 insertions(+), 193 deletions(-)

diff --git a/lib/nl.c b/lib/nl.c
index 8fc9ec1..d0828fc 100644
--- a/lib/nl.c
+++ b/lib/nl.c
@@ -126,47 +126,14 @@ int nl_connect(struct nl_sock *sk, int protocol)
 	if (err < 0)
 		goto errout;
 
-	if (_nl_socket_is_local_port_unspecified (sk)) {
-		uint32_t port;
-		uint32_t used_ports[32] = { 0 };
-
-		while (1) {
-			port = _nl_socket_generate_local_port_no_release(sk);
-
-			if (port == UINT32_MAX) {
-				NL_DBG(4, "nl_connect(%p): no more unused local ports.\n", sk);
-				_nl_socket_used_ports_release_all(used_ports);
-				err = -NLE_EXIST;
-				goto errout;
-			}
-			err = bind(sk->s_fd, (struct sockaddr*) &sk->s_local,
-				   sizeof(sk->s_local));
-			if (err == 0)
-				break;
-
-			errsv = errno;
-			if (errsv == EADDRINUSE) {
-				NL_DBG(4, "nl_connect(%p): local port %u already in use. Retry.\n", sk, (unsigned) port);
-				_nl_socket_used_ports_set(used_ports, port);
-			} else {
-				NL_DBG(4, "nl_connect(%p): bind() for port %u failed with %d (%s)\n",
-					sk, (unsigned) port, errsv, strerror_r(errsv, buf, sizeof(buf)));
-				_nl_socket_used_ports_release_all(used_ports);
-				err = -nl_syserr2nlerr(errsv);
-				goto errout;
-			}
-		}
-		_nl_socket_used_ports_release_all(used_ports);
-	} else {
-		err = bind(sk->s_fd, (struct sockaddr*) &sk->s_local,
-			   sizeof(sk->s_local));
-		if (err != 0) {
-			errsv = errno;
-			NL_DBG(4, "nl_connect(%p): bind() failed with %d (%s)\n",
+	err = bind(sk->s_fd, (struct sockaddr*) &sk->s_local,
+			sizeof(sk->s_local));
+	if (err != 0) {
+		errsv = errno;
+		NL_DBG(4, "nl_connect(%p): bind() failed with %d (%s)\n",
 				sk, errsv, strerror_r(errsv, buf, sizeof(buf)));
-			err = -nl_syserr2nlerr(errsv);
-			goto errout;
-		}
+		err = -nl_syserr2nlerr(errsv);
+		goto errout;
 	}
 
 	addrlen = sizeof(local);
diff --git a/lib/socket.c b/lib/socket.c
index b29d1da..8aa909e 100644
--- a/lib/socket.c
+++ b/lib/socket.c
@@ -59,120 +59,6 @@ static void __init init_default_cb(void)
 	}
 }
 
-static uint32_t used_ports_map[32];
-static NL_RW_LOCK(port_map_lock);
-
-static uint32_t generate_local_port(void)
-{
-	int i, j, n, m;
-	static uint16_t idx_state = 0;
-	uint32_t pid = getpid() & 0x3FFFFF;
-
-	nl_write_lock(&port_map_lock);
-
-	if (idx_state == 0) {
-		uint32_t t = time(NULL);
-
-		/* from time to time (on average each 2^15 calls), the idx_state will
-		 * be zero again. No problem, just "seed" anew with time(). */
-		idx_state = t ^ (t >> 16) ^ 0x3047;
-	} else
-		idx_state = idx_state + 20011; /* add prime number */
-
-	i = idx_state >> 5;
-	n = idx_state;
-	for (j = 0; j < 32; j++) {
-		/* walk the index somewhat randomized, with always leaving the block
-		 * #0 as last. The reason is that libnl-1 will start at block #0,
-		 * so just leave the first 32 ports preferably for libnl-1 owned sockets
-		 * (this is relevant only if the applications ends up using both versions
-		 * of the library and doesn't hurt otherwise). */
-		if (j == 31)
-			i = 0;
-		else
-			i = (((i-1) + 7) % 31) + 1;
-
-		if (used_ports_map[i] == 0xFFFFFFFF)
-			continue;
-
-		for (m = 0; m < 32; m++) {
-			n = (n + 13) % 32;
-			if (1UL & (used_ports_map[i] >> n))
-				continue;
-
-			used_ports_map[i] |= (1UL << n);
-			n += (i * 32);
-
-			/* PID_MAX_LIMIT is currently at 2^22, leaving 10 bit
-			 * to, i.e. 1024 unique ports per application. */
-
-			nl_write_unlock(&port_map_lock);
-
-			return pid + (((uint32_t)n) << 22);
-		}
-	}
-
-	nl_write_unlock(&port_map_lock);
-
-	/* Out of sockets in our own PID namespace, what to do? FIXME */
-	NL_DBG(1, "Warning: Ran out of unique local port namespace\n");
-	return UINT32_MAX;
-}
-
-static void release_local_port(uint32_t port)
-{
-	int nr;
-	uint32_t mask;
-
-	if (port == UINT32_MAX)
-		return;
-
-	BUG_ON(port == 0);
-
-	nr = port >> 22;
-	mask = 1UL << (nr % 32);
-	nr /= 32;
-
-	nl_write_lock(&port_map_lock);
-	BUG_ON((used_ports_map[nr] & mask) != mask);
-	used_ports_map[nr] &= ~mask;
-	nl_write_unlock(&port_map_lock);
-}
-
-/** \cond skip */
-void _nl_socket_used_ports_release_all(const uint32_t *used_ports)
-{
-	int i;
-
-	for (i = 0; i < 32; i++) {
-		if (used_ports[i] != 0) {
-			nl_write_lock(&port_map_lock);
-			for (; i < 32; i++) {
-				BUG_ON((used_ports_map[i] & used_ports[i]) != used_ports[i]);
-				used_ports_map[i] &= ~(used_ports[i]);
-			}
-			nl_write_unlock(&port_map_lock);
-			return;
-		}
-	}
-}
-
-void _nl_socket_used_ports_set(uint32_t *used_ports, uint32_t port)
-{
-	int nr;
-	int32_t mask;
-
-	nr = port >> 22;
-	mask = 1UL << (nr % 32);
-	nr /= 32;
-
-	/*
-	BUG_ON(port == UINT32_MAX || port == 0 || (getpid() & 0x3FFFFF) != (port & 0x3FFFFF));
-	BUG_ON(used_ports[nr] & mask);
-	*/
-
-	used_ports[nr] |= mask;
-}
 /** \endcond */
 
 /**
@@ -251,9 +137,6 @@ void nl_socket_free(struct nl_sock *sk)
 	if (sk->s_fd >= 0)
 		close(sk->s_fd);
 
-	if (!(sk->s_flags & NL_OWN_PORT))
-		release_local_port(sk->s_local.nl_pid);
-
 	nl_cb_put(sk->s_cb);
 	free(sk);
 }
@@ -329,28 +212,6 @@ void nl_socket_enable_auto_ack(struct nl_sock *sk)
 	sk->s_flags &= ~NL_NO_AUTO_ACK;
 }
 
-/** @} */
-
-/** \cond skip */
-int _nl_socket_is_local_port_unspecified(struct nl_sock *sk)
-{
-	return (sk->s_local.nl_pid == 0);
-}
-
-uint32_t _nl_socket_generate_local_port_no_release(struct nl_sock *sk)
-{
-	uint32_t port;
-
-	/* reset the port to generate_local_port(), but do not release
-	 * the previously generated port. */
-
-	port = generate_local_port();
-	sk->s_flags &= ~NL_OWN_PORT;
-	sk->s_local.nl_pid = port;
-	return port;
-}
-/** \endcond */
-
 /**
  * @name Source Idenficiation
  * @{
@@ -358,18 +219,6 @@ uint32_t _nl_socket_generate_local_port_no_release(struct nl_sock *sk)
 
 uint32_t nl_socket_get_local_port(const struct nl_sock *sk)
 {
-	if (sk->s_local.nl_pid == 0) {
-		/* modify the const argument sk. This is justified, because
-		 * nobody ever saw the local_port from externally. So, we
-		 * initilize it on first use.
-		 *
-		 * Note that this also means that you cannot call this function
-		 * from multiple threads without synchronization. But nl_sock
-		 * is not automatically threadsafe anyway, so the user is not
-		 * allowed to do that.
-		 */
-		return _nl_socket_generate_local_port_no_release((struct nl_sock *) sk);
-	}
 	return sk->s_local.nl_pid;
 }
 
@@ -387,8 +236,6 @@ uint32_t nl_socket_get_local_port(const struct nl_sock *sk)
  */
 void nl_socket_set_local_port(struct nl_sock *sk, uint32_t port)
 {
-	if (!(sk->s_flags & NL_OWN_PORT))
-		release_local_port(sk->s_local.nl_pid);
 	sk->s_flags |= NL_OWN_PORT;
 	sk->s_local.nl_pid = port;
 }
-- 
1.7.10.4



From dcbw at redhat.com  Wed Jun 17 07:19:19 2015
From: dcbw at redhat.com (Dan Williams)
Date: Wed, 17 Jun 2015 09:19:19 -0500
Subject: [PATCH v2] remove automatic port id generation
In-Reply-To: <1434548995-10175-1-git-send-email-julien.courtat@6wind.com>
References: <1433481206.5221.29.camel@redhat.com>
 <1434548995-10175-1-git-send-email-julien.courtat@6wind.com>
Message-ID: <1434550759.3952.1.camel@redhat.com>

On Wed, 2015-06-17 at 15:49 +0200, Julien Courtat wrote:
> Since kernel can automatically set a unique portid to each socket any
> application would bind with, there is no use to keep the portid generation
> procedure made of 22 bits for the pid and 10 bits left for a pseudo
> random value.

I haven't looked, but how far back does that kernel functionality go?
Has it always been there?  The port code has been there since the
initial 2007 import to git, so I just feel like there must have been
some reason Thomas Graf wrote it...

Dan

> Remove this procedure and let kernel choose a port id for the socket.
> It is still possible for an application to set the port id manually via
> nl_socket_set_local_port().
> 
> Signed-off-by: Julien Courtat <julien.courtat at 6wind.com>
> ---
>  lib/nl.c     |   47 +++---------------
>  lib/socket.c |  153 ----------------------------------------------------------
>  2 files changed, 7 insertions(+), 193 deletions(-)
> 
> diff --git a/lib/nl.c b/lib/nl.c
> index 8fc9ec1..d0828fc 100644
> --- a/lib/nl.c
> +++ b/lib/nl.c
> @@ -126,47 +126,14 @@ int nl_connect(struct nl_sock *sk, int protocol)
>  	if (err < 0)
>  		goto errout;
>  
> -	if (_nl_socket_is_local_port_unspecified (sk)) {
> -		uint32_t port;
> -		uint32_t used_ports[32] = { 0 };
> -
> -		while (1) {
> -			port = _nl_socket_generate_local_port_no_release(sk);
> -
> -			if (port == UINT32_MAX) {
> -				NL_DBG(4, "nl_connect(%p): no more unused local ports.\n", sk);
> -				_nl_socket_used_ports_release_all(used_ports);
> -				err = -NLE_EXIST;
> -				goto errout;
> -			}
> -			err = bind(sk->s_fd, (struct sockaddr*) &sk->s_local,
> -				   sizeof(sk->s_local));
> -			if (err == 0)
> -				break;
> -
> -			errsv = errno;
> -			if (errsv == EADDRINUSE) {
> -				NL_DBG(4, "nl_connect(%p): local port %u already in use. Retry.\n", sk, (unsigned) port);
> -				_nl_socket_used_ports_set(used_ports, port);
> -			} else {
> -				NL_DBG(4, "nl_connect(%p): bind() for port %u failed with %d (%s)\n",
> -					sk, (unsigned) port, errsv, strerror_r(errsv, buf, sizeof(buf)));
> -				_nl_socket_used_ports_release_all(used_ports);
> -				err = -nl_syserr2nlerr(errsv);
> -				goto errout;
> -			}
> -		}
> -		_nl_socket_used_ports_release_all(used_ports);
> -	} else {
> -		err = bind(sk->s_fd, (struct sockaddr*) &sk->s_local,
> -			   sizeof(sk->s_local));
> -		if (err != 0) {
> -			errsv = errno;
> -			NL_DBG(4, "nl_connect(%p): bind() failed with %d (%s)\n",
> +	err = bind(sk->s_fd, (struct sockaddr*) &sk->s_local,
> +			sizeof(sk->s_local));
> +	if (err != 0) {
> +		errsv = errno;
> +		NL_DBG(4, "nl_connect(%p): bind() failed with %d (%s)\n",
>  				sk, errsv, strerror_r(errsv, buf, sizeof(buf)));
> -			err = -nl_syserr2nlerr(errsv);
> -			goto errout;
> -		}
> +		err = -nl_syserr2nlerr(errsv);
> +		goto errout;
>  	}
>  
>  	addrlen = sizeof(local);
> diff --git a/lib/socket.c b/lib/socket.c
> index b29d1da..8aa909e 100644
> --- a/lib/socket.c
> +++ b/lib/socket.c
> @@ -59,120 +59,6 @@ static void __init init_default_cb(void)
>  	}
>  }
>  
> -static uint32_t used_ports_map[32];
> -static NL_RW_LOCK(port_map_lock);
> -
> -static uint32_t generate_local_port(void)
> -{
> -	int i, j, n, m;
> -	static uint16_t idx_state = 0;
> -	uint32_t pid = getpid() & 0x3FFFFF;
> -
> -	nl_write_lock(&port_map_lock);
> -
> -	if (idx_state == 0) {
> -		uint32_t t = time(NULL);
> -
> -		/* from time to time (on average each 2^15 calls), the idx_state will
> -		 * be zero again. No problem, just "seed" anew with time(). */
> -		idx_state = t ^ (t >> 16) ^ 0x3047;
> -	} else
> -		idx_state = idx_state + 20011; /* add prime number */
> -
> -	i = idx_state >> 5;
> -	n = idx_state;
> -	for (j = 0; j < 32; j++) {
> -		/* walk the index somewhat randomized, with always leaving the block
> -		 * #0 as last. The reason is that libnl-1 will start at block #0,
> -		 * so just leave the first 32 ports preferably for libnl-1 owned sockets
> -		 * (this is relevant only if the applications ends up using both versions
> -		 * of the library and doesn't hurt otherwise). */
> -		if (j == 31)
> -			i = 0;
> -		else
> -			i = (((i-1) + 7) % 31) + 1;
> -
> -		if (used_ports_map[i] == 0xFFFFFFFF)
> -			continue;
> -
> -		for (m = 0; m < 32; m++) {
> -			n = (n + 13) % 32;
> -			if (1UL & (used_ports_map[i] >> n))
> -				continue;
> -
> -			used_ports_map[i] |= (1UL << n);
> -			n += (i * 32);
> -
> -			/* PID_MAX_LIMIT is currently at 2^22, leaving 10 bit
> -			 * to, i.e. 1024 unique ports per application. */
> -
> -			nl_write_unlock(&port_map_lock);
> -
> -			return pid + (((uint32_t)n) << 22);
> -		}
> -	}
> -
> -	nl_write_unlock(&port_map_lock);
> -
> -	/* Out of sockets in our own PID namespace, what to do? FIXME */
> -	NL_DBG(1, "Warning: Ran out of unique local port namespace\n");
> -	return UINT32_MAX;
> -}
> -
> -static void release_local_port(uint32_t port)
> -{
> -	int nr;
> -	uint32_t mask;
> -
> -	if (port == UINT32_MAX)
> -		return;
> -
> -	BUG_ON(port == 0);
> -
> -	nr = port >> 22;
> -	mask = 1UL << (nr % 32);
> -	nr /= 32;
> -
> -	nl_write_lock(&port_map_lock);
> -	BUG_ON((used_ports_map[nr] & mask) != mask);
> -	used_ports_map[nr] &= ~mask;
> -	nl_write_unlock(&port_map_lock);
> -}
> -
> -/** \cond skip */
> -void _nl_socket_used_ports_release_all(const uint32_t *used_ports)
> -{
> -	int i;
> -
> -	for (i = 0; i < 32; i++) {
> -		if (used_ports[i] != 0) {
> -			nl_write_lock(&port_map_lock);
> -			for (; i < 32; i++) {
> -				BUG_ON((used_ports_map[i] & used_ports[i]) != used_ports[i]);
> -				used_ports_map[i] &= ~(used_ports[i]);
> -			}
> -			nl_write_unlock(&port_map_lock);
> -			return;
> -		}
> -	}
> -}
> -
> -void _nl_socket_used_ports_set(uint32_t *used_ports, uint32_t port)
> -{
> -	int nr;
> -	int32_t mask;
> -
> -	nr = port >> 22;
> -	mask = 1UL << (nr % 32);
> -	nr /= 32;
> -
> -	/*
> -	BUG_ON(port == UINT32_MAX || port == 0 || (getpid() & 0x3FFFFF) != (port & 0x3FFFFF));
> -	BUG_ON(used_ports[nr] & mask);
> -	*/
> -
> -	used_ports[nr] |= mask;
> -}
>  /** \endcond */
>  
>  /**
> @@ -251,9 +137,6 @@ void nl_socket_free(struct nl_sock *sk)
>  	if (sk->s_fd >= 0)
>  		close(sk->s_fd);
>  
> -	if (!(sk->s_flags & NL_OWN_PORT))
> -		release_local_port(sk->s_local.nl_pid);
> -
>  	nl_cb_put(sk->s_cb);
>  	free(sk);
>  }
> @@ -329,28 +212,6 @@ void nl_socket_enable_auto_ack(struct nl_sock *sk)
>  	sk->s_flags &= ~NL_NO_AUTO_ACK;
>  }
>  
> -/** @} */
> -
> -/** \cond skip */
> -int _nl_socket_is_local_port_unspecified(struct nl_sock *sk)
> -{
> -	return (sk->s_local.nl_pid == 0);
> -}
> -
> -uint32_t _nl_socket_generate_local_port_no_release(struct nl_sock *sk)
> -{
> -	uint32_t port;
> -
> -	/* reset the port to generate_local_port(), but do not release
> -	 * the previously generated port. */
> -
> -	port = generate_local_port();
> -	sk->s_flags &= ~NL_OWN_PORT;
> -	sk->s_local.nl_pid = port;
> -	return port;
> -}
> -/** \endcond */
> -
>  /**
>   * @name Source Idenficiation
>   * @{
> @@ -358,18 +219,6 @@ uint32_t _nl_socket_generate_local_port_no_release(struct nl_sock *sk)
>  
>  uint32_t nl_socket_get_local_port(const struct nl_sock *sk)
>  {
> -	if (sk->s_local.nl_pid == 0) {
> -		/* modify the const argument sk. This is justified, because
> -		 * nobody ever saw the local_port from externally. So, we
> -		 * initilize it on first use.
> -		 *
> -		 * Note that this also means that you cannot call this function
> -		 * from multiple threads without synchronization. But nl_sock
> -		 * is not automatically threadsafe anyway, so the user is not
> -		 * allowed to do that.
> -		 */
> -		return _nl_socket_generate_local_port_no_release((struct nl_sock *) sk);
> -	}
>  	return sk->s_local.nl_pid;
>  }
>  
> @@ -387,8 +236,6 @@ uint32_t nl_socket_get_local_port(const struct nl_sock *sk)
>   */
>  void nl_socket_set_local_port(struct nl_sock *sk, uint32_t port)
>  {
> -	if (!(sk->s_flags & NL_OWN_PORT))
> -		release_local_port(sk->s_local.nl_pid);
>  	sk->s_flags |= NL_OWN_PORT;
>  	sk->s_local.nl_pid = port;
>  }




From jbernard at toulouse.viveris.fr  Wed Jun 17 07:31:18 2015
From: jbernard at toulouse.viveris.fr (Julien BERNARD)
Date: Wed, 17 Jun 2015 16:31:18 +0200
Subject: cannot set TUN interface up/down with Python API (wrapper)
In-Reply-To: <1429536373.7093.22.camel@redhat.com>
References: <5530FD11.9040308@toulouse.viveris.com>
 <1429536373.7093.22.camel@redhat.com>
Message-ID: <558184B6.9040307@toulouse.viveris.fr>

Hi Thomas,

Thanks for your answer.

I'm working the problem with David.

I tried with older versions. On Ubuntu 12.04 LTS the version was 3.2.3 
and this was the only version I could get to work.

The last working revision is 88940b71f81525b1080fcdd5a029537e9a85ca38, 
the revision just after the 3.2.3 release.
The next revision (ef75c4edf0930b4d745da695c5fe0075c7b3afdd) introduces 
a segfault in the script that is resolved in the 3.2.5 release (this 
should be the fix introduced by the revision 
4035e5b5e88529e6c7a12c41dcd8637ed69498d9).
Thus, I applied the fix on the revision 
ef75c4edf0930b4d745da695c5fe0075c7b3afdd and I can confirm that the 
problem was introduced by this revision.
However I'm not familiar enough with all of this to determine exactly 
what causes the bug.

Could you please help me to understand what really causes this error?

Regards,

-- 
Julien



Le 20/04/2015 15:26, Thomas Haller a ?crit :
> On Fri, 2015-04-17 at 14:31 +0200, David Pradas wrote:
>> Hi,
>
> Hi David,
>
>
>> I'm having a problem when using the Pyhton API (wrapper) for link
>> management (change address, set state up/down). I am not able to set a
>> TUN interface up/down with the python wrapper. However, I am capable of
>> doing that with the "C" API.
>> This is the procedure I follow:
>>
>> 1. I first create the TUN interface "tun0":
>>
>> /sudo ip tuntap add dev tun0 mode tun/
>>
>> 2. Then, I execute my python script (test.py):
>>
>> /#!/usr/bin/env python2//
>> //import netlink.route.link as link//
>> //import netlink.core as netlink//
>> //import netlink.route.address as address//
>> //
>> //sock = netlink.Socket()//
>> //sock.connect(netlink.NETLINK_ROUTE)//
>> //cache = link.LinkCache()//
>> //cache.refill(sock)//
>> //iface = cache['tun0']//
>> //iface.flags = ['-up']//
>> /*/iface.change()/*/
> can you attach a small (working) reproducer? Where is this test.py
> script?
>
> You say it works via the "C" API. Did you write the same code in plain C
> and that was working?
>
>
>> 3. Finally, I obtain the following output when the file "test.py" has
>> been executed.
>>
>> I get an " Invalid input data or parameter" exception when I call the
>> "iface.change()" :
>>
>> //  nl_recvmsgs_report() returns error
>> //  Traceback (most recent call last):
>> //  File "./test.py", line 12, in <module>
>> //    iface.change()
>> //  File "/usr/local/lib/python2.7/dist-packages/netlink/route/link.py",
>> line 409, in change
>> //    raise netlink.KernelError(ret)
>> // netlink.core.KernelError: Kernel returned: Invalid input data or
>> parameter
>>
>> On the other hand, I am capable of setting up/down other interfaces
>> which are not tun/tap (such as "eth") following the same method.
>> However, even in that case, I obtain the following error:
>>
>> // File "./test.py", line 12, in <module>
>> //   iface.change()
>> //  File "/usr/local/lib/python2.7/dist-packages/netlink/route/link.py",
>> line 409, in change
>> //    raise netlink.KernelError(ret)
>> // netlink.core.KernelError: Kernel returned: Message sequence number
>> mismatch
>>
>> I can not figure out where the problem is. Any ideas please?
> Hm... I don't know. Try enabling debug logging for libnl via
>
> export NLDBG=100
>
>
>
>> I am running Ubuntu 14.04 LTS 64 bits and using the last release of
>> libnl 3.2.26 (I have also tried 3.2.25 with same results) . FYI: the
>> Python wrapper was correctly working with Ubuntu 12.04 LTS 64 bits, i.e.
>> I could set the TUN up/down without problems.
> you could try whether an older version works, and then finding the
> version that breaks your script (e.g. using git bisec).
>
>
> Thomas
>
>
> _______________________________________________
> libnl mailing list
> libnl at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/libnl



From nicolas.dichtel at 6wind.com  Thu Jun 18 05:22:54 2015
From: nicolas.dichtel at 6wind.com (Nicolas Dichtel)
Date: Thu, 18 Jun 2015 14:22:54 +0200
Subject: [PATCH v2] remove automatic port id generation
In-Reply-To: <1434550759.3952.1.camel@redhat.com>
References: <1433481206.5221.29.camel@redhat.com>	
 <1434548995-10175-1-git-send-email-julien.courtat@6wind.com>
 <1434550759.3952.1.camel@redhat.com>
Message-ID: <5582B81E.7000207@6wind.com>

Le 17/06/2015 16:19, Dan Williams a ?crit :
> On Wed, 2015-06-17 at 15:49 +0200, Julien Courtat wrote:
>> Since kernel can automatically set a unique portid to each socket any
>> application would bind with, there is no use to keep the portid generation
>> procedure made of 22 bits for the pid and 10 bits left for a pseudo
>> random value.
>
> I haven't looked, but how far back does that kernel functionality go?
> Has it always been there?  The port code has been there since the
> initial 2007 import to git, so I just feel like there must have been
> some reason Thomas Graf wrote it...
Thomas, do you some information about this?


Regards,
Nicolas


From ranker72 at gmail.com  Thu Jun 18 06:50:22 2015
From: ranker72 at gmail.com (ferran)
Date: Thu, 18 Jun 2015 15:50:22 +0200
Subject: Resources cleanup upon using received data
In-Reply-To: <557F247A.8030803@gmail.com>
References: <557AF9C3.3060809@gmail.com> <1434126803.4018.21.camel@redhat.com>
 <557F1A1A.6080009@gmail.com> <557F247A.8030803@gmail.com>
Message-ID: <5582CC9E.1060500@gmail.com>

Hi there,

I have advanced on this. The reason why the callback isn't executed is
that actually the socket hasn't been allocated. Capturing the error, I
get error code -6, that is,  NLE_EXIST, "Object exists" and system's
EEXIST or EADDRINUSE.

When I didn't do nl_socket_free and consequently, didn't close the
socket, nl lib kept assigning me sockets with different local ports.
However, if I do free the socket, for some nl lib tries to assign me a
socket with a local port that is still in use. This is my problem.

For some reason the library thinks that a local port is available when
it really isn't. What could motivate this misbehavior?

Regards,
Ferran

On 15/06/15 21:16, ferran wrote:
> Hi,
>
> I forgot to mention that the callback, when called, is always called
> twice. However, I don't free any resource inside the callback, but after it.
>
> I can't figure out how freeing the socket after the callback can prevent
> the callback itself to be called.
>
> Regards,
> Ferran
>
> On 15/06/15 20:31, ferran wrote:
>> Hi Dan,
>> Thank you for your kind reply.
>>
>> I agree that the nice way to go would be to reuse the same socket, but I
>> can't access to the upper level, in the example, "caller.c". It's part
>> of a wider project, and I'm afraid that it would break a level of
>> abstraction.
>>
>> I have to add information: "get_wireless_stats" is called once per
>> wireless device each 10 seconds. Therefore, "caller.c", in practice, is
>> doing:
>>
>> int main ()
>>     struct wireless_stats ofs;
>>     while (true)
>>     {
>>         for_each_dev(device)
>>         {
>>             get_wireless_stats(device, &ofs);
>>         }
>>         sleep_seconds(10);
>>     }
>> return 0;
>>
>> Where "device" is a string that is translated with "if_nametoindex"
>> inside "get_wireless_stats". Each device is queried one after the other
>> without threading or alike.
>>
>> This said, I tried again with more verbose logging and freed the msg and
>> socket resources before finishing "get_wireless_stats". I get the stats
>> doing :
>> ...
>>
>>     nlsmg_free(msg);
>>     nl_close(sk);
>>     return 0;
>>     
>> nla_put_failure:
>>     nlmsg_free(msg);
>>     nl_close(sk);
>>     return err;
>> }
>>
>> But if I do "nl_socket_free(sk)" instead of "nl_close(sk)", then the
>> callback isn't called, and the stats don't get copied to the target
>> structure. Does it make any sense to you?
>>
>> Regards,
>> Ferran
>>
>> On 12/06/15 18:33, Dan Williams wrote:
>>> On Fri, 2015-06-12 at 17:24 +0200, ferran wrote:
>>>> Hello everyone,
>>>> I have some issues at managing resources used to query wireless
>>>> statistics, I hope you can help me.
>>>>
>>>> Currently I successfully query cfg80211 to get statistics about wireless
>>>> devices such as tx bitrate, every 10 seconds. My problem is that I have
>>>> been unable to do this without leaking file descriptors and memory. The
>>>> code I use is inherited and I am trying to fix it, but I can't manage to
>>>> release the resources without losing the retrieved data. Until now, I
>>>> have read the documentation, compared with implementation examples found
>>>> here and there, and consulted frequently the doxygen reference. However,
>>>> I still need some more help.
>>>>
>>>> Issue 1: 'nl_recvmsgs_default()' will block until receiving a message if
>>>> socket is configured as blocking (default), but won't wait for the
>>>> callback to finish, right? So how could I possibly release the resources
>>>> just after nl_recvmsgs if the callback needs the received data?
>>> nl_recvmsgs_default() will block and process messages as long as (a)
>>> there are messages in the receive buffer and (b) your callback returns
>>> NL_SKIP.  It will wait for your callback to finish before proceeding.
>>>
>>> One thing I notice: there isn't a lot of sense in doing all the setup
>>> every 10 seconds.  You might as well just do the setup once and then
>>> every 10s do the nl_msg_alloc/send/recv.  
>>>
>>>> Issue 2: I have sumarized  the code so that you can check the run flow
>>>> and the memory management, it's posted in pastebin:
>>>> http://pastebin.com/EYADmDpy
>>>> Could you have a look to it, please? It's less than 100 lines, comments
>>>> included. How should I release the resources used by the nl socket and
>>>> nl message?
>>> The code you've got isn't freeing either 'msg' or 'sk', so you're
>>> leaking both of those every 10 seconds.  How about something like this;
>>> alternatively you can just make sure that both the normal and
>>> nla_put_failure paths in get_wireless_stats() free both 'msg' and 'sk'.
>>>
>>> //// ----------- caller.c ------------------
>>> /* includes */
>>> int main ()
>>>     struct wireless_stats ofs;
>>>     struct nl_sock *sk;
>>>     int family_id;
>>>     int err;
>>>
>>>     sk = nl_socket_alloc();
>>>     genl_connect(sk);
>>>
>>>     // WARNING, the docs say we must call genl_family_put() later and we don't!    
>>>     family_id = genl_ctrl_resolve(sk, "nl80211");
>>>     
>>>     nl_socket_modify_cb(sk, NL_CB_VALID, NL_CB_CUSTOM,
>>>         stats_handler, NULL);
>>>
>>>     while (true)
>>>     {
>>>         get_wireless_stats(sk, &ofs);
>>>         /* use retrieved data */
>>>     
>>>         sleep_seconds(10);
>>>     }
>>>
>>>     nl_socket_free(sk);
>>> return 0;
>>>
>>> //// --------- wireless_stats.c -----------
>>>
>>> void get_wireless_stats(struct nl_socket *sk, struct wireless_stats *ofs)
>>> {
>>>     struct nl_msg *msg;
>>>     int err;
>>>
>>>     shared_stats = ofs;
>>>     
>>>     msg = nlmsg_alloc();
>>>     genlmsg_put(msg, 0, 0, family_id, 0, NLM_F_DUMP, NL80211_CMD_GET_STATION, 0;
>>>     NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex("mesh0"));
>>>     err = nl_send_auto_complete(sk, msg);
>>>     nl_recvmsgs_default(sk);
>>>     nlsmg_free(msg);
>>>     return 0;
>>>     
>>>     // Not sure who comes here, but it isn't part of the success workflow, and is required at compilation time.
>>>     // -> the NLA_PUT_U32 macro has a 'goto nla_put_failure' in case there isn't enough memory
>>> nla_put_failure:
>>>     nlmsg_free(msg);
>>>     return err;
>>> }
>>>
>>> <no changes to stats_handler>
>>>




From thaller at redhat.com  Fri Jun 19 09:14:50 2015
From: thaller at redhat.com (Thomas Haller)
Date: Fri, 19 Jun 2015 18:14:50 +0200
Subject: [PATCH 1/2] Add ipvlan support
In-Reply-To: <1433911990-14569-1-git-send-email-xiyou.wangcong@gmail.com>
References: <1433911990-14569-1-git-send-email-xiyou.wangcong@gmail.com>
Message-ID: <1434730490.29331.14.camel@redhat.com>

On Tue, 2015-06-09 at 21:53 -0700, Cong Wang wrote:
> Signed-off-by: Cong Wang <xiyou.wangcong at gmail.com>
> ---
>  include/Makefile.am                   |   1 +
>  include/linux-private/linux/if_link.h |  15 ++
>  include/netlink/route/link/ipvlan.h   |  37 +++++
>  lib/Makefile.am                       |   2 +-
>  lib/route/link/ipvlan.c               | 279 
> ++++++++++++++++++++++++++++++++++
>  libnl-route-3.sym                     |  10 ++
>  6 files changed, 343 insertions(+), 1 deletion(-)
>  create mode 100644 include/netlink/route/link/ipvlan.h
>  create mode 100644 lib/route/link/ipvlan.c
> 
> diff --git a/include/Makefile.am b/include/Makefile.am
> index bf86ed1..ffaa9a5 100644
> --- a/include/Makefile.am
> +++ b/include/Makefile.am
> @@ -60,6 +60,7 @@ nobase_libnlinclude_HEADERS = \
>  	netlink/route/link/ipip.h \
>  	netlink/route/link/ipvti.h \
>  	netlink/route/link/sit.h \
> +	netlink/route/link/ipvlan.h \
>  	netlink/route/qdisc/cbq.h \
>  	netlink/route/qdisc/dsmark.h \
>  	netlink/route/qdisc/fifo.h \
> diff --git a/include/linux-private/linux/if_link.h b/include/linux
> -private/linux/if_link.h
> index ff95760..69e30d0 100644
> --- a/include/linux-private/linux/if_link.h
> +++ b/include/linux-private/linux/if_link.h
> @@ -305,6 +305,21 @@ enum macvlan_mode {
>  
>  #define MACVLAN_FLAG_NOPROMISC	1
>  
> +/* IPVLAN section */
> +enum {
> +	IFLA_IPVLAN_UNSPEC,
> +	IFLA_IPVLAN_MODE,
> +	__IFLA_IPVLAN_MAX
> +};
> +
> +#define IFLA_IPVLAN_MAX (__IFLA_IPVLAN_MAX - 1)
> +
> +enum ipvlan_mode {
> +	IPVLAN_MODE_L2 = 0,
> +	IPVLAN_MODE_L3,
> +	IPVLAN_MODE_MAX
> +};
> +
>  /* VXLAN section */
>  enum {
>  	IFLA_VXLAN_UNSPEC,
> diff --git a/include/netlink/route/link/ipvlan.h 
> b/include/netlink/route/link/ipvlan.h
> new file mode 100644
> index 0000000..21cce85
> --- /dev/null
> +++ b/include/netlink/route/link/ipvlan.h
> @@ -0,0 +1,37 @@
> +/*
> + * netlink/route/link/ipvlan.h		IPVLAN interface
> + *
> + *	This library is free software; you can redistribute it 
> and/or
> + *	modify it under the terms of the GNU Lesser General Public
> + *	License as published by the Free Software Foundation version 
> 2.1
> + *	of the License.
> + *
> + * Copyright (c) 2015 Cong Wang <cwang at twopensource.com>
> + */
> +
> +#ifndef NETLINK_LINK_IPVLAN_H_
> +#define NETLINK_LINK_IPVLAN_H_
> +
> +#include <netlink/netlink.h>
> +#include <netlink/route/link.h>
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif
> +
> +extern struct rtnl_link *rtnl_link_ipvlan_alloc(void);
> +
> +extern int		rtnl_link_is_ipvlan(struct rtnl_link *);
> +
> +extern char *		rtnl_link_ipvlan_mode2str(int, char *, 
> size_t);
> +extern int		rtnl_link_ipvlan_str2mode(const char *);
> +
> +extern int		rtnl_link_ipvlan_set_mode(struct rtnl_link 
> *,
> +			                           uint16_t);
> +extern uint16_t		rtnl_link_ipvlan_get_mode(struct 
> rtnl_link *);
> +
> +#ifdef __cplusplus
> +}
> +#endif
> +
> +#endif
> diff --git a/lib/Makefile.am b/lib/Makefile.am
> index 92f812c..1474c8d 100644
> --- a/lib/Makefile.am
> +++ b/lib/Makefile.am
> @@ -110,7 +110,7 @@ libnl_route_3_la_SOURCES = \
>  	route/link/bonding.c route/link/can.c route/link/macvlan.c \
>  	route/link/vxlan.c route/link/veth.c route/link/ipip.c \
>  	route/link/ipgre.c route/link/sit.c route/link/ipvti.c \
> -	route/link/ip6tnl.c route/link/ifb.c \
> +	route/link/ip6tnl.c route/link/ifb.c route/link/ipvlan.c \
>  	\
>  	route/qdisc/blackhole.c route/qdisc/cbq.c 
> route/qdisc/dsmark.c \
>  	route/qdisc/fifo.c route/qdisc/htb.c route/qdisc/netem.c \
> diff --git a/lib/route/link/ipvlan.c b/lib/route/link/ipvlan.c
> new file mode 100644
> index 0000000..2ad56f8
> --- /dev/null
> +++ b/lib/route/link/ipvlan.c
> @@ -0,0 +1,279 @@
> +/*
> + * lib/route/link/ipvlan.c	IPVLAN Link Info
> + *
> + *	This library is free software; you can redistribute it 
> and/or
> + *	modify it under the terms of the GNU Lesser General Public
> + *	License as published by the Free Software Foundation version 
> 2.1
> + *	of the License.
> + *
> + * Copyright (c) 2015 Cong Wang <cwang at twopensource.com>
> + */
> +
> +/**
> + * @ingroup link
> + * @defgroup ipvlan IPVLAN
> + * IP-based Virtual LAN link module
> + *
> + * @details
> + * \b Link Type Name: "ipvlan"
> + *
> + * @route_doc{link_ipvlan, IPVLAN Documentation}
> + *
> + * @{
> + */
> +
> +#include <netlink-private/netlink.h>
> +#include <netlink/netlink.h>
> +#include <netlink/attr.h>
> +#include <netlink/utils.h>
> +#include <netlink/object.h>
> +#include <netlink/route/rtnl.h>
> +#include <netlink-private/route/link/api.h>
> +#include <netlink/route/link/ipvlan.h>
> +
> +#include <linux/if_link.h>
> +
> +/** @cond SKIP */
> +#define IPVLAN_HAS_MODE	(1<<0)
> +
> +struct ipvlan_info
> +{
> +	uint16_t		ipi_mode;
> +	uint32_t		ipi_mask;
> +};
> +
> +/** @endcond */
> +
> +static struct nla_policy ipvlan_policy[IFLA_IPVLAN_MAX+1] = {
> +	[IFLA_IPVLAN_MODE]	= { .type = NLA_U16 },
> +};
> +
> +static int ipvlan_alloc(struct rtnl_link *link)
> +{
> +	struct ipvlan_info *ipi;
> +
> +	if (link->l_info)
> +		memset(link->l_info, 0, sizeof(*ipi));
> +	else {
> +		if ((ipi = calloc(1, sizeof(*ipi))) == NULL)
> +			return -NLE_NOMEM;
> +
> +		link->l_info = ipi;
> +	}
> +
> +	return 0;
> +}
> +
> +static int ipvlan_parse(struct rtnl_link *link, struct nlattr *data,
> +                         struct nlattr *xstats)
> +{
> +	struct nlattr *tb[IFLA_IPVLAN_MAX+1];
> +	struct ipvlan_info *ipi;
> +	int err;
> +
> +	NL_DBG(3, "Parsing IPVLAN link info");
> +
> +	if ((err = nla_parse_nested(tb, IFLA_IPVLAN_MAX, data, 
> ipvlan_policy)) < 0)
> +		goto errout;
> +
> +	if ((err = ipvlan_alloc(link)) < 0)
> +		goto errout;
> +
> +	ipi = link->l_info;
> +
> +	if (tb[IFLA_IPVLAN_MODE]) {
> +		ipi->ipi_mode = nla_get_u16(tb[IFLA_IPVLAN_MODE]);
> +		ipi->ipi_mask |= IPVLAN_HAS_MODE;
> +	}
> +
> +	err = 0;
> +errout:
> +	return err;
> +}
> +
> +static void ipvlan_free(struct rtnl_link *link)
> +{
> +	free(link->l_info);
> +	link->l_info = NULL;
> +}
> +
> +static void ipvlan_dump(struct rtnl_link *link, struct 
> nl_dump_params *p)
> +{
> +	char buf[64];
> +	struct ipvlan_info *ipi = link->l_info;
> +
> +	if (ipi->ipi_mask & IPVLAN_HAS_MODE) {
> +		rtnl_link_ipvlan_mode2str(ipi->ipi_mode, buf, 
> sizeof(buf));
> +		nl_dump(p, "ipvlan-mode %s", buf);
> +	}
> +}
> +
> +static int ipvlan_clone(struct rtnl_link *dst, struct rtnl_link 
> *src)
> +{
> +	struct ipvlan_info *vdst, *vsrc = src->l_info;
> +	int err;
> +
> +	dst->l_info = NULL;
> +	if ((err = rtnl_link_set_type(dst, "ipvlan")) < 0)
> +		return err;
> +	vdst = dst->l_info;
> +
> +	if (!vdst || !vsrc)
> +		return -NLE_NOMEM;
> +
> +	memcpy(vdst, vsrc, sizeof(struct ipvlan_info));
> +
> +	return 0;
> +}
> +
> +static int ipvlan_put_attrs(struct nl_msg *msg, struct rtnl_link 
> *link)
> +{
> +	struct ipvlan_info *ipi = link->l_info;
> +	struct nlattr *data;
> +
> +	if (!(data = nla_nest_start(msg, IFLA_INFO_DATA)))
> +		return -NLE_MSGSIZE;
> +
> +	if (ipi->ipi_mask & IPVLAN_HAS_MODE)
> +		NLA_PUT_U16(msg, IFLA_IPVLAN_MODE, ipi->ipi_mode);
> +
> +	nla_nest_end(msg, data);
> +
> +nla_put_failure:
> +
> +	return 0;
> +}
> +
> +static struct rtnl_link_info_ops ipvlan_info_ops = {
> +	.io_name		= "ipvlan",
> +	.io_alloc		= ipvlan_alloc,
> +	.io_parse		= ipvlan_parse,
> +	.io_dump = {
> +	    [NL_DUMP_LINE]	= ipvlan_dump,
> +	    [NL_DUMP_DETAILS]	= ipvlan_dump,
> +	},
> +	.io_clone		= ipvlan_clone,
> +	.io_put_attrs		= ipvlan_put_attrs,
> +	.io_free		= ipvlan_free,
> +};
> +
> +/** @cond SKIP */
> +#define IS_IPVLAN_LINK_ASSERT(link) \
> +	if ((link)->l_info_ops != &ipvlan_info_ops) { \
> +		APPBUG("Link is not a ipvlan link. set type 
> \"ipvlan\" first."); \
> +		return -NLE_OPNOTSUPP; \
> +	}
> +/** @endcond */
> +
> +/**
> + * @name IPVLAN Object
> + * @{
> + */
> +
> +/**
> + * Allocate link object of type IPVLAN
> + *
> + * @return Allocated link object or NULL.
> + */
> +struct rtnl_link *rtnl_link_ipvlan_alloc(void)
> +{
> +	struct rtnl_link *link;
> +	int err;
> +
> +	if (!(link = rtnl_link_alloc()))
> +		return NULL;
> +
> +	if ((err = rtnl_link_set_type(link, "ipvlan")) < 0) {
> +		rtnl_link_put(link);
> +		return NULL;
> +	}
> +
> +	return link;
> +}
> +
> +/**
> + * Check if link is a IPVLAN link
> + * @arg link		Link object
> + *
> + * @return True if link is a IPVLAN link, otherwise false is 
> returned.
> + */
> +int rtnl_link_is_ipvlan(struct rtnl_link *link)
> +{
> +	return link->l_info_ops && !strcmp(link->l_info_ops
> ->io_name, "ipvlan");
> +}
> +
> +/**
> + * Set IPVLAN MODE
> + * @arg link		Link object
> + * @arg mode		IPVLAN mode
> + *
> + * @return 0 on success or a negative error code
> + */
> +int rtnl_link_ipvlan_set_mode(struct rtnl_link *link, uint16_t mode)
> +{
> +	struct ipvlan_info *ipi = link->l_info;
> +
> +	IS_IPVLAN_LINK_ASSERT(link);
> +
> +	if (mode != IPVLAN_MODE_L2 && mode != IPVLAN_MODE_L3)
> +		return -NLE_INVAL;
> +
> +	ipi->ipi_mode = mode;
> +	ipi->ipi_mask |= IPVLAN_HAS_MODE;
> +
> +	return 0;
> +}
> +
> +/**
> + * Get IPVLAN Mode
> + * @arg link		Link object
> + *
> + * @return IPVLAN mode, 0 if not set or a negative error code.
> + */
> +uint16_t rtnl_link_ipvlan_get_mode(struct rtnl_link *link)
> +{
> +	struct ipvlan_info *ipi = link->l_info;
> +
> +	IS_IPVLAN_LINK_ASSERT(link);
> +
> +	if (ipi->ipi_mask & IPVLAN_HAS_MODE)
> +		return ipi->ipi_mode;
> +	else
> +		return 0;
> +}
> +
> +/** @} */
> +
> +static const struct trans_tbl ipvlan_modes[] = {
> +	__ADD(IPVLAN_MODE_L2, l2),
> +	__ADD(IPVLAN_MODE_L3, l3),
> +};
> +
> +/**
> + * @name Mode Translation
> + * @{
> + */
> +
> +char *rtnl_link_ipvlan_mode2str(int mode, char *buf, size_t len)
> +{
> +	return __type2str(mode, buf, len, ipvlan_modes, 
> ARRAY_SIZE(ipvlan_modes));
> +}
> +
> +int rtnl_link_ipvlan_str2mode(const char *name)
> +{
> +	return __str2type(name, ipvlan_modes, 
> ARRAY_SIZE(ipvlan_modes));
> +}
> +
> +/** @} */
> +
> +static void __init ipvlan_init(void)
> +{
> +	rtnl_link_register_info(&ipvlan_info_ops);
> +}
> +
> +static void __exit ipvlan_exit(void)
> +{
> +	rtnl_link_unregister_info(&ipvlan_info_ops);
> +}
> +
> +/** @} */
> diff --git a/libnl-route-3.sym b/libnl-route-3.sym
> index ad2ed36..f55a162 100644
> --- a/libnl-route-3.sym
> +++ b/libnl-route-3.sym
> @@ -872,3 +872,13 @@ global:
>  	rtnl_tc_str2stat;
>  	rtnl_u32_get_classid;
>  } libnl_3;
> +
> +libnl_3_2_27 {
> +global:
> +	rtnl_link_ipvlan_alloc;
> +	rtnl_link_is_ipvlan;
> +	rtnl_link_ipvlan_mode2str;
> +	rtnl_link_ipvlan_str2mode;
> +	rtnl_link_ipvlan_set_mode;
> +	rtnl_link_ipvlan_get_mode;
> +} libnl_3_2_26;
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/libnl/attachments/20150619/1b1c4320/attachment.sig>

From thaller at redhat.com  Fri Jun 19 09:14:47 2015
From: thaller at redhat.com (Thomas Haller)
Date: Fri, 19 Jun 2015 18:14:47 +0200
Subject: [PATCH 1/2] Add ipvlan support
In-Reply-To: <1433911990-14569-1-git-send-email-xiyou.wangcong@gmail.com>
References: <1433911990-14569-1-git-send-email-xiyou.wangcong@gmail.com>
Message-ID: <1434730487.29331.13.camel@redhat.com>

On Tue, 2015-06-09 at 21:53 -0700, Cong Wang wrote:
> Signed-off-by: Cong Wang <xiyou.wangcong at gmail.com>
> ---
>  include/Makefile.am                   |   1 +
>  include/linux-private/linux/if_link.h |  15 ++
>  include/netlink/route/link/ipvlan.h   |  37 +++++
>  lib/Makefile.am                       |   2 +-
>  lib/route/link/ipvlan.c               | 279 
> ++++++++++++++++++++++++++++++++++
>  libnl-route-3.sym                     |  10 ++
>  6 files changed, 343 insertions(+), 1 deletion(-)
>  create mode 100644 include/netlink/route/link/ipvlan.h
>  create mode 100644 lib/route/link/ipvlan.c


Hi Cong,

Thanks for the patches. Both unmodified applied as
https://github.com/thom311/libnl/commit/12e87e444dc4ffd4e5d3ca2e99b08e4
e22665a86




Two follow-up questions though...


> +int rtnl_link_ipvlan_set_mode(struct rtnl_link *link, uint16_t mode)
> +{
> +	struct ipvlan_info *ipi = link->l_info;
> +
> +	IS_IPVLAN_LINK_ASSERT(link);
> +
> +	if (mode != IPVLAN_MODE_L2 && mode != IPVLAN_MODE_L3)
> +		return -NLE_INVAL;
> +
> +	ipi->ipi_mode = mode;
> +	ipi->ipi_mask |= IPVLAN_HAS_MODE;
> +
> +	return 0;
> +}

wouldn't it be better to allow any mode? Otherwise, if a new mode gets
added, libnl needs to be patched too.
Or do you think it's highly unlikely that another mode will be added in
the future?



> +/**
> + * Get IPVLAN Mode
> + * @arg link		Link object
> + *
> + * @return IPVLAN mode, 0 if not set or a negative error code.
> + */
> +uint16_t rtnl_link_ipvlan_get_mode(struct rtnl_link *link)
> +{
> +	struct ipvlan_info *ipi = link->l_info;
> +
> +	IS_IPVLAN_LINK_ASSERT(link);
> +
> +	if (ipi->ipi_mask & IPVLAN_HAS_MODE)
> +		return ipi->ipi_mode;
> +	else
> +		return 0;
> +}

0 is equal to IPVLAN_MODE_L2, so you cannot signal an error.
Also, the function cannot ever return a negative error code.

How about changing the signature to:

int rtnl_link_ipvlan_get_mode(struct rtnl_link *link, uint16_t *out_mode);




Thomas
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/libnl/attachments/20150619/26e18fdb/attachment.sig>

From thaller at redhat.com  Fri Jun 19 09:17:35 2015
From: thaller at redhat.com (Thomas Haller)
Date: Fri, 19 Jun 2015 18:17:35 +0200
Subject: [PATCH 1/2] Add ipvlan support
In-Reply-To: <1434730490.29331.14.camel@redhat.com>
References: <1433911990-14569-1-git-send-email-xiyou.wangcong@gmail.com>
 <1434730490.29331.14.camel@redhat.com>
Message-ID: <1434730655.29331.15.camel@redhat.com>

On Fri, 2015-06-19 at 18:14 +0200, Thomas Haller wrote:
> On Tue, 2015-06-09 at 21:53 -0700, Cong Wang wrote:
> > Signed-off-by: Cong Wang <xiyou.wangcong at gmail.com>
> > ---
> >  include/Makefile.am                   |   1 +
> >  include/linux-private/linux/if_link.h |  15 ++
> >  include/netlink/route/link/ipvlan.h   |  37 +++++
> >  lib/Makefile.am                       |   2 +-
> >  lib/route/link/ipvlan.c               | 279 
> > ++++++++++++++++++++++++++++++++++
> >  libnl-route-3.sym                     |  10 ++
> >  6 files changed, 343 insertions(+), 1 deletion(-)
> >  create mode 100644 include/netlink/route/link/ipvlan.h
> >  create mode 100644 lib/route/link/ipvlan.c
> > 



\me sending non-sense emails. Sorry for the noise.


Thomas
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/libnl/attachments/20150619/6bd01598/attachment.sig>

From xiyou.wangcong at gmail.com  Mon Jun 22 09:43:57 2015
From: xiyou.wangcong at gmail.com (Cong Wang)
Date: Mon, 22 Jun 2015 09:43:57 -0700
Subject: [PATCH 1/2] Add ipvlan support
In-Reply-To: <1434730487.29331.13.camel@redhat.com>
References: <1433911990-14569-1-git-send-email-xiyou.wangcong@gmail.com>
 <1434730487.29331.13.camel@redhat.com>
Message-ID: <CAM_iQpVZvT1cugFWhHruEQ4H+-sYeuAE_yD2tyArB2e-NWQpdA@mail.gmail.com>

On Fri, Jun 19, 2015 at 9:14 AM, Thomas Haller <thaller at redhat.com> wrote:
> Hi Cong,
>
> Thanks for the patches. Both unmodified applied as
> https://github.com/thom311/libnl/commit/12e87e444dc4ffd4e5d3ca2e99b08e4
> e22665a86
>
>

Thanks!

>
>
> Two follow-up questions though...
>
>
>> +int rtnl_link_ipvlan_set_mode(struct rtnl_link *link, uint16_t mode)
>> +{
>> +     struct ipvlan_info *ipi = link->l_info;
>> +
>> +     IS_IPVLAN_LINK_ASSERT(link);
>> +
>> +     if (mode != IPVLAN_MODE_L2 && mode != IPVLAN_MODE_L3)
>> +             return -NLE_INVAL;
>> +
>> +     ipi->ipi_mode = mode;
>> +     ipi->ipi_mask |= IPVLAN_HAS_MODE;
>> +
>> +     return 0;
>> +}
>
> wouldn't it be better to allow any mode? Otherwise, if a new mode gets
> added, libnl needs to be patched too.
> Or do you think it's highly unlikely that another mode will be added in
> the future?
>

We could add more modes in the future, but it should be fine to
add them here too, right? I mean, it is valid to change:

rtnl_link_ipvlan_set_mode(NEW_MODE) == -EINVAL

to:

rtnl_link_ipvlan_set_mode(NEW_MODE) == 0

It is not considered as an ABI breakage.

>
>> +/**
>> + * Get IPVLAN Mode
>> + * @arg link         Link object
>> + *
>> + * @return IPVLAN mode, 0 if not set or a negative error code.
>> + */
>> +uint16_t rtnl_link_ipvlan_get_mode(struct rtnl_link *link)
>> +{
>> +     struct ipvlan_info *ipi = link->l_info;
>> +
>> +     IS_IPVLAN_LINK_ASSERT(link);
>> +
>> +     if (ipi->ipi_mask & IPVLAN_HAS_MODE)
>> +             return ipi->ipi_mode;
>> +     else
>> +             return 0;
>> +}
>
> 0 is equal to IPVLAN_MODE_L2, so you cannot signal an error.
> Also, the function cannot ever return a negative error code.
>
> How about changing the signature to:
>
> int rtnl_link_ipvlan_get_mode(struct rtnl_link *link, uint16_t *out_mode);
>

Good catch! Sounds good to me. Let me know if you want me
to send a patch or you will do it.


From ranker72 at gmail.com  Tue Jun 23 08:10:31 2015
From: ranker72 at gmail.com (ferran)
Date: Tue, 23 Jun 2015 17:10:31 +0200
Subject: Resources cleanup upon using received data
In-Reply-To: <5582CC9E.1060500@gmail.com>
References: <557AF9C3.3060809@gmail.com> <1434126803.4018.21.camel@redhat.com>
 <557F1A1A.6080009@gmail.com> <557F247A.8030803@gmail.com>
 <5582CC9E.1060500@gmail.com>
Message-ID: <558976E7.807@gmail.com>

Hi,

I just wanted to note that assigning a fixed port number to the recently
allocated socket solved the problem. For some reason, nl_msg_alloc
returned a pointer to an already open socket, instead of a new one.

Actually, nl_connect always returned NLE_EXIST, but it wasn't a problem
when not freeing the socket every time.

In short, you can omit this issue, another part of the project was
interferring with mine.

Thank you for the help!

Best regards,
Ferran

On 18/06/15 15:50, ferran wrote:
> Hi there,
>
> I have advanced on this. The reason why the callback isn't executed is
> that actually the socket hasn't been allocated. Capturing the error, I
> get error code -6, that is,  NLE_EXIST, "Object exists" and system's
> EEXIST or EADDRINUSE.
>
> When I didn't do nl_socket_free and consequently, didn't close the
> socket, nl lib kept assigning me sockets with different local ports.
> However, if I do free the socket, for some nl lib tries to assign me a
> socket with a local port that is still in use. This is my problem.
>
> For some reason the library thinks that a local port is available when
> it really isn't. What could motivate this misbehavior?
>
> Regards,
> Ferran
>
> On 15/06/15 21:16, ferran wrote:
>> Hi,
>>
>> I forgot to mention that the callback, when called, is always called
>> twice. However, I don't free any resource inside the callback, but after it.
>>
>> I can't figure out how freeing the socket after the callback can prevent
>> the callback itself to be called.
>>
>> Regards,
>> Ferran
>>
>> On 15/06/15 20:31, ferran wrote:
>>> Hi Dan,
>>> Thank you for your kind reply.
>>>
>>> I agree that the nice way to go would be to reuse the same socket, but I
>>> can't access to the upper level, in the example, "caller.c". It's part
>>> of a wider project, and I'm afraid that it would break a level of
>>> abstraction.
>>>
>>> I have to add information: "get_wireless_stats" is called once per
>>> wireless device each 10 seconds. Therefore, "caller.c", in practice, is
>>> doing:
>>>
>>> int main ()
>>>     struct wireless_stats ofs;
>>>     while (true)
>>>     {
>>>         for_each_dev(device)
>>>         {
>>>             get_wireless_stats(device, &ofs);
>>>         }
>>>         sleep_seconds(10);
>>>     }
>>> return 0;
>>>
>>> Where "device" is a string that is translated with "if_nametoindex"
>>> inside "get_wireless_stats". Each device is queried one after the other
>>> without threading or alike.
>>>
>>> This said, I tried again with more verbose logging and freed the msg and
>>> socket resources before finishing "get_wireless_stats". I get the stats
>>> doing :
>>> ...
>>>
>>>     nlsmg_free(msg);
>>>     nl_close(sk);
>>>     return 0;
>>>     
>>> nla_put_failure:
>>>     nlmsg_free(msg);
>>>     nl_close(sk);
>>>     return err;
>>> }
>>>
>>> But if I do "nl_socket_free(sk)" instead of "nl_close(sk)", then the
>>> callback isn't called, and the stats don't get copied to the target
>>> structure. Does it make any sense to you?
>>>
>>> Regards,
>>> Ferran
>>>
>>> On 12/06/15 18:33, Dan Williams wrote:
>>>> On Fri, 2015-06-12 at 17:24 +0200, ferran wrote:
>>>>> Hello everyone,
>>>>> I have some issues at managing resources used to query wireless
>>>>> statistics, I hope you can help me.
>>>>>
>>>>> Currently I successfully query cfg80211 to get statistics about wireless
>>>>> devices such as tx bitrate, every 10 seconds. My problem is that I have
>>>>> been unable to do this without leaking file descriptors and memory. The
>>>>> code I use is inherited and I am trying to fix it, but I can't manage to
>>>>> release the resources without losing the retrieved data. Until now, I
>>>>> have read the documentation, compared with implementation examples found
>>>>> here and there, and consulted frequently the doxygen reference. However,
>>>>> I still need some more help.
>>>>>
>>>>> Issue 1: 'nl_recvmsgs_default()' will block until receiving a message if
>>>>> socket is configured as blocking (default), but won't wait for the
>>>>> callback to finish, right? So how could I possibly release the resources
>>>>> just after nl_recvmsgs if the callback needs the received data?
>>>> nl_recvmsgs_default() will block and process messages as long as (a)
>>>> there are messages in the receive buffer and (b) your callback returns
>>>> NL_SKIP.  It will wait for your callback to finish before proceeding.
>>>>
>>>> One thing I notice: there isn't a lot of sense in doing all the setup
>>>> every 10 seconds.  You might as well just do the setup once and then
>>>> every 10s do the nl_msg_alloc/send/recv.  
>>>>
>>>>> Issue 2: I have sumarized  the code so that you can check the run flow
>>>>> and the memory management, it's posted in pastebin:
>>>>> http://pastebin.com/EYADmDpy
>>>>> Could you have a look to it, please? It's less than 100 lines, comments
>>>>> included. How should I release the resources used by the nl socket and
>>>>> nl message?
>>>> The code you've got isn't freeing either 'msg' or 'sk', so you're
>>>> leaking both of those every 10 seconds.  How about something like this;
>>>> alternatively you can just make sure that both the normal and
>>>> nla_put_failure paths in get_wireless_stats() free both 'msg' and 'sk'.
>>>>
>>>> //// ----------- caller.c ------------------
>>>> /* includes */
>>>> int main ()
>>>>     struct wireless_stats ofs;
>>>>     struct nl_sock *sk;
>>>>     int family_id;
>>>>     int err;
>>>>
>>>>     sk = nl_socket_alloc();
>>>>     genl_connect(sk);
>>>>
>>>>     // WARNING, the docs say we must call genl_family_put() later and we don't!    
>>>>     family_id = genl_ctrl_resolve(sk, "nl80211");
>>>>     
>>>>     nl_socket_modify_cb(sk, NL_CB_VALID, NL_CB_CUSTOM,
>>>>         stats_handler, NULL);
>>>>
>>>>     while (true)
>>>>     {
>>>>         get_wireless_stats(sk, &ofs);
>>>>         /* use retrieved data */
>>>>     
>>>>         sleep_seconds(10);
>>>>     }
>>>>
>>>>     nl_socket_free(sk);
>>>> return 0;
>>>>
>>>> //// --------- wireless_stats.c -----------
>>>>
>>>> void get_wireless_stats(struct nl_socket *sk, struct wireless_stats *ofs)
>>>> {
>>>>     struct nl_msg *msg;
>>>>     int err;
>>>>
>>>>     shared_stats = ofs;
>>>>     
>>>>     msg = nlmsg_alloc();
>>>>     genlmsg_put(msg, 0, 0, family_id, 0, NLM_F_DUMP, NL80211_CMD_GET_STATION, 0;
>>>>     NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex("mesh0"));
>>>>     err = nl_send_auto_complete(sk, msg);
>>>>     nl_recvmsgs_default(sk);
>>>>     nlsmg_free(msg);
>>>>     return 0;
>>>>     
>>>>     // Not sure who comes here, but it isn't part of the success workflow, and is required at compilation time.
>>>>     // -> the NLA_PUT_U32 macro has a 'goto nla_put_failure' in case there isn't enough memory
>>>> nla_put_failure:
>>>>     nlmsg_free(msg);
>>>>     return err;
>>>> }
>>>>
>>>> <no changes to stats_handler>
>>>>
>




From jbernard at toulouse.viveris.fr  Wed Jun 24 06:25:23 2015
From: jbernard at toulouse.viveris.fr (Julien BERNARD)
Date: Wed, 24 Jun 2015 15:25:23 +0200
Subject: cannot set TUN interface up/down with Python API (wrapper)
In-Reply-To: <558184B6.9040307@toulouse.viveris.fr>
References: <5530FD11.9040308@toulouse.viveris.com>
 <1429536373.7093.22.camel@redhat.com> <558184B6.9040307@toulouse.viveris.fr>
Message-ID: <558AAFC3.5010807@toulouse.viveris.fr>

Hi,
>
> The last working revision is 88940b71f81525b1080fcdd5a029537e9a85ca38, 
> the revision just after the 3.2.3 release.
> The next revision (ef75c4edf0930b4d745da695c5fe0075c7b3afdd) 
> introduces a segfault in the script that is resolved in the 3.2.5 
> release (this should be the fix introduced by the revision 
> 4035e5b5e88529e6c7a12c41dcd8637ed69498d9).
> Thus, I applied the fix on the revision 
> ef75c4edf0930b4d745da695c5fe0075c7b3afdd and I can confirm that the 
> problem was introduced by this revision.
> However I'm not familiar enough with all of this to determine exactly 
> what causes the bug.
>
> Could you please help me to understand what really causes this error?

I managed to fix the problem.
In fact the error is caused by the link type set to 'tun' which is not 
supported (there is nor tun.c in route/link/ neither in the python wrapper).
In C it works because I think there is a default behavior for tun 
interface but this should not correcly be implemented in python.

At the moment, in order to make this work, I simply redefined the link 
type as 'dummy' before changing the flags.
The script is thus as follow:
#!/usr/bin/env python2
import netlink.route.link as link
import netlink.core as netlink
import netlink.route.address as address

sock = netlink.Socket()
sock.connect(netlink.NETLINK_ROUTE)
cache = link.LinkCache()
cache.refill(sock)
iface = cache['tun0']
iface.type = 'dummy'
iface.flags = ['-up']
iface.change()


The libnl still returns an error (the same as for classic ethernet 
interfaces: netlink.core.KernelError: Kernel returned: Message sequence 
number mismatch) but this works.
I will try to find out why there is this problem and if there is 
something to fix in the python wrapper I would report it.

Regards,

-- 
Julien BERNARD



From thaller at redhat.com  Fri Jun 26 08:48:22 2015
From: thaller at redhat.com (Thomas Haller)
Date: Fri, 26 Jun 2015 17:48:22 +0200
Subject: [PATCH v2] remove automatic port id generation
In-Reply-To: <1434548995-10175-1-git-send-email-julien.courtat@6wind.com>
References: <1433481206.5221.29.camel@redhat.com>
 <1434548995-10175-1-git-send-email-julien.courtat@6wind.com>
Message-ID: <1435333702.7244.18.camel@redhat.com>

On Wed, 2015-06-17 at 15:49 +0200, Julien Courtat wrote:
> Since kernel can automatically set a unique portid to each socket any
> application would bind with, there is no use to keep the portid 
> generation
> procedure made of 22 bits for the pid and 10 bits left for a pseudo
> random value.
> Remove this procedure and let kernel choose a port id for the socket.
> It is still possible for an application to set the port id manually 
> via
> nl_socket_set_local_port().
> 
> Signed-off-by: Julien Courtat <julien.courtat at 6wind.com>
> ---

Hi Julien,

The patch removes generate_local_port() entirely. I think that is too
much because it changes behavior in the following case:

    sk = nl_socket_alloc();
    port = nl_socket_get_local_port(sk);
    /* do something with port... */
    nl_connect(sk, NETLINK_...);

Calling nl_socket_get_local_port() before connecting the socket already
assigns a port. While it is not a good idea to do that, I'd rather not
change behavior without strong reason.

So I would restore some parts that you deleted from lib/socket.c.
(you don't have to send a v3 if we agree on that).




Regarding the part in lib/nl.c:
The question still stands whether it is safe to do the change it(?).
But I think yes. AFAIS, netlink_autobind() is in kernel for a ~very~
long time.



Thomas
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/libnl/attachments/20150626/46cc8220/attachment.sig>

From thaller at redhat.com  Fri Jun 26 09:08:19 2015
From: thaller at redhat.com (Thomas Haller)
Date: Fri, 26 Jun 2015 18:08:19 +0200
Subject: [PATCH 1/2] Add ipvlan support
In-Reply-To: <CAM_iQpVZvT1cugFWhHruEQ4H+-sYeuAE_yD2tyArB2e-NWQpdA@mail.gmail.com>
References: <1433911990-14569-1-git-send-email-xiyou.wangcong@gmail.com>
 <1434730487.29331.13.camel@redhat.com>
 <CAM_iQpVZvT1cugFWhHruEQ4H+-sYeuAE_yD2tyArB2e-NWQpdA@mail.gmail.com>
Message-ID: <1435334899.7244.23.camel@redhat.com>

On Mon, 2015-06-22 at 09:43 -0700, Cong Wang wrote:
> On Fri, Jun 19, 2015 at 9:14 AM, Thomas Haller <thaller at redhat.com> 
> wrote:
> > Hi Cong,
> > 
> > Thanks for the patches. Both unmodified applied as
> > https://github.com/thom311/libnl/commit/12e87e444dc4ffd4e5d3ca2e99b
> > 08e4
> > e22665a86
> > 
> > 
> 
> Thanks!
> 
> > 
> > 
> > Two follow-up questions though...
> > 
> > 
> > > +int rtnl_link_ipvlan_set_mode(struct rtnl_link *link, uint16_t 
> > > mode)
> > > +{
> > > +     struct ipvlan_info *ipi = link->l_info;
> > > +
> > > +     IS_IPVLAN_LINK_ASSERT(link);
> > > +
> > > +     if (mode != IPVLAN_MODE_L2 && mode != IPVLAN_MODE_L3)
> > > +             return -NLE_INVAL;
> > > +
> > > +     ipi->ipi_mode = mode;
> > > +     ipi->ipi_mask |= IPVLAN_HAS_MODE;
> > > +
> > > +     return 0;
> > > +}
> > 
> > wouldn't it be better to allow any mode? Otherwise, if a new mode 
> > gets
> > added, libnl needs to be patched too.
> > Or do you think it's highly unlikely that another mode will be 
> > added in
> > the future?
> > 
> 
> We could add more modes in the future, but it should be fine to
> add them here too, right? I mean, it is valid to change:
> 
> rtnl_link_ipvlan_set_mode(NEW_MODE) == -EINVAL
> 
> to:
> 
> rtnl_link_ipvlan_set_mode(NEW_MODE) == 0
> 
> It is not considered as an ABI breakage.

Yes. But when adding NEW_MODE to kernel, old libnl3 does't work with
that mode until upgrading the library too.

I would just drop the check.

Pushed https://github.com/thom311/libnl/commit/371226b834b662e6ad99400f
fc20450e574ca5c2

If you disagree, we can revert/rework that.





> > > +/**
> > > + * Get IPVLAN Mode
> > > + * @arg link         Link object
> > > + *
> > > + * @return IPVLAN mode, 0 if not set or a negative error code.
> > > + */
> > > +uint16_t rtnl_link_ipvlan_get_mode(struct rtnl_link *link)
> > > +{
> > > +     struct ipvlan_info *ipi = link->l_info;
> > > +
> > > +     IS_IPVLAN_LINK_ASSERT(link);
> > > +
> > > +     if (ipi->ipi_mask & IPVLAN_HAS_MODE)
> > > +             return ipi->ipi_mode;
> > > +     else
> > > +             return 0;
> > > +}
> > 
> > 0 is equal to IPVLAN_MODE_L2, so you cannot signal an error.
> > Also, the function cannot ever return a negative error code.
> > 
> > How about changing the signature to:
> > 
> > int rtnl_link_ipvlan_get_mode(struct rtnl_link *link, uint16_t 
> > *out_mode);
> > 
> 
> Good catch! Sounds good to me. Let me know if you want me
> to send a patch or you will do it.

done as
https://github.com/thom311/libnl/commit/b4afcadc30f0133135c6f8b062d6e1c
a68b645a7


Looks good?


Thomas
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/libnl/attachments/20150626/0a901d44/attachment.sig>

From xiyou.wangcong at gmail.com  Fri Jun 26 10:48:58 2015
From: xiyou.wangcong at gmail.com (Cong Wang)
Date: Fri, 26 Jun 2015 10:48:58 -0700
Subject: [PATCH 1/2] Add ipvlan support
In-Reply-To: <1435334899.7244.23.camel@redhat.com>
References: <1433911990-14569-1-git-send-email-xiyou.wangcong@gmail.com>
 <1434730487.29331.13.camel@redhat.com>
 <CAM_iQpVZvT1cugFWhHruEQ4H+-sYeuAE_yD2tyArB2e-NWQpdA@mail.gmail.com>
 <1435334899.7244.23.camel@redhat.com>
Message-ID: <CAM_iQpVEV0PJNRLt+VQK+ydSJNYJW42cqiE_u=rb+x6jSr8aGg@mail.gmail.com>

On Fri, Jun 26, 2015 at 9:08 AM, Thomas Haller <thaller at redhat.com> wrote:
>
> Yes. But when adding NEW_MODE to kernel, old libnl3 does't work with
> that mode until upgrading the library too.
>


New feature requires a new version, it is fair, right? :)

> I would just drop the check.
>
> Pushed https://github.com/thom311/libnl/commit/371226b834b662e6ad99400f
> fc20450e574ca5c2
>
> If you disagree, we can revert/rework that.
>

I don't have strong opinion here, so it is up to you.

>
> done as
> https://github.com/thom311/libnl/commit/b4afcadc30f0133135c6f8b062d6e1c
> a68b645a7
>
>
> Looks good?
>

Sure, except I think NLE_INVAL is slightly better than NLE_OPNOTSUPP.


Anyway, thanks!


