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
Closed

Comments

@stapelberg
Copy link
Contributor

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
Copy link
Contributor

mikioh 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 this to the Unplanned milestone Nov 2, 2018
@gopherbot
Copy link

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

@stapelberg
Copy link
Contributor Author

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

@mikioh
Copy link
Contributor

mikioh commented Nov 6, 2018

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

@gopherbot
Copy link

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
…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>
@golang golang locked and limited conversation to collaborators Nov 6, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants