Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

net, x/net/internal/socket: ipv6ZoneCache not updated on cache misses #28535

Closed
stapelberg opened this issue Nov 1, 2018 · 5 comments

Comments

Projects
None yet
3 participants
@stapelberg
Copy link
Contributor

commented Nov 1, 2018

Please answer these questions before submitting your issue. Thanks!

What version of Go are you using (go version)?

go version go1.11.1 linux/amd64

What operating system and processor architecture are you using (go env)?

GOARCH="amd64"
GOBIN=""
GOCACHE="/home/michael/.cache/go-build"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/michael/go"
GOPROXY=""
GORACE=""
GOROOT="/home/michael/sdk/go1.11.1"
GOTMPDIR=""
GOTOOLDIR="/home/michael/sdk/go1.11.1/pkg/tool/linux_amd64"
GCCGO="/usr/bin/gccgo"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build554331710=/tmp/go-build -gno-record-gcc-switches"

What did you do?

Creating a listener on a link-local IPv6 address fails on bootup for ≈ 1 minute longer than necessary. This code:

ln, err := net.Listen("tcp", "[fe80::ba27:ebff:fe3b:11b0%eth0]:80")
if err != nil {
  log.Println(err)
}

results in:

1970/01/01 01:00:05 listen tcp [fe80::ba27:ebff:fe3b:11b0%eth0]:80: bind: cannot assign requested address
2018/11/01 18:19:37 listen tcp [fe80::ba27:ebff:fe3b:11b0%eth0]:80: bind: invalid argument
2018/11/01 18:20:11 listen tcp [fe80::ba27:ebff:fe3b:11b0%eth0]:80: bind: invalid argument
[…]
2018/11/01 18:21:11 now listening on [fe80::ba27:ebff:fe3b:11b0%eth0]:80

Notably, listening fails for about 1 minute, which is the time it takes for zoneCache to be invalidated.

This is on a Raspberry Pi 3B+, where the eth0 interface is connected via USB (as is the case on all Raspberry Pi models).

What’s happening here is the following (in order):

  1. System boots, I install a listener on all available IP addresses, including ::1, which fills the zoneCache.
  2. The network interface eth0 is discovered once the USB hub is probed.
  3. eth0 comes up, assigning itself a link-local IPv6 address.
  4. At this point, listening fails with “cannot assign requested address”, because the link-local IPv6 address is marked as tentative while the kernel performs duplicate address detection (DAD).
  5. After a second or so, DAD finishes and the address becomes available.
  6. At this point, listening still fails, this time with “invalid argument”, because the bind call’s sin6_scope_id parameter is set to 0, because the zoneCache does not contain the correct entry for the eth0 interface. This is because zoneCache was filled before that interface existed. In strace, you’ll see: [pid 1716] bind(9, {sa_family=AF_INET6, sin6_port=htons(80), inet_pton(AF_INET6, "fe80::ba27:ebff:fe3b:11b0", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, 28) = -1 EINVAL (Invalid argument)
  7. After (at most) 1 minute, the zoneCache is invalidated and updated.
  8. Only now does listening succeed. In strace, you’ll see: [pid 1715] bind(7, {sa_family=AF_INET6, sin6_port=htons(80), inet_pton(AF_INET6, "fe80::ba27:ebff:fe3b:11b0", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=if_nametoindex("eth0")}, 28) = 0

I suggest we update the zoneCache upon cache misses, which fixes this issue. I can send a CL to do that.

@mikioh

This comment has been minimized.

Copy link
Contributor

commented Nov 2, 2018

It's fine if this proposal focuses on the invalidation using the signal of operation malfunction; otherwise, we should take another approach that working together with the routing information base inside the kernel for accuracy and correctness (upon the fate/nature of IP routing; we cannot avoid any micro routing loop at any time, anywhere.)

Also we need to fix x/net/internal/socket too.

I can send a CL to do that.

Thanks. I miss a cup of Glühwein and Heidelberg Christmas market.

@mikioh mikioh changed the title net: ipv6ZoneCache not updated on cache misses net, x/net/internal/socket: ipv6ZoneCache not updated on cache misses Nov 2, 2018

@mikioh mikioh added the help wanted label Nov 2, 2018

@mikioh mikioh added this to the Unplanned milestone Nov 2, 2018

@gopherbot

This comment has been minimized.

Copy link

commented Nov 2, 2018

Change https://golang.org/cl/146941 mentions this issue: net: update zoneCache on cache misses to cover appearing interfaces

@stapelberg

This comment has been minimized.

Copy link
Contributor Author

commented Nov 2, 2018

Once the change landed, I can update x/net, too.

@gopherbot gopherbot closed this in 9fc22d2 Nov 6, 2018

@mikioh

This comment has been minimized.

Copy link
Contributor

commented Nov 6, 2018

Please add Updates golang/go#28535 to the CL description for x/net.

@gopherbot

This comment has been minimized.

Copy link

commented Nov 6, 2018

Change https://golang.org/cl/147739 mentions this issue: net: update zoneCache on cache misses to cover appearing interfaces

gopherbot pushed a commit to golang/net that referenced this issue Nov 7, 2018

internal/socket: update zoneCache on cache misses to cover appearing …
…interfaces

Updates golang/go#28535

Change-Id: Id653b21b4d893cc8b6b9a74b129d1ce9b7e26a9f
Reviewed-on: https://go-review.googlesource.com/c/147739
Reviewed-by: Mikio Hara <mikioh.public.networking@gmail.com>
Run-TryBot: Mikio Hara <mikioh.public.networking@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.