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  }