1 // Copyright 2017 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.
18 "golang.org/x/net/internal/iana"
19 "golang.org/x/net/internal/nettest"
20 "golang.org/x/net/ipv6"
23 func BenchmarkPacketConnReadWriteUnicast(b *testing.B) {
25 case "nacl", "plan9", "windows":
26 b.Skipf("not supported on %s", runtime.GOOS)
29 payload := []byte("HELLO-R-U-THERE")
31 0x69, 0x8b, 0xee, 0xf1, 0xca, 0xfe, 0xff, 0x01,
32 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x01, 0x00, 0x00,
33 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
34 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x02, 0x00, 0x00,
35 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
37 greh := []byte{0x00, 0x00, 0x86, 0xdd, 0x00, 0x00, 0x00, 0x00}
38 datagram := append(greh, append(iph, payload...)...)
39 bb := make([]byte, 128)
40 cm := ipv6.ControlMessage{
41 TrafficClass: iana.DiffServAF11 | iana.CongestionExperienced,
43 Src: net.IPv6loopback,
45 if ifi := nettest.RoutedInterface("ip6", net.FlagUp|net.FlagLoopback); ifi != nil {
46 cm.IfIndex = ifi.Index
49 b.Run("UDP", func(b *testing.B) {
50 c, err := nettest.NewLocalPacketListener("udp6")
52 b.Skipf("not supported on %s/%s: %v", runtime.GOOS, runtime.GOARCH, err)
55 p := ipv6.NewPacketConn(c)
57 cf := ipv6.FlagHopLimit | ipv6.FlagInterface
58 if err := p.SetControlMessage(cf, true); err != nil {
61 wms := []ipv6.Message{
63 Buffers: [][]byte{payload},
68 rms := []ipv6.Message{
70 Buffers: [][]byte{bb},
71 OOB: ipv6.NewControlMessage(cf),
74 b.Run("Net", func(b *testing.B) {
75 for i := 0; i < b.N; i++ {
76 if _, err := c.WriteTo(payload, dst); err != nil {
79 if _, _, err := c.ReadFrom(bb); err != nil {
84 b.Run("ToFrom", func(b *testing.B) {
85 for i := 0; i < b.N; i++ {
86 if _, err := p.WriteTo(payload, &cm, dst); err != nil {
89 if _, _, _, err := p.ReadFrom(bb); err != nil {
94 b.Run("Batch", func(b *testing.B) {
95 for i := 0; i < b.N; i++ {
96 if _, err := p.WriteBatch(wms, 0); err != nil {
99 if _, err := p.ReadBatch(rms, 0); err != nil {
105 b.Run("IP", func(b *testing.B) {
106 switch runtime.GOOS {
108 b.Skip("need to configure gre on netbsd")
110 b.Skip("net.inet.gre.allow=0 by default on openbsd")
113 c, err := net.ListenPacket(fmt.Sprintf("ip6:%d", iana.ProtocolGRE), "::1")
115 b.Skipf("not supported on %s/%s: %v", runtime.GOOS, runtime.GOARCH, err)
118 p := ipv6.NewPacketConn(c)
120 cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagSrc | ipv6.FlagDst | ipv6.FlagInterface | ipv6.FlagPathMTU
121 if err := p.SetControlMessage(cf, true); err != nil {
124 wms := []ipv6.Message{
126 Buffers: [][]byte{datagram},
131 rms := []ipv6.Message{
133 Buffers: [][]byte{bb},
134 OOB: ipv6.NewControlMessage(cf),
137 b.Run("Net", func(b *testing.B) {
138 for i := 0; i < b.N; i++ {
139 if _, err := c.WriteTo(datagram, dst); err != nil {
142 if _, _, err := c.ReadFrom(bb); err != nil {
147 b.Run("ToFrom", func(b *testing.B) {
148 for i := 0; i < b.N; i++ {
149 if _, err := p.WriteTo(datagram, &cm, dst); err != nil {
152 if _, _, _, err := p.ReadFrom(bb); err != nil {
157 b.Run("Batch", func(b *testing.B) {
158 for i := 0; i < b.N; i++ {
159 if _, err := p.WriteBatch(wms, 0); err != nil {
162 if _, err := p.ReadBatch(rms, 0); err != nil {
170 func TestPacketConnConcurrentReadWriteUnicast(t *testing.T) {
171 switch runtime.GOOS {
172 case "nacl", "plan9", "windows":
173 t.Skipf("not supported on %s", runtime.GOOS)
176 payload := []byte("HELLO-R-U-THERE")
178 0x69, 0x8b, 0xee, 0xf1, 0xca, 0xfe, 0xff, 0x01,
179 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x01, 0x00, 0x00,
180 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
181 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x02, 0x00, 0x00,
182 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
184 greh := []byte{0x00, 0x00, 0x86, 0xdd, 0x00, 0x00, 0x00, 0x00}
185 datagram := append(greh, append(iph, payload...)...)
187 t.Run("UDP", func(t *testing.T) {
188 c, err := nettest.NewLocalPacketListener("udp6")
190 t.Skipf("not supported on %s/%s: %v", runtime.GOOS, runtime.GOARCH, err)
193 p := ipv6.NewPacketConn(c)
194 t.Run("ToFrom", func(t *testing.T) {
195 testPacketConnConcurrentReadWriteUnicast(t, p, payload, c.LocalAddr(), false)
197 t.Run("Batch", func(t *testing.T) {
198 testPacketConnConcurrentReadWriteUnicast(t, p, payload, c.LocalAddr(), true)
201 t.Run("IP", func(t *testing.T) {
202 switch runtime.GOOS {
204 t.Skip("need to configure gre on netbsd")
206 t.Skip("net.inet.gre.allow=0 by default on openbsd")
209 c, err := net.ListenPacket(fmt.Sprintf("ip6:%d", iana.ProtocolGRE), "::1")
211 t.Skipf("not supported on %s/%s: %v", runtime.GOOS, runtime.GOARCH, err)
214 p := ipv6.NewPacketConn(c)
215 t.Run("ToFrom", func(t *testing.T) {
216 testPacketConnConcurrentReadWriteUnicast(t, p, datagram, c.LocalAddr(), false)
218 t.Run("Batch", func(t *testing.T) {
219 testPacketConnConcurrentReadWriteUnicast(t, p, datagram, c.LocalAddr(), true)
224 func testPacketConnConcurrentReadWriteUnicast(t *testing.T, p *ipv6.PacketConn, data []byte, dst net.Addr, batch bool) {
225 ifi := nettest.RoutedInterface("ip6", net.FlagUp|net.FlagLoopback)
226 cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagSrc | ipv6.FlagDst | ipv6.FlagInterface | ipv6.FlagPathMTU
228 if err := p.SetControlMessage(cf, true); err != nil { // probe before test
229 if nettest.ProtocolNotSupported(err) {
230 t.Skipf("not supported on %s", runtime.GOOS)
235 var wg sync.WaitGroup
238 b := make([]byte, 128)
239 n, cm, _, err := p.ReadFrom(b)
244 if !bytes.Equal(b[:n], data) {
245 t.Errorf("got %#v; want %#v", b[:n], data)
249 if strings.Contains(s, ",") {
250 t.Errorf("should be space-separated values: %s", s)
254 batchReader := func() {
256 ms := []ipv6.Message{
258 Buffers: [][]byte{make([]byte, 128)},
259 OOB: ipv6.NewControlMessage(cf),
262 n, err := p.ReadBatch(ms, 0)
268 t.Errorf("got %d; want %d", n, len(ms))
271 var cm ipv6.ControlMessage
272 if err := cm.Parse(ms[0].OOB[:ms[0].NN]); err != nil {
276 b := ms[0].Buffers[0][:ms[0].N]
277 if !bytes.Equal(b, data) {
278 t.Errorf("got %#v; want %#v", b, data)
282 if strings.Contains(s, ",") {
283 t.Errorf("should be space-separated values: %s", s)
287 writer := func(toggle bool) {
289 cm := ipv6.ControlMessage{
290 TrafficClass: iana.DiffServAF11 | iana.CongestionExperienced,
292 Src: net.IPv6loopback,
295 cm.IfIndex = ifi.Index
297 if err := p.SetControlMessage(cf, toggle); err != nil {
301 n, err := p.WriteTo(data, &cm, dst)
307 t.Errorf("got %d; want %d", n, len(data))
311 batchWriter := func(toggle bool) {
313 cm := ipv6.ControlMessage{
314 TrafficClass: iana.DiffServAF11 | iana.CongestionExperienced,
316 Src: net.IPv6loopback,
319 cm.IfIndex = ifi.Index
321 if err := p.SetControlMessage(cf, toggle); err != nil {
325 ms := []ipv6.Message{
327 Buffers: [][]byte{data},
332 n, err := p.WriteBatch(ms, 0)
338 t.Errorf("got %d; want %d", n, len(ms))
341 if ms[0].N != len(data) {
342 t.Errorf("got %d; want %d", ms[0].N, len(data))
349 for i := 0; i < N; i++ {
357 for i := 0; i < 2*N; i++ {
359 go batchWriter(i%2 != 0)
365 for i := 0; i < N; i++ {