netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 1/2] Implement IP_UNICAST_IF socket option.
@ 2012-02-06 17:57 Erich E. Hoover
  0 siblings, 0 replies; 6+ messages in thread
From: Erich E. Hoover @ 2012-02-06 17:57 UTC (permalink / raw)
  To: Linux Netdev; +Cc: Erich E. Hoover


The IP_UNICAST_IF feature is needed by the Wine project.  This patch implements the feature by setting the outgoing interface in a similar fashion to that of IP_PKTINFO.  A separate option is needed to handle this feature since the existing options do not provide all of the characteristics required by IP_UNICAST_IF, a summary is provided below.

SO_BINDTODEVICE:
* SO_BINDTODEVICE requires administrative privileges, IP_UNICAST_IF does not.  From reading some old mailing list articles my understanding is that SO_BINDTODEVICE requires administrative privileges because it can override the administrator's routing settings.
* The SO_BINDTODEVICE option restricts both outbound and inbound traffic, IP_UNICAST_IF only impacts outbound traffic.

IP_PKTINFO:
* Since IP_PKTINFO and IP_UNICAST_IF are independent options, implementing IP_UNICAST_IF with IP_PKTINFO will likely break some applications.
* Implementing IP_UNICAST_IF on top of IP_PKTINFO significantly complicates the Wine codebase and reduces the socket performance (doing this requires a lot of extra communication between the "server" and "user" layers).

bind():
* bind() does not work on broadcast packets, IP_UNICAST_IF is specifically intended to work with broadcast packets.

Signed-off-by: Erich E. Hoover <ehoover@mines.edu>
---
 include/linux/in.h      |    1 +
 include/net/inet_sock.h |    2 +
 include/net/ip.h        |    1 +
 net/ipv4/af_inet.c      |    2 +
 net/ipv4/ip_sockglue.c  |   48 +++++++++++++++++++++++++++++++++++++++++++++++
 net/ipv4/ping.c         |    2 +-
 net/ipv4/raw.c          |    2 +-
 net/ipv4/udp.c          |    2 +-
 net/ipv6/af_inet6.c     |    2 +
 9 files changed, 59 insertions(+), 3 deletions(-)

diff --git a/include/linux/in.h b/include/linux/in.h
index 01129c0..89f6682 100644
--- a/include/linux/in.h
+++ b/include/linux/in.h
@@ -86,6 +86,7 @@ struct in_addr {
 
 #define IP_MINTTL       21
 #define IP_NODEFRAG     22
+#define IP_UNICAST_IF   23
 
 /* IP_MTU_DISCOVER values */
 #define IP_PMTUDISC_DONT		0	/* Never send DF frames */
diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h
index e3e4051..ad517f5 100644
--- a/include/net/inet_sock.h
+++ b/include/net/inet_sock.h
@@ -132,6 +132,7 @@ struct rtable;
  * @tos - TOS
  * @mc_ttl - Multicasting TTL
  * @is_icsk - is this an inet_connection_sock?
+ * @outif_index - Outgoing device index
  * @mc_index - Multicast device index
  * @mc_list - Group array
  * @cork - info to build ip hdr on each ip frag while socket is corked
@@ -167,6 +168,7 @@ struct inet_sock {
 				transparent:1,
 				mc_all:1,
 				nodefrag:1;
+	int			outif_index;
 	int			mc_index;
 	__be32			mc_addr;
 	struct ip_mc_socklist __rcu	*mc_list;
diff --git a/include/net/ip.h b/include/net/ip.h
index 775009f..05aa269 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -452,6 +452,7 @@ extern int ip_options_rcv_srr(struct sk_buff *skb);
 
 extern void	ipv4_pktinfo_prepare(struct sk_buff *skb);
 extern void	ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb);
+extern int	ip_default_ifindex(const struct sock *sk);
 extern int	ip_cmsg_send(struct net *net,
 			     struct msghdr *msg, struct ipcm_cookie *ipc);
 extern int	ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval, unsigned int optlen);
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index f7b5670..a5855cd 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -375,6 +375,8 @@ lookup_protocol:
 	sk->sk_protocol	   = protocol;
 	sk->sk_backlog_rcv = sk->sk_prot->backlog_rcv;
 
+	inet->outif_index  = 0;
+
 	inet->uc_ttl	= -1;
 	inet->mc_loop	= 1;
 	inet->mc_ttl	= 1;
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index 8aa87c1..87646e4 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -186,6 +186,21 @@ void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb)
 }
 EXPORT_SYMBOL(ip_cmsg_recv);
 
+int ip_default_ifindex(const struct sock *sk)
+{
+	struct inet_sock *inet = inet_sk(sk);
+	int ifindex = sk->sk_bound_dev_if;
+
+	/*
+         * If not bound to a specific interface then set the outgoing interface
+	 * to the value from the IP_UNICAST_IF socket option.
+         */
+	if (!ifindex)
+		ifindex = inet->outif_index;
+
+	return ifindex;
+}
+
 int ip_cmsg_send(struct net *net, struct msghdr *msg, struct ipcm_cookie *ipc)
 {
 	int err;
@@ -469,6 +484,7 @@ static int do_ip_setsockopt(struct sock *sk, int level,
 			     (1<<IP_ROUTER_ALERT) | (1<<IP_FREEBIND) |
 			     (1<<IP_PASSSEC) | (1<<IP_TRANSPARENT) |
 			     (1<<IP_MINTTL) | (1<<IP_NODEFRAG))) ||
+	    optname == IP_UNICAST_IF ||
 	    optname == IP_MULTICAST_TTL ||
 	    optname == IP_MULTICAST_ALL ||
 	    optname == IP_MULTICAST_LOOP ||
@@ -628,6 +644,35 @@ static int do_ip_setsockopt(struct sock *sk, int level,
 			goto e_inval;
 		inet->mc_loop = !!val;
 		break;
+	case IP_UNICAST_IF:
+	{
+		struct net_device *dev = NULL;
+		int ifindex;
+
+		if (optlen != sizeof(int))
+			goto e_inval;
+
+		ifindex = (__force int)ntohl((__force __be32)val);
+		if (ifindex == 0) {
+			inet->outif_index = 0;
+			err = 0;
+			break;
+		}
+
+		dev = dev_get_by_index(sock_net(sk), ifindex);
+		err = -EADDRNOTAVAIL;
+		if (!dev)
+			break;
+		dev_put(dev);
+
+		err = -EINVAL;
+		if (sk->sk_bound_dev_if && ifindex != sk->sk_bound_dev_if)
+			break;
+
+		inet->outif_index = ifindex;
+		err = 0;
+		break;
+	}
 	case IP_MULTICAST_IF:
 	{
 		struct ip_mreqn mreq;
@@ -1178,6 +1223,9 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname,
 	case IP_MULTICAST_LOOP:
 		val = inet->mc_loop;
 		break;
+	case IP_UNICAST_IF:
+		val = (__force int)htonl((__u32) inet->outif_index);
+		break;
 	case IP_MULTICAST_IF:
 	{
 		struct in_addr addr;
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c
index aea5a19..abeb454 100644
--- a/net/ipv4/ping.c
+++ b/net/ipv4/ping.c
@@ -510,7 +510,7 @@ static int ping_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
 
 	ipc.addr = inet->inet_saddr;
 	ipc.opt = NULL;
-	ipc.oif = sk->sk_bound_dev_if;
+	ipc.oif = ip_default_ifindex(sk);
 	ipc.tx_flags = 0;
 	err = sock_tx_timestamp(sk, &ipc.tx_flags);
 	if (err)
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index 3ccda5a..000d9fb 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -515,7 +515,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
 	ipc.addr = inet->inet_saddr;
 	ipc.opt = NULL;
 	ipc.tx_flags = 0;
-	ipc.oif = sk->sk_bound_dev_if;
+	ipc.oif = ip_default_ifindex(sk);
 
 	if (msg->msg_controllen) {
 		err = ip_cmsg_send(sock_net(sk), msg, &ipc);
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 5d075b5..651eb62 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -869,7 +869,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
 	}
 	ipc.addr = inet->inet_saddr;
 
-	ipc.oif = sk->sk_bound_dev_if;
+	ipc.oif = ip_default_ifindex(sk);
 	err = sock_tx_timestamp(sk, &ipc.tx_flags);
 	if (err)
 		return err;
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 273f48d..13b84bc 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -210,6 +210,8 @@ lookup_protocol:
 	 */
 	inet->uc_ttl	= -1;
 
+	inet->outif_index = 0;
+
 	inet->mc_loop	= 1;
 	inet->mc_ttl	= 1;
 	inet->mc_index	= 0;
-- 
1.7.5.4

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH v3 1/2] Implement IP_UNICAST_IF socket option.
  2012-02-06 20:30       ` Shawn Lu
@ 2012-02-06 22:14         ` Erich E. Hoover
  0 siblings, 0 replies; 6+ messages in thread
From: Erich E. Hoover @ 2012-02-06 22:14 UTC (permalink / raw)
  To: Shawn Lu; +Cc: Linux Netdev

On Mon, Feb 6, 2012 at 1:30 PM, Shawn Lu <shawn.lu@ericsson.com> wrote:
> ...
> If sk->sk_bound_dev_if has a value,  we are not going to use
> outif_index anywhere. Seting outif_index is confusing in this case,
>
> In addition,  when socket has bond to specific device, this
> Option should return fail to indicate it is wrong to use  IP_UNICAST_IF
> Here.

Ok.

Erich Hoover
ehoover@mines.edu

^ permalink raw reply	[flat|nested] 6+ messages in thread

* RE: [PATCH v3 1/2] Implement IP_UNICAST_IF socket option.
  2012-02-06 19:51     ` Erich E. Hoover
@ 2012-02-06 20:30       ` Shawn Lu
  2012-02-06 22:14         ` Erich E. Hoover
  0 siblings, 1 reply; 6+ messages in thread
From: Shawn Lu @ 2012-02-06 20:30 UTC (permalink / raw)
  To: Erich E. Hoover; +Cc: Linux Netdev

 

> -----Original Message-----
> From: Erich E. Hoover [mailto:ehoover@mines.edu] 
> Sent: Monday, February 06, 2012 11:51 AM
> To: Shawn Lu
> Cc: Linux Netdev
> Subject: Re: [PATCH v3 1/2] Implement IP_UNICAST_IF socket option.
> 
> On Mon, Feb 6, 2012 at 12:40 PM, Shawn Lu 
> <shawn.lu@ericsson.com> wrote:
> >...
> > What I mean is replace
> >  if (sk->sk_bound_dev_if && ifindex != sk->sk_bound_dev_if)  With
> >  if (sk->sk_bound_dev_if)
> 
> Are you sure that that's appropriate?  I choose to do it this 
> way since IP_MULTICAST_IF does the exact same check.
If sk->sk_bound_dev_if has a value,  we are not going to use
outif_index anywhere. Seting outif_index is confusing in this case,

In addition,  when socket has bond to specific device, this
Option should return fail to indicate it is wrong to use  IP_UNICAST_IF
Here.
> 
> Erich Hoover
> ehoover@mines.edu
> 

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v3 1/2] Implement IP_UNICAST_IF socket option.
  2012-02-06 19:40   ` Shawn Lu
@ 2012-02-06 19:51     ` Erich E. Hoover
  2012-02-06 20:30       ` Shawn Lu
  0 siblings, 1 reply; 6+ messages in thread
From: Erich E. Hoover @ 2012-02-06 19:51 UTC (permalink / raw)
  To: Shawn Lu; +Cc: Linux Netdev

On Mon, Feb 6, 2012 at 12:40 PM, Shawn Lu <shawn.lu@ericsson.com> wrote:
>...
> What I mean is replace
>  if (sk->sk_bound_dev_if && ifindex != sk->sk_bound_dev_if)
> With
>  if (sk->sk_bound_dev_if)

Are you sure that that's appropriate?  I choose to do it this way
since IP_MULTICAST_IF does the exact same check.

Erich Hoover
ehoover@mines.edu

^ permalink raw reply	[flat|nested] 6+ messages in thread

* RE: [PATCH v3 1/2] Implement IP_UNICAST_IF socket option.
  2012-02-06 19:35 ` Erich E. Hoover
@ 2012-02-06 19:40   ` Shawn Lu
  2012-02-06 19:51     ` Erich E. Hoover
  0 siblings, 1 reply; 6+ messages in thread
From: Shawn Lu @ 2012-02-06 19:40 UTC (permalink / raw)
  To: Erich E. Hoover; +Cc: Linux Netdev

 

> -----Original Message-----
> From: Erich E. Hoover [mailto:ehoover@mines.edu] 
> Sent: Monday, February 06, 2012 11:35 AM
> To: Shawn Lu
> Cc: Linux Netdev
> Subject: Re: [PATCH v3 1/2] Implement IP_UNICAST_IF socket option.
> 
> On Mon, Feb 6, 2012 at 12:00 PM, Shawn Lu 
> <shawn.lu@ericsson.com> wrote:
> >On 2/6/12, Erich E. Hoover <ehoover@mines.edu> wrote:
> >> ...
> >> +             if (sk->sk_bound_dev_if && ifindex != 
> >> + sk->sk_bound_dev_if)
> > If I understand right,  when sk->sk_bound_dev_if !=0 ,  
> > sk->sk_bound_dev_if will be used instead. Then why bother 
> to set outif_index.
> > Here.
> 
> It seems to me that if the socket is already bound to an 
> interface (other than intended interface) then it makes sense 
> to fail to set the option, since it will clearly not work 
> under this circumstance.  I may be misunderstanding you though.
What I mean is replace 
  if (sk->sk_bound_dev_if && ifindex != sk->sk_bound_dev_if)
With 
  if (sk->sk_bound_dev_if)
> 
> Erich Hoover
> ehoover@mines.edu
> 

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v3 1/2] Implement IP_UNICAST_IF socket option.
       [not found] <62162DF05402B341B3DB59932A1FA992B5B5CA0154@EUSAACMS0702.eamcs.ericsson.se>
@ 2012-02-06 19:35 ` Erich E. Hoover
  2012-02-06 19:40   ` Shawn Lu
  0 siblings, 1 reply; 6+ messages in thread
From: Erich E. Hoover @ 2012-02-06 19:35 UTC (permalink / raw)
  To: Shawn Lu; +Cc: Linux Netdev

On Mon, Feb 6, 2012 at 12:00 PM, Shawn Lu <shawn.lu@ericsson.com> wrote:
>On 2/6/12, Erich E. Hoover <ehoover@mines.edu> wrote:
>> ...
>> +             if (sk->sk_bound_dev_if && ifindex != sk->sk_bound_dev_if)
> If I understand right,  when sk->sk_bound_dev_if !=0 ,  sk->sk_bound_dev_if
> will be used instead. Then why bother to set outif_index.
> Here.

It seems to me that if the socket is already bound to an interface
(other than intended interface) then it makes sense to fail to set the
option, since it will clearly not work under this circumstance.  I may
be misunderstanding you though.

Erich Hoover
ehoover@mines.edu

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2012-02-06 22:14 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-02-06 17:57 [PATCH v3 1/2] Implement IP_UNICAST_IF socket option Erich E. Hoover
     [not found] <62162DF05402B341B3DB59932A1FA992B5B5CA0154@EUSAACMS0702.eamcs.ericsson.se>
2012-02-06 19:35 ` Erich E. Hoover
2012-02-06 19:40   ` Shawn Lu
2012-02-06 19:51     ` Erich E. Hoover
2012-02-06 20:30       ` Shawn Lu
2012-02-06 22:14         ` Erich E. Hoover

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).