diff mbox series

[net-next,1/2] inet_diag: export SO_REUSEADDR and SO_REUSEPORT sockopts

Message ID 0b1deb44b8401042542a112e8235e039fc0a5f65.1694523876.git.jbaron@akamai.com (mailing list archive)
State Changes Requested
Delegated to: Netdev Maintainers
Headers show
Series export SO_REUSEADDR and SO_REUSEPORT via sock_diag | expand

Checks

Context Check Description
netdev/series_format success Posting correctly formatted
netdev/tree_selection success Clearly marked for net-next, async
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 1342 this patch: 1342
netdev/cc_maintainers success CCed 7 of 7 maintainers
netdev/build_clang success Errors and warnings before: 1364 this patch: 1364
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 1365 this patch: 1365
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 46 lines checked
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

Jason Baron Sept. 12, 2023, 2:31 p.m. UTC
Add the ability to monitor SO_REUSEADDR and SO_REUSEPORT for an inet
socket. These settings are currently readable via getsockopt().
We have an app that will sometimes fail to bind() and it's helpful to
understand what other apps are causing the bind() conflict.

Signed-off-by: Jason Baron <jbaron@akamai.com>
---
 include/linux/inet_diag.h      | 2 ++
 include/uapi/linux/inet_diag.h | 7 +++++++
 net/ipv4/inet_diag.c           | 7 +++++++
 3 files changed, 16 insertions(+)

Comments

Kuniyuki Iwashima Sept. 12, 2023, 4:26 p.m. UTC | #1
From: Jason Baron <jbaron@akamai.com>
Date: Tue, 12 Sep 2023 10:31:48 -0400
> Add the ability to monitor SO_REUSEADDR and SO_REUSEPORT for an inet
> socket. These settings are currently readable via getsockopt().
> We have an app that will sometimes fail to bind() and it's helpful to
> understand what other apps are causing the bind() conflict.

If bind() fails with -EADDRINUSE, you can find the conflicting sockets
with just the failing 2-tuple, no ?

Also, BPF iterator and bpf_sk_getsockopt() has the same functionality
with more flexibility.  (See: sol_socket_sockopt() in net/core/filter.c)


> 
> Signed-off-by: Jason Baron <jbaron@akamai.com>
> ---
>  include/linux/inet_diag.h      | 2 ++
>  include/uapi/linux/inet_diag.h | 7 +++++++
>  net/ipv4/inet_diag.c           | 7 +++++++
>  3 files changed, 16 insertions(+)
> 
> diff --git a/include/linux/inet_diag.h b/include/linux/inet_diag.h
> index 84abb30a3fbb..d05a4c26b13d 100644
> --- a/include/linux/inet_diag.h
> +++ b/include/linux/inet_diag.h
> @@ -77,6 +77,8 @@ static inline size_t inet_diag_msg_attrs_size(void)
>  #endif
>  		+ nla_total_size(sizeof(struct inet_diag_sockopt))
>  						     /* INET_DIAG_SOCKOPT */
> +		+ nla_total_size(sizeof(struct inet_diag_reuse))
> +						    /* INET_DIAG_REUSE */
>  		;
>  }
>  int inet_diag_msg_attrs_fill(struct sock *sk, struct sk_buff *skb,
> diff --git a/include/uapi/linux/inet_diag.h b/include/uapi/linux/inet_diag.h
> index 50655de04c9b..f93eeea1faba 100644
> --- a/include/uapi/linux/inet_diag.h
> +++ b/include/uapi/linux/inet_diag.h
> @@ -161,6 +161,7 @@ enum {
>  	INET_DIAG_SK_BPF_STORAGES,
>  	INET_DIAG_CGROUP_ID,
>  	INET_DIAG_SOCKOPT,
> +	INET_DIAG_REUSE,
>  	__INET_DIAG_MAX,
>  };
>  
> @@ -201,6 +202,12 @@ struct inet_diag_sockopt {
>  		unused:5;
>  };
>  
> +struct inet_diag_reuse {
> +	__u8	reuse:4,
> +		reuseport:1,
> +		unused:3;
> +};
> +
>  /* INET_DIAG_VEGASINFO */
>  
>  struct tcpvegas_info {
> diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
> index e13a84433413..d6ebb1e612fc 100644
> --- a/net/ipv4/inet_diag.c
> +++ b/net/ipv4/inet_diag.c
> @@ -125,6 +125,7 @@ int inet_diag_msg_attrs_fill(struct sock *sk, struct sk_buff *skb,
>  			     bool net_admin)
>  {
>  	const struct inet_sock *inet = inet_sk(sk);
> +	struct inet_diag_reuse inet_reuse = {};
>  	struct inet_diag_sockopt inet_sockopt;
>  
>  	if (nla_put_u8(skb, INET_DIAG_SHUTDOWN, sk->sk_shutdown))
> @@ -197,6 +198,12 @@ int inet_diag_msg_attrs_fill(struct sock *sk, struct sk_buff *skb,
>  		    &inet_sockopt))
>  		goto errout;
>  
> +	inet_reuse.reuse = sk->sk_reuse;
> +	inet_reuse.reuseport = sk->sk_reuseport;
> +	if (nla_put(skb, INET_DIAG_REUSE, sizeof(inet_reuse),
> +		    &inet_reuse))
> +		goto errout;
> +
>  	return 0;
>  errout:
>  	return 1;
> -- 
> 2.25.1
Jason Baron Sept. 12, 2023, 6:54 p.m. UTC | #2
On 9/12/23 12:26 PM, Kuniyuki Iwashima wrote:
> From: Jason Baron <jbaron@akamai.com>
> Date: Tue, 12 Sep 2023 10:31:48 -0400
>> Add the ability to monitor SO_REUSEADDR and SO_REUSEPORT for an inet
>> socket. These settings are currently readable via getsockopt().
>> We have an app that will sometimes fail to bind() and it's helpful to
>> understand what other apps are causing the bind() conflict.
> 
> If bind() fails with -EADDRINUSE, you can find the conflicting sockets
> with just the failing 2-tuple, no ?

True, yes one can figure out the conflicting socket as is I agree, but 
then the next step is what went wrong. For so_reuseport, you also need 
to match uid for it to work. Or if the socket is bound to different 
devices it is ok, regardless of the reuse/reuseport setting (if I read 
the code correctly)...And these other factors are currently exposed via 
sock_diag. So maybe you can deduce these via process of elimination but 
I think it could be nice to be more explicit about it.

> 
> Also, BPF iterator and bpf_sk_getsockopt() has the same functionality
> with more flexibility.  (See: sol_socket_sockopt() in net/core/filter.c)
> 
> 

True, yeah on one hand the fact that reuseport/reuseaddr are exposed via 
bpf means they are useful and reasonable to expose. On the other hand 
yeah there's an existing interface if you want to hook up bpf code. In 
the use case I had, we have a C++ application that wants to print debug 
information about the conflicting socket when the -EADDRINUSE happens 
and not necessarily have to invoke a bpf program.

Thanks,

-Jason


>>
>> Signed-off-by: Jason Baron <jbaron@akamai.com>
>> ---
>>   include/linux/inet_diag.h      | 2 ++
>>   include/uapi/linux/inet_diag.h | 7 +++++++
>>   net/ipv4/inet_diag.c           | 7 +++++++
>>   3 files changed, 16 insertions(+)
>>
>> diff --git a/include/linux/inet_diag.h b/include/linux/inet_diag.h
>> index 84abb30a3fbb..d05a4c26b13d 100644
>> --- a/include/linux/inet_diag.h
>> +++ b/include/linux/inet_diag.h
>> @@ -77,6 +77,8 @@ static inline size_t inet_diag_msg_attrs_size(void)
>>   #endif
>>   		+ nla_total_size(sizeof(struct inet_diag_sockopt))
>>   						     /* INET_DIAG_SOCKOPT */
>> +		+ nla_total_size(sizeof(struct inet_diag_reuse))
>> +						    /* INET_DIAG_REUSE */
>>   		;
>>   }
>>   int inet_diag_msg_attrs_fill(struct sock *sk, struct sk_buff *skb,
>> diff --git a/include/uapi/linux/inet_diag.h b/include/uapi/linux/inet_diag.h
>> index 50655de04c9b..f93eeea1faba 100644
>> --- a/include/uapi/linux/inet_diag.h
>> +++ b/include/uapi/linux/inet_diag.h
>> @@ -161,6 +161,7 @@ enum {
>>   	INET_DIAG_SK_BPF_STORAGES,
>>   	INET_DIAG_CGROUP_ID,
>>   	INET_DIAG_SOCKOPT,
>> +	INET_DIAG_REUSE,
>>   	__INET_DIAG_MAX,
>>   };
>>   
>> @@ -201,6 +202,12 @@ struct inet_diag_sockopt {
>>   		unused:5;
>>   };
>>   
>> +struct inet_diag_reuse {
>> +	__u8	reuse:4,
>> +		reuseport:1,
>> +		unused:3;
>> +};
>> +
>>   /* INET_DIAG_VEGASINFO */
>>   
>>   struct tcpvegas_info {
>> diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
>> index e13a84433413..d6ebb1e612fc 100644
>> --- a/net/ipv4/inet_diag.c
>> +++ b/net/ipv4/inet_diag.c
>> @@ -125,6 +125,7 @@ int inet_diag_msg_attrs_fill(struct sock *sk, struct sk_buff *skb,
>>   			     bool net_admin)
>>   {
>>   	const struct inet_sock *inet = inet_sk(sk);
>> +	struct inet_diag_reuse inet_reuse = {};
>>   	struct inet_diag_sockopt inet_sockopt;
>>   
>>   	if (nla_put_u8(skb, INET_DIAG_SHUTDOWN, sk->sk_shutdown))
>> @@ -197,6 +198,12 @@ int inet_diag_msg_attrs_fill(struct sock *sk, struct sk_buff *skb,
>>   		    &inet_sockopt))
>>   		goto errout;
>>   
>> +	inet_reuse.reuse = sk->sk_reuse;
>> +	inet_reuse.reuseport = sk->sk_reuseport;
>> +	if (nla_put(skb, INET_DIAG_REUSE, sizeof(inet_reuse),
>> +		    &inet_reuse))
>> +		goto errout;
>> +
>>   	return 0;
>>   errout:
>>   	return 1;
>> -- 
>> 2.25.1
diff mbox series

Patch

diff --git a/include/linux/inet_diag.h b/include/linux/inet_diag.h
index 84abb30a3fbb..d05a4c26b13d 100644
--- a/include/linux/inet_diag.h
+++ b/include/linux/inet_diag.h
@@ -77,6 +77,8 @@  static inline size_t inet_diag_msg_attrs_size(void)
 #endif
 		+ nla_total_size(sizeof(struct inet_diag_sockopt))
 						     /* INET_DIAG_SOCKOPT */
+		+ nla_total_size(sizeof(struct inet_diag_reuse))
+						    /* INET_DIAG_REUSE */
 		;
 }
 int inet_diag_msg_attrs_fill(struct sock *sk, struct sk_buff *skb,
diff --git a/include/uapi/linux/inet_diag.h b/include/uapi/linux/inet_diag.h
index 50655de04c9b..f93eeea1faba 100644
--- a/include/uapi/linux/inet_diag.h
+++ b/include/uapi/linux/inet_diag.h
@@ -161,6 +161,7 @@  enum {
 	INET_DIAG_SK_BPF_STORAGES,
 	INET_DIAG_CGROUP_ID,
 	INET_DIAG_SOCKOPT,
+	INET_DIAG_REUSE,
 	__INET_DIAG_MAX,
 };
 
@@ -201,6 +202,12 @@  struct inet_diag_sockopt {
 		unused:5;
 };
 
+struct inet_diag_reuse {
+	__u8	reuse:4,
+		reuseport:1,
+		unused:3;
+};
+
 /* INET_DIAG_VEGASINFO */
 
 struct tcpvegas_info {
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
index e13a84433413..d6ebb1e612fc 100644
--- a/net/ipv4/inet_diag.c
+++ b/net/ipv4/inet_diag.c
@@ -125,6 +125,7 @@  int inet_diag_msg_attrs_fill(struct sock *sk, struct sk_buff *skb,
 			     bool net_admin)
 {
 	const struct inet_sock *inet = inet_sk(sk);
+	struct inet_diag_reuse inet_reuse = {};
 	struct inet_diag_sockopt inet_sockopt;
 
 	if (nla_put_u8(skb, INET_DIAG_SHUTDOWN, sk->sk_shutdown))
@@ -197,6 +198,12 @@  int inet_diag_msg_attrs_fill(struct sock *sk, struct sk_buff *skb,
 		    &inet_sockopt))
 		goto errout;
 
+	inet_reuse.reuse = sk->sk_reuse;
+	inet_reuse.reuseport = sk->sk_reuseport;
+	if (nla_put(skb, INET_DIAG_REUSE, sizeof(inet_reuse),
+		    &inet_reuse))
+		goto errout;
+
 	return 0;
 errout:
 	return 1;