github.com/Andyfoo/golang/x/net@v0.0.0-20190901054642-57c1bf301704/ipv6/readwrite_test.go (about) 1 // Copyright 2013 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package ipv6_test 6 7 import ( 8 "bytes" 9 "fmt" 10 "net" 11 "runtime" 12 "strings" 13 "sync" 14 "testing" 15 16 "github.com/Andyfoo/golang/x/net/internal/iana" 17 "github.com/Andyfoo/golang/x/net/ipv6" 18 "github.com/Andyfoo/golang/x/net/nettest" 19 ) 20 21 func BenchmarkReadWriteUnicast(b *testing.B) { 22 switch runtime.GOOS { 23 case "fuchsia", "hurd", "js", "nacl", "plan9", "windows": 24 b.Skipf("not supported on %s", runtime.GOOS) 25 } 26 27 c, err := nettest.NewLocalPacketListener("udp6") 28 if err != nil { 29 b.Skipf("not supported on %s/%s: %v", runtime.GOOS, runtime.GOARCH, err) 30 } 31 defer c.Close() 32 33 dst := c.LocalAddr() 34 wb, rb := []byte("HELLO-R-U-THERE"), make([]byte, 128) 35 36 b.Run("NetUDP", func(b *testing.B) { 37 for i := 0; i < b.N; i++ { 38 if _, err := c.WriteTo(wb, dst); err != nil { 39 b.Fatal(err) 40 } 41 if _, _, err := c.ReadFrom(rb); err != nil { 42 b.Fatal(err) 43 } 44 } 45 }) 46 b.Run("IPv6UDP", func(b *testing.B) { 47 p := ipv6.NewPacketConn(c) 48 cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagSrc | ipv6.FlagDst | ipv6.FlagInterface | ipv6.FlagPathMTU 49 if err := p.SetControlMessage(cf, true); err != nil { 50 b.Fatal(err) 51 } 52 cm := ipv6.ControlMessage{ 53 TrafficClass: iana.DiffServAF11 | iana.CongestionExperienced, 54 HopLimit: 1, 55 } 56 ifi, _ := nettest.RoutedInterface("ip6", net.FlagUp|net.FlagLoopback) 57 if ifi != nil { 58 cm.IfIndex = ifi.Index 59 } 60 61 for i := 0; i < b.N; i++ { 62 if _, err := p.WriteTo(wb, &cm, dst); err != nil { 63 b.Fatal(err) 64 } 65 if _, _, _, err := p.ReadFrom(rb); err != nil { 66 b.Fatal(err) 67 } 68 } 69 }) 70 } 71 72 func BenchmarkPacketConnReadWriteUnicast(b *testing.B) { 73 switch runtime.GOOS { 74 case "fuchsia", "hurd", "js", "nacl", "plan9", "windows": 75 b.Skipf("not supported on %s", runtime.GOOS) 76 } 77 78 payload := []byte("HELLO-R-U-THERE") 79 iph := []byte{ 80 0x69, 0x8b, 0xee, 0xf1, 0xca, 0xfe, 0xff, 0x01, 81 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x01, 0x00, 0x00, 82 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 83 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x02, 0x00, 0x00, 84 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 85 } 86 greh := []byte{0x00, 0x00, 0x86, 0xdd, 0x00, 0x00, 0x00, 0x00} 87 datagram := append(greh, append(iph, payload...)...) 88 bb := make([]byte, 128) 89 cm := ipv6.ControlMessage{ 90 TrafficClass: iana.DiffServAF11 | iana.CongestionExperienced, 91 HopLimit: 1, 92 Src: net.IPv6loopback, 93 } 94 ifi, _ := nettest.RoutedInterface("ip6", net.FlagUp|net.FlagLoopback) 95 if ifi != nil { 96 cm.IfIndex = ifi.Index 97 } 98 99 b.Run("UDP", func(b *testing.B) { 100 c, err := nettest.NewLocalPacketListener("udp6") 101 if err != nil { 102 b.Skipf("not supported on %s/%s: %v", runtime.GOOS, runtime.GOARCH, err) 103 } 104 defer c.Close() 105 p := ipv6.NewPacketConn(c) 106 dst := c.LocalAddr() 107 cf := ipv6.FlagHopLimit | ipv6.FlagInterface 108 if err := p.SetControlMessage(cf, true); err != nil { 109 b.Fatal(err) 110 } 111 wms := []ipv6.Message{ 112 { 113 Buffers: [][]byte{payload}, 114 Addr: dst, 115 OOB: cm.Marshal(), 116 }, 117 } 118 rms := []ipv6.Message{ 119 { 120 Buffers: [][]byte{bb}, 121 OOB: ipv6.NewControlMessage(cf), 122 }, 123 } 124 b.Run("Net", func(b *testing.B) { 125 for i := 0; i < b.N; i++ { 126 if _, err := c.WriteTo(payload, dst); err != nil { 127 b.Fatal(err) 128 } 129 if _, _, err := c.ReadFrom(bb); err != nil { 130 b.Fatal(err) 131 } 132 } 133 }) 134 b.Run("ToFrom", func(b *testing.B) { 135 for i := 0; i < b.N; i++ { 136 if _, err := p.WriteTo(payload, &cm, dst); err != nil { 137 b.Fatal(err) 138 } 139 if _, _, _, err := p.ReadFrom(bb); err != nil { 140 b.Fatal(err) 141 } 142 } 143 }) 144 b.Run("Batch", func(b *testing.B) { 145 for i := 0; i < b.N; i++ { 146 if _, err := p.WriteBatch(wms, 0); err != nil { 147 b.Fatal(err) 148 } 149 if _, err := p.ReadBatch(rms, 0); err != nil { 150 b.Fatal(err) 151 } 152 } 153 }) 154 }) 155 b.Run("IP", func(b *testing.B) { 156 switch runtime.GOOS { 157 case "netbsd": 158 b.Skip("need to configure gre on netbsd") 159 case "openbsd": 160 b.Skip("net.inet.gre.allow=0 by default on openbsd") 161 } 162 163 c, err := net.ListenPacket(fmt.Sprintf("ip6:%d", iana.ProtocolGRE), "::1") 164 if err != nil { 165 b.Skipf("not supported on %s/%s: %v", runtime.GOOS, runtime.GOARCH, err) 166 } 167 defer c.Close() 168 p := ipv6.NewPacketConn(c) 169 dst := c.LocalAddr() 170 cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagSrc | ipv6.FlagDst | ipv6.FlagInterface | ipv6.FlagPathMTU 171 if err := p.SetControlMessage(cf, true); err != nil { 172 b.Fatal(err) 173 } 174 wms := []ipv6.Message{ 175 { 176 Buffers: [][]byte{datagram}, 177 Addr: dst, 178 OOB: cm.Marshal(), 179 }, 180 } 181 rms := []ipv6.Message{ 182 { 183 Buffers: [][]byte{bb}, 184 OOB: ipv6.NewControlMessage(cf), 185 }, 186 } 187 b.Run("Net", func(b *testing.B) { 188 for i := 0; i < b.N; i++ { 189 if _, err := c.WriteTo(datagram, dst); err != nil { 190 b.Fatal(err) 191 } 192 if _, _, err := c.ReadFrom(bb); err != nil { 193 b.Fatal(err) 194 } 195 } 196 }) 197 b.Run("ToFrom", func(b *testing.B) { 198 for i := 0; i < b.N; i++ { 199 if _, err := p.WriteTo(datagram, &cm, dst); err != nil { 200 b.Fatal(err) 201 } 202 if _, _, _, err := p.ReadFrom(bb); err != nil { 203 b.Fatal(err) 204 } 205 } 206 }) 207 b.Run("Batch", func(b *testing.B) { 208 for i := 0; i < b.N; i++ { 209 if _, err := p.WriteBatch(wms, 0); err != nil { 210 b.Fatal(err) 211 } 212 if _, err := p.ReadBatch(rms, 0); err != nil { 213 b.Fatal(err) 214 } 215 } 216 }) 217 }) 218 } 219 220 func TestPacketConnConcurrentReadWriteUnicastUDP(t *testing.T) { 221 switch runtime.GOOS { 222 case "fuchsia", "hurd", "js", "nacl", "plan9", "windows": 223 t.Skipf("not supported on %s", runtime.GOOS) 224 } 225 if !nettest.SupportsIPv6() { 226 t.Skip("ipv6 is not supported") 227 } 228 229 c, err := nettest.NewLocalPacketListener("udp6") 230 if err != nil { 231 t.Fatal(err) 232 } 233 defer c.Close() 234 p := ipv6.NewPacketConn(c) 235 defer p.Close() 236 237 dst := c.LocalAddr() 238 ifi, _ := nettest.RoutedInterface("ip6", net.FlagUp|net.FlagLoopback) 239 cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagSrc | ipv6.FlagDst | ipv6.FlagInterface | ipv6.FlagPathMTU 240 wb := []byte("HELLO-R-U-THERE") 241 242 if err := p.SetControlMessage(cf, true); err != nil { // probe before test 243 if protocolNotSupported(err) { 244 t.Skipf("not supported on %s", runtime.GOOS) 245 } 246 t.Fatal(err) 247 } 248 249 var wg sync.WaitGroup 250 reader := func() { 251 defer wg.Done() 252 rb := make([]byte, 128) 253 if n, cm, _, err := p.ReadFrom(rb); err != nil { 254 t.Error(err) 255 return 256 } else if !bytes.Equal(rb[:n], wb) { 257 t.Errorf("got %v; want %v", rb[:n], wb) 258 return 259 } else { 260 s := cm.String() 261 if strings.Contains(s, ",") { 262 t.Errorf("should be space-separated values: %s", s) 263 } 264 } 265 } 266 writer := func(toggle bool) { 267 defer wg.Done() 268 cm := ipv6.ControlMessage{ 269 TrafficClass: iana.DiffServAF11 | iana.CongestionExperienced, 270 Src: net.IPv6loopback, 271 } 272 if ifi != nil { 273 cm.IfIndex = ifi.Index 274 } 275 if err := p.SetControlMessage(cf, toggle); err != nil { 276 t.Error(err) 277 return 278 } 279 if n, err := p.WriteTo(wb, &cm, dst); err != nil { 280 t.Error(err) 281 return 282 } else if n != len(wb) { 283 t.Errorf("got %d; want %d", n, len(wb)) 284 return 285 } 286 } 287 288 const N = 10 289 wg.Add(N) 290 for i := 0; i < N; i++ { 291 go reader() 292 } 293 wg.Add(2 * N) 294 for i := 0; i < 2*N; i++ { 295 go writer(i%2 != 0) 296 } 297 wg.Add(N) 298 for i := 0; i < N; i++ { 299 go reader() 300 } 301 wg.Wait() 302 } 303 304 func TestPacketConnConcurrentReadWriteUnicast(t *testing.T) { 305 switch runtime.GOOS { 306 case "fuchsia", "hurd", "js", "nacl", "plan9", "windows": 307 t.Skipf("not supported on %s", runtime.GOOS) 308 } 309 310 payload := []byte("HELLO-R-U-THERE") 311 iph := []byte{ 312 0x69, 0x8b, 0xee, 0xf1, 0xca, 0xfe, 0xff, 0x01, 313 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x01, 0x00, 0x00, 314 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 315 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x02, 0x00, 0x00, 316 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 317 } 318 greh := []byte{0x00, 0x00, 0x86, 0xdd, 0x00, 0x00, 0x00, 0x00} 319 datagram := append(greh, append(iph, payload...)...) 320 321 t.Run("UDP", func(t *testing.T) { 322 c, err := nettest.NewLocalPacketListener("udp6") 323 if err != nil { 324 t.Skipf("not supported on %s/%s: %v", runtime.GOOS, runtime.GOARCH, err) 325 } 326 defer c.Close() 327 p := ipv6.NewPacketConn(c) 328 t.Run("ToFrom", func(t *testing.T) { 329 testPacketConnConcurrentReadWriteUnicast(t, p, payload, c.LocalAddr(), false) 330 }) 331 t.Run("Batch", func(t *testing.T) { 332 testPacketConnConcurrentReadWriteUnicast(t, p, payload, c.LocalAddr(), true) 333 }) 334 }) 335 t.Run("IP", func(t *testing.T) { 336 switch runtime.GOOS { 337 case "netbsd": 338 t.Skip("need to configure gre on netbsd") 339 case "openbsd": 340 t.Skip("net.inet.gre.allow=0 by default on openbsd") 341 } 342 343 c, err := net.ListenPacket(fmt.Sprintf("ip6:%d", iana.ProtocolGRE), "::1") 344 if err != nil { 345 t.Skipf("not supported on %s/%s: %v", runtime.GOOS, runtime.GOARCH, err) 346 } 347 defer c.Close() 348 p := ipv6.NewPacketConn(c) 349 t.Run("ToFrom", func(t *testing.T) { 350 testPacketConnConcurrentReadWriteUnicast(t, p, datagram, c.LocalAddr(), false) 351 }) 352 t.Run("Batch", func(t *testing.T) { 353 testPacketConnConcurrentReadWriteUnicast(t, p, datagram, c.LocalAddr(), true) 354 }) 355 }) 356 } 357 358 func testPacketConnConcurrentReadWriteUnicast(t *testing.T, p *ipv6.PacketConn, data []byte, dst net.Addr, batch bool) { 359 t.Helper() 360 361 ifi, _ := nettest.RoutedInterface("ip6", net.FlagUp|net.FlagLoopback) 362 cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagSrc | ipv6.FlagDst | ipv6.FlagInterface | ipv6.FlagPathMTU 363 364 if err := p.SetControlMessage(cf, true); err != nil { // probe before test 365 if protocolNotSupported(err) { 366 t.Skipf("not supported on %s", runtime.GOOS) 367 } 368 t.Fatal(err) 369 } 370 371 var wg sync.WaitGroup 372 reader := func() { 373 defer wg.Done() 374 b := make([]byte, 128) 375 n, cm, _, err := p.ReadFrom(b) 376 if err != nil { 377 t.Error(err) 378 return 379 } 380 if !bytes.Equal(b[:n], data) { 381 t.Errorf("got %#v; want %#v", b[:n], data) 382 return 383 } 384 s := cm.String() 385 if strings.Contains(s, ",") { 386 t.Errorf("should be space-separated values: %s", s) 387 return 388 } 389 } 390 batchReader := func() { 391 defer wg.Done() 392 ms := []ipv6.Message{ 393 { 394 Buffers: [][]byte{make([]byte, 128)}, 395 OOB: ipv6.NewControlMessage(cf), 396 }, 397 } 398 n, err := p.ReadBatch(ms, 0) 399 if err != nil { 400 t.Error(err) 401 return 402 } 403 if n != len(ms) { 404 t.Errorf("got %d; want %d", n, len(ms)) 405 return 406 } 407 var cm ipv6.ControlMessage 408 if err := cm.Parse(ms[0].OOB[:ms[0].NN]); err != nil { 409 t.Error(err) 410 return 411 } 412 b := ms[0].Buffers[0][:ms[0].N] 413 if !bytes.Equal(b, data) { 414 t.Errorf("got %#v; want %#v", b, data) 415 return 416 } 417 s := cm.String() 418 if strings.Contains(s, ",") { 419 t.Errorf("should be space-separated values: %s", s) 420 return 421 } 422 } 423 writer := func(toggle bool) { 424 defer wg.Done() 425 cm := ipv6.ControlMessage{ 426 TrafficClass: iana.DiffServAF11 | iana.CongestionExperienced, 427 HopLimit: 1, 428 Src: net.IPv6loopback, 429 } 430 if ifi != nil { 431 cm.IfIndex = ifi.Index 432 } 433 if err := p.SetControlMessage(cf, toggle); err != nil { 434 t.Error(err) 435 return 436 } 437 n, err := p.WriteTo(data, &cm, dst) 438 if err != nil { 439 t.Error(err) 440 return 441 } 442 if n != len(data) { 443 t.Errorf("got %d; want %d", n, len(data)) 444 return 445 } 446 } 447 batchWriter := func(toggle bool) { 448 defer wg.Done() 449 cm := ipv6.ControlMessage{ 450 TrafficClass: iana.DiffServAF11 | iana.CongestionExperienced, 451 HopLimit: 1, 452 Src: net.IPv6loopback, 453 } 454 if ifi != nil { 455 cm.IfIndex = ifi.Index 456 } 457 if err := p.SetControlMessage(cf, toggle); err != nil { 458 t.Error(err) 459 return 460 } 461 ms := []ipv6.Message{ 462 { 463 Buffers: [][]byte{data}, 464 OOB: cm.Marshal(), 465 Addr: dst, 466 }, 467 } 468 n, err := p.WriteBatch(ms, 0) 469 if err != nil { 470 t.Error(err) 471 return 472 } 473 if n != len(ms) { 474 t.Errorf("got %d; want %d", n, len(ms)) 475 return 476 } 477 if ms[0].N != len(data) { 478 t.Errorf("got %d; want %d", ms[0].N, len(data)) 479 return 480 } 481 } 482 483 const N = 10 484 wg.Add(N) 485 for i := 0; i < N; i++ { 486 if batch { 487 go batchReader() 488 } else { 489 go reader() 490 } 491 } 492 wg.Add(2 * N) 493 for i := 0; i < 2*N; i++ { 494 if batch { 495 go batchWriter(i%2 != 0) 496 } else { 497 go writer(i%2 != 0) 498 } 499 } 500 wg.Add(N) 501 for i := 0; i < N; i++ { 502 if batch { 503 go batchReader() 504 } else { 505 go reader() 506 } 507 } 508 wg.Wait() 509 }