netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Fw: [Bugme-new] [Bug 7665] New: getsockopt(IPV6_*CAST_HOPS) returns -1
@ 2006-12-11 17:56 Andrew Morton
  2006-12-11 21:55 ` Brian Haley
  0 siblings, 1 reply; 7+ messages in thread
From: Andrew Morton @ 2006-12-11 17:56 UTC (permalink / raw)
  To: netdev



Begin forwarded message:

Date: Mon, 11 Dec 2006 07:18:20 -0800
From: bugme-daemon@bugzilla.kernel.org
To: bugme-new@lists.osdl.org
Subject: [Bugme-new] [Bug 7665] New: getsockopt(IPV6_*CAST_HOPS) returns -1


http://bugzilla.kernel.org/show_bug.cgi?id=7665

           Summary: getsockopt(IPV6_*CAST_HOPS) returns -1
    Kernel Version: 2.6.19
            Status: NEW
          Severity: normal
             Owner: yoshfuji@linux-ipv6.org
         Submitter: rdenis@simphalempin.com


Most recent kernel where this bug did *NOT* occur: N/A
Distribution: Debian Sid
Hardware Environment: i386
Software Environment: glibc 2.3.6
Problem Description:

Where fd is a socket (datagram or raw) with IPv6 protocol family,
getsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, ...) succeeds, but the returned 
hop limit is -1. connect()'ing the socket first does not solve the problem.

Same problem with IPV6_MULTICAST_HOPS.

Steps to reproduce:

Compile and run the following test case:

#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

int main (void)
{
        int fd, val;
        socklen_t len = sizeof (val);
        struct sockaddr_in6 addr;

        memset (&addr, 0, sizeof (addr));
        fd = socket (AF_INET6, SOCK_RAW, IPPROTO_UDP);
        addr.sin6_family = AF_INET6;
        addr.sin6_addr.s6_addr[15] = 1;
        connect (fd, (struct sockaddr *)&addr, sizeof (addr));

        if (fd == -1) return 1;
        if (getsockopt (fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &val, &len) == 0)
                printf ("Default unicast hops limit: %d\n", val);
        if (getsockopt (fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val, &len) == 
0)
                printf ("Default multicast hops limit: %d\n", val);
        return 0;
}

------- You are receiving this mail because: -------
You are on the CC list for the bug, or are watching someone who is.

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

* Re: Fw: [Bugme-new] [Bug 7665] New: getsockopt(IPV6_*CAST_HOPS) returns -1
  2006-12-11 17:56 Fw: [Bugme-new] [Bug 7665] New: getsockopt(IPV6_*CAST_HOPS) returns -1 Andrew Morton
@ 2006-12-11 21:55 ` Brian Haley
  2006-12-12  8:08   ` Rémi Denis-Courmont
  0 siblings, 1 reply; 7+ messages in thread
From: Brian Haley @ 2006-12-11 21:55 UTC (permalink / raw)
  To: rdenis; +Cc: Andrew Morton, netdev

Andrew Morton wrote:
> Where fd is a socket (datagram or raw) with IPv6 protocol family,
> getsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, ...) succeeds, but the returned 
> hop limit is -1. connect()'ing the socket first does not solve the problem.

An IPv6 socket's hoplimit value is not set at creation time, instead, 
the hoplimit in an outgoing packet is set dynamically at transmit time 
to one of the following (in this order):

1. Hoplimit route metric (if set)
2. Outgoing interface value (/proc/sys/net/ipv6/conf/ethX/hop_limit)
3. Global IPv6 value (/proc/sys/net/ipv6/conf/all/hop_limit)

A setsockopt() value *will* override this.

Some *nixes have a different behavior and do set it at socket() creation 
time.

-Brian

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

* Re: Fw: [Bugme-new] [Bug 7665] New: getsockopt(IPV6_*CAST_HOPS) returns -1
  2006-12-11 21:55 ` Brian Haley
@ 2006-12-12  8:08   ` Rémi Denis-Courmont
  2006-12-12 21:16     ` Brian Haley
  0 siblings, 1 reply; 7+ messages in thread
From: Rémi Denis-Courmont @ 2006-12-12  8:08 UTC (permalink / raw)
  To: Brian Haley; +Cc: Andrew Morton, netdev

	Hello,

Le lundi 11 décembre 2006 22:55, Brian Haley a écrit :
> Andrew Morton wrote:
> > Where fd is a socket (datagram or raw) with IPv6 protocol family,
> > getsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, ...) succeeds, but
> > the returned hop limit is -1. connect()'ing the socket first does
> > not solve the problem.
>
> An IPv6 socket's hoplimit value is not set at creation time, instead,
> the hoplimit in an outgoing packet is set dynamically at transmit
> time to one of the following (in this order):
>
> 1. Hoplimit route metric (if set)
> 2. Outgoing interface value (/proc/sys/net/ipv6/conf/ethX/hop_limit)
> 3. Global IPv6 value (/proc/sys/net/ipv6/conf/all/hop_limit)
>
> A setsockopt() value *will* override this.

Relevant standard (RFC 3493) notes:

   The IPV6_UNICAST_HOPS option may be used with getsockopt() to
   determine the hop limit value that the system will use for subsequent
   unicast packets sent via that socket.

I don't reckon -1 could be the hop limit value. IMHO, the value from 
case 1 (if socket is connected to some destination), otherwise case 2 
(if bound to a scope interface) or ultimately the default hop limit 
ought to be returned instead, as it will be most often correct, while 
the current behavior is always wrong, unless setsockopt() has been used 
first. I don't if some people may think doing a route lookup in 
getsockopt might be overly expensive, but at least the two other cases 
should be ok, particularly the last one.

-- 
Rémi Denis-Courmont

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

* Re: Fw: [Bugme-new] [Bug 7665] New: getsockopt(IPV6_*CAST_HOPS) returns -1
  2006-12-12  8:08   ` Rémi Denis-Courmont
@ 2006-12-12 21:16     ` Brian Haley
  2006-12-12 22:38       ` Rémi Denis-Courmont
  2006-12-13  1:11       ` David Miller
  0 siblings, 2 replies; 7+ messages in thread
From: Brian Haley @ 2006-12-12 21:16 UTC (permalink / raw)
  To: Rémi Denis-Courmont; +Cc: Andrew Morton, netdev, David Miller

[-- Attachment #1: Type: text/plain, Size: 1664 bytes --]

>>> Where fd is a socket (datagram or raw) with IPv6 protocol family,
>>> getsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, ...) succeeds, but
>>> the returned hop limit is -1. connect()'ing the socket first does
>>> not solve the problem.
>> An IPv6 socket's hoplimit value is not set at creation time, instead,
>> the hoplimit in an outgoing packet is set dynamically at transmit
>> time to one of the following (in this order):
>>
>> 1. Hoplimit route metric (if set)
>> 2. Outgoing interface value (/proc/sys/net/ipv6/conf/ethX/hop_limit)
>> 3. Global IPv6 value (/proc/sys/net/ipv6/conf/all/hop_limit)
>>
>> A setsockopt() value *will* override this.
> 
> Relevant standard (RFC 3493) notes:
> 
>    The IPV6_UNICAST_HOPS option may be used with getsockopt() to
>    determine the hop limit value that the system will use for subsequent
>    unicast packets sent via that socket.
> 
> I don't reckon -1 could be the hop limit value.

-1 means un-initialized.

> IMHO, the value from 
> case 1 (if socket is connected to some destination), otherwise case 2 
> (if bound to a scope interface) or ultimately the default hop limit 
> ought to be returned instead, as it will be most often correct, while 
> the current behavior is always wrong, unless setsockopt() has been used 
> first. I don't if some people may think doing a route lookup in 
> getsockopt might be overly expensive, but at least the two other cases 
> should be ok, particularly the last one.

The following patch seems to work for me, but this code has behaved this 
way for a while, so don't know if it will break any existing apps.

-Brian


Signed-off-by: Brian Haley <brian.haley@hp.com>


[-- Attachment #2: ipv6hops.patch --]
[-- Type: text/x-patch, Size: 776 bytes --]

diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index 1eafcfc..352690e 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -978,12 +978,27 @@ static int do_ipv6_getsockopt(struct soc
 		break;
 
 	case IPV6_UNICAST_HOPS:
-		val = np->hop_limit;
-		break;
-
 	case IPV6_MULTICAST_HOPS:
-		val = np->mcast_hops;
+	{
+		struct dst_entry *dst;
+
+		if (optname == IPV6_UNICAST_HOPS)
+			val = np->hop_limit;
+		else
+			val = np->mcast_hops;
+
+		dst = sk_dst_get(sk);
+		if (dst) {
+			if (val < 0)
+				val = dst_metric(dst, RTAX_HOPLIMIT);
+			if (val < 0)
+				val = ipv6_get_hoplimit(dst->dev);
+			dst_release(dst);
+		}
+		if (val < 0)
+			val = ipv6_devconf.hop_limit;
 		break;
+	}
 
 	case IPV6_MULTICAST_LOOP:
 		val = np->mc_loop;

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

* Re: Fw: [Bugme-new] [Bug 7665] New: getsockopt(IPV6_*CAST_HOPS) returns -1
  2006-12-12 21:16     ` Brian Haley
@ 2006-12-12 22:38       ` Rémi Denis-Courmont
  2006-12-13  1:11       ` David Miller
  1 sibling, 0 replies; 7+ messages in thread
From: Rémi Denis-Courmont @ 2006-12-12 22:38 UTC (permalink / raw)
  To: Brian Haley; +Cc: Andrew Morton, netdev, David Miller

Le mardi 12 décembre 2006 22:16, vous avez écrit :
> > I don't reckon -1 could be the hop limit value.
>
> -1 means un-initialized.

Sure, -1 means "kernel default" for setsockopt(), but it is not 
specified for getsockopt().

> The following patch seems to work for me, but this code has behaved
> this way for a while, so don't know if it will break any existing
> apps.

Google Codesearch for "getsockopt IPV6_MULTICAST_HOPS" yields a bunch of 
apps that seem to assume a valid hop limit is returned, none of which 
detects -1. I believe applying your patch would fix much more apps than 
it is going to break. Hopefully those not handling -1 will somehow cast 
it to 255 if it is ever re-used, but I can also imagine some broken 
SDP-or-similar with "/-1" or "/4294967295" as a hop limit.

Thanks,

-- 
Rémi Denis-Courmont

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

* Re: [Bugme-new] [Bug 7665] New: getsockopt(IPV6_*CAST_HOPS) returns -1
  2006-12-12 21:16     ` Brian Haley
  2006-12-12 22:38       ` Rémi Denis-Courmont
@ 2006-12-13  1:11       ` David Miller
  2006-12-13 17:28         ` Brian Haley
  1 sibling, 1 reply; 7+ messages in thread
From: David Miller @ 2006-12-13  1:11 UTC (permalink / raw)
  To: brian.haley; +Cc: rdenis, akpm, netdev

From: Brian Haley <brian.haley@hp.com>
Date: Tue, 12 Dec 2006 16:16:27 -0500

> The following patch seems to work for me, but this code has behaved this 
> way for a while, so don't know if it will break any existing apps.
> 
> Signed-off-by: Brian Haley <brian.haley@hp.com>

I like this patch so I have applied it, thanks Brian.  I'll
push it to -stable too.

I wonder, since the most accurate return value is tied to the route,
what is expected of this getsockopt() before a socket's identity
(and therefore route) is known?

I suppose returning the default value, which Brian's patch does,
is a reasonable best-effort.

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

* Re: [Bugme-new] [Bug 7665] New: getsockopt(IPV6_*CAST_HOPS) returns -1
  2006-12-13  1:11       ` David Miller
@ 2006-12-13 17:28         ` Brian Haley
  0 siblings, 0 replies; 7+ messages in thread
From: Brian Haley @ 2006-12-13 17:28 UTC (permalink / raw)
  To: David Miller; +Cc: rdenis, akpm, netdev

David Miller wrote:
> I wonder, since the most accurate return value is tied to the route,
> what is expected of this getsockopt() before a socket's identity
> (and therefore route) is known?

A search for RTAX_HOPLIMIT found very little code that ever sets it, 
iproute2 was the only important one, so the interface/system default is 
probably the only one that's ever used.

-Brian

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

end of thread, other threads:[~2006-12-13 17:54 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-12-11 17:56 Fw: [Bugme-new] [Bug 7665] New: getsockopt(IPV6_*CAST_HOPS) returns -1 Andrew Morton
2006-12-11 21:55 ` Brian Haley
2006-12-12  8:08   ` Rémi Denis-Courmont
2006-12-12 21:16     ` Brian Haley
2006-12-12 22:38       ` Rémi Denis-Courmont
2006-12-13  1:11       ` David Miller
2006-12-13 17:28         ` Brian Haley

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).