github.com/Andyfoo/golang/x/net@v0.0.0-20190901054642-57c1bf301704/ipv4/readwrite_test.go (about) 1 // Copyright 2012 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 ipv4_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/ipv4" 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("udp4") 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("IPv4UDP", func(b *testing.B) { 47 p := ipv4.NewPacketConn(c) 48 cf := ipv4.FlagTTL | ipv4.FlagInterface 49 if err := p.SetControlMessage(cf, true); err != nil { 50 b.Fatal(err) 51 } 52 cm := ipv4.ControlMessage{TTL: 1} 53 ifi, _ := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagLoopback) 54 if ifi != nil { 55 cm.IfIndex = ifi.Index 56 } 57 58 for i := 0; i < b.N; i++ { 59 if _, err := p.WriteTo(wb, &cm, dst); err != nil { 60 b.Fatal(err) 61 } 62 if _, _, _, err := p.ReadFrom(rb); err != nil { 63 b.Fatal(err) 64 } 65 } 66 }) 67 } 68 69 func BenchmarkPacketConnReadWriteUnicast(b *testing.B) { 70 switch runtime.GOOS { 71 case "fuchsia", "hurd", "js", "nacl", "plan9", "windows": 72 b.Skipf("not supported on %s", runtime.GOOS) 73 } 74 75 payload := []byte("HELLO-R-U-THERE") 76 iph, err := (&ipv4.Header{ 77 Version: ipv4.Version, 78 Len: ipv4.HeaderLen, 79 TotalLen: ipv4.HeaderLen + len(payload), 80 TTL: 1, 81 Protocol: iana.ProtocolReserved, 82 Src: net.IPv4(192, 0, 2, 1), 83 Dst: net.IPv4(192, 0, 2, 254), 84 }).Marshal() 85 if err != nil { 86 b.Fatal(err) 87 } 88 greh := []byte{0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00} 89 datagram := append(greh, append(iph, payload...)...) 90 bb := make([]byte, 128) 91 cm := ipv4.ControlMessage{ 92 Src: net.IPv4(127, 0, 0, 1), 93 } 94 ifi, _ := nettest.RoutedInterface("ip4", 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("udp4") 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 := ipv4.NewPacketConn(c) 106 dst := c.LocalAddr() 107 cf := ipv4.FlagTTL | ipv4.FlagInterface 108 if err := p.SetControlMessage(cf, true); err != nil { 109 b.Fatal(err) 110 } 111 wms := []ipv4.Message{ 112 { 113 Buffers: [][]byte{payload}, 114 Addr: dst, 115 OOB: cm.Marshal(), 116 }, 117 } 118 rms := []ipv4.Message{ 119 { 120 Buffers: [][]byte{bb}, 121 OOB: ipv4.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("ip4:%d", iana.ProtocolGRE), "127.0.0.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 := ipv4.NewPacketConn(c) 169 dst := c.LocalAddr() 170 cf := ipv4.FlagTTL | ipv4.FlagInterface 171 if err := p.SetControlMessage(cf, true); err != nil { 172 b.Fatal(err) 173 } 174 wms := []ipv4.Message{ 175 { 176 Buffers: [][]byte{datagram}, 177 Addr: dst, 178 OOB: cm.Marshal(), 179 }, 180 } 181 rms := []ipv4.Message{ 182 { 183 Buffers: [][]byte{bb}, 184 OOB: ipv4.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 226 c, err := nettest.NewLocalPacketListener("udp4") 227 if err != nil { 228 t.Fatal(err) 229 } 230 defer c.Close() 231 p := ipv4.NewPacketConn(c) 232 defer p.Close() 233 234 dst := c.LocalAddr() 235 ifi, _ := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagLoopback) 236 cf := ipv4.FlagTTL | ipv4.FlagSrc | ipv4.FlagDst | ipv4.FlagInterface 237 wb := []byte("HELLO-R-U-THERE") 238 239 if err := p.SetControlMessage(cf, true); err != nil { // probe before test 240 if protocolNotSupported(err) { 241 t.Skipf("not supported on %s", runtime.GOOS) 242 } 243 t.Fatal(err) 244 } 245 246 var wg sync.WaitGroup 247 reader := func() { 248 defer wg.Done() 249 rb := make([]byte, 128) 250 if n, cm, _, err := p.ReadFrom(rb); err != nil { 251 t.Error(err) 252 return 253 } else if !bytes.Equal(rb[:n], wb) { 254 t.Errorf("got %v; want %v", rb[:n], wb) 255 return 256 } else { 257 s := cm.String() 258 if strings.Contains(s, ",") { 259 t.Errorf("should be space-separated values: %s", s) 260 } 261 } 262 } 263 writer := func(toggle bool) { 264 defer wg.Done() 265 cm := ipv4.ControlMessage{ 266 Src: net.IPv4(127, 0, 0, 1), 267 } 268 if ifi != nil { 269 cm.IfIndex = ifi.Index 270 } 271 if err := p.SetControlMessage(cf, toggle); err != nil { 272 t.Error(err) 273 return 274 } 275 if n, err := p.WriteTo(wb, &cm, dst); err != nil { 276 t.Error(err) 277 return 278 } else if n != len(wb) { 279 t.Errorf("got %d; want %d", n, len(wb)) 280 return 281 } 282 } 283 284 const N = 10 285 wg.Add(N) 286 for i := 0; i < N; i++ { 287 go reader() 288 } 289 wg.Add(2 * N) 290 for i := 0; i < 2*N; i++ { 291 go writer(i%2 != 0) 292 } 293 wg.Add(N) 294 for i := 0; i < N; i++ { 295 go reader() 296 } 297 wg.Wait() 298 } 299 300 func TestPacketConnConcurrentReadWriteUnicast(t *testing.T) { 301 switch runtime.GOOS { 302 case "fuchsia", "hurd", "js", "nacl", "plan9", "windows": 303 t.Skipf("not supported on %s", runtime.GOOS) 304 } 305 306 payload := []byte("HELLO-R-U-THERE") 307 iph, err := (&ipv4.Header{ 308 Version: ipv4.Version, 309 Len: ipv4.HeaderLen, 310 TotalLen: ipv4.HeaderLen + len(payload), 311 TTL: 1, 312 Protocol: iana.ProtocolReserved, 313 Src: net.IPv4(192, 0, 2, 1), 314 Dst: net.IPv4(192, 0, 2, 254), 315 }).Marshal() 316 if err != nil { 317 t.Fatal(err) 318 } 319 greh := []byte{0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00} 320 datagram := append(greh, append(iph, payload...)...) 321 322 t.Run("UDP", func(t *testing.T) { 323 c, err := nettest.NewLocalPacketListener("udp4") 324 if err != nil { 325 t.Skipf("not supported on %s/%s: %v", runtime.GOOS, runtime.GOARCH, err) 326 } 327 defer c.Close() 328 p := ipv4.NewPacketConn(c) 329 t.Run("ToFrom", func(t *testing.T) { 330 testPacketConnConcurrentReadWriteUnicast(t, p, payload, c.LocalAddr(), false) 331 }) 332 t.Run("Batch", func(t *testing.T) { 333 testPacketConnConcurrentReadWriteUnicast(t, p, payload, c.LocalAddr(), true) 334 }) 335 }) 336 t.Run("IP", func(t *testing.T) { 337 switch runtime.GOOS { 338 case "netbsd": 339 t.Skip("need to configure gre on netbsd") 340 case "openbsd": 341 t.Skip("net.inet.gre.allow=0 by default on openbsd") 342 } 343 344 c, err := net.ListenPacket(fmt.Sprintf("ip4:%d", iana.ProtocolGRE), "127.0.0.1") 345 if err != nil { 346 t.Skipf("not supported on %s/%s: %v", runtime.GOOS, runtime.GOARCH, err) 347 } 348 defer c.Close() 349 p := ipv4.NewPacketConn(c) 350 t.Run("ToFrom", func(t *testing.T) { 351 testPacketConnConcurrentReadWriteUnicast(t, p, datagram, c.LocalAddr(), false) 352 }) 353 t.Run("Batch", func(t *testing.T) { 354 testPacketConnConcurrentReadWriteUnicast(t, p, datagram, c.LocalAddr(), true) 355 }) 356 }) 357 } 358 359 func testPacketConnConcurrentReadWriteUnicast(t *testing.T, p *ipv4.PacketConn, data []byte, dst net.Addr, batch bool) { 360 t.Helper() 361 362 ifi, _ := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagLoopback) 363 cf := ipv4.FlagTTL | ipv4.FlagSrc | ipv4.FlagDst | ipv4.FlagInterface 364 365 if err := p.SetControlMessage(cf, true); err != nil { // probe before test 366 if protocolNotSupported(err) { 367 t.Skipf("not supported on %s", runtime.GOOS) 368 } 369 t.Fatal(err) 370 } 371 372 var wg sync.WaitGroup 373 reader := func() { 374 defer wg.Done() 375 b := make([]byte, 128) 376 n, cm, _, err := p.ReadFrom(b) 377 if err != nil { 378 t.Error(err) 379 return 380 } 381 if !bytes.Equal(b[:n], data) { 382 t.Errorf("got %#v; want %#v", b[:n], data) 383 return 384 } 385 s := cm.String() 386 if strings.Contains(s, ",") { 387 t.Errorf("should be space-separated values: %s", s) 388 return 389 } 390 } 391 batchReader := func() { 392 defer wg.Done() 393 ms := []ipv4.Message{ 394 { 395 Buffers: [][]byte{make([]byte, 128)}, 396 OOB: ipv4.NewControlMessage(cf), 397 }, 398 } 399 n, err := p.ReadBatch(ms, 0) 400 if err != nil { 401 t.Error(err) 402 return 403 } 404 if n != len(ms) { 405 t.Errorf("got %d; want %d", n, len(ms)) 406 return 407 } 408 var cm ipv4.ControlMessage 409 if err := cm.Parse(ms[0].OOB[:ms[0].NN]); err != nil { 410 t.Error(err) 411 return 412 } 413 var b []byte 414 if _, ok := dst.(*net.IPAddr); ok { 415 var h ipv4.Header 416 if err := h.Parse(ms[0].Buffers[0][:ms[0].N]); err != nil { 417 t.Error(err) 418 return 419 } 420 b = ms[0].Buffers[0][h.Len:ms[0].N] 421 } else { 422 b = ms[0].Buffers[0][:ms[0].N] 423 } 424 if !bytes.Equal(b, data) { 425 t.Errorf("got %#v; want %#v", b, data) 426 return 427 } 428 s := cm.String() 429 if strings.Contains(s, ",") { 430 t.Errorf("should be space-separated values: %s", s) 431 return 432 } 433 } 434 writer := func(toggle bool) { 435 defer wg.Done() 436 cm := ipv4.ControlMessage{ 437 Src: net.IPv4(127, 0, 0, 1), 438 } 439 if ifi != nil { 440 cm.IfIndex = ifi.Index 441 } 442 if err := p.SetControlMessage(cf, toggle); err != nil { 443 t.Error(err) 444 return 445 } 446 n, err := p.WriteTo(data, &cm, dst) 447 if err != nil { 448 t.Error(err) 449 return 450 } 451 if n != len(data) { 452 t.Errorf("got %d; want %d", n, len(data)) 453 return 454 } 455 } 456 batchWriter := func(toggle bool) { 457 defer wg.Done() 458 cm := ipv4.ControlMessage{ 459 Src: net.IPv4(127, 0, 0, 1), 460 } 461 if ifi != nil { 462 cm.IfIndex = ifi.Index 463 } 464 if err := p.SetControlMessage(cf, toggle); err != nil { 465 t.Error(err) 466 return 467 } 468 ms := []ipv4.Message{ 469 { 470 Buffers: [][]byte{data}, 471 OOB: cm.Marshal(), 472 Addr: dst, 473 }, 474 } 475 n, err := p.WriteBatch(ms, 0) 476 if err != nil { 477 t.Error(err) 478 return 479 } 480 if n != len(ms) { 481 t.Errorf("got %d; want %d", n, len(ms)) 482 return 483 } 484 if ms[0].N != len(data) { 485 t.Errorf("got %d; want %d", ms[0].N, len(data)) 486 return 487 } 488 } 489 490 const N = 10 491 wg.Add(N) 492 for i := 0; i < N; i++ { 493 if batch { 494 go batchReader() 495 } else { 496 go reader() 497 } 498 } 499 wg.Add(2 * N) 500 for i := 0; i < 2*N; i++ { 501 if batch { 502 go batchWriter(i%2 != 0) 503 } else { 504 go writer(i%2 != 0) 505 } 506 507 } 508 wg.Add(N) 509 for i := 0; i < N; i++ { 510 if batch { 511 go batchReader() 512 } else { 513 go reader() 514 } 515 } 516 wg.Wait() 517 }