github.com/vishvananda/netlink@v1.3.0/handle_test.go (about)

     1  // +build linux
     2  
     3  package netlink
     4  
     5  import (
     6  	"crypto/rand"
     7  	"encoding/hex"
     8  	"fmt"
     9  	"io"
    10  	"net"
    11  	"sync"
    12  	"sync/atomic"
    13  	"testing"
    14  	"time"
    15  	"unsafe"
    16  
    17  	"github.com/vishvananda/netlink/nl"
    18  	"github.com/vishvananda/netns"
    19  	"golang.org/x/sys/unix"
    20  )
    21  
    22  func TestHandleCreateClose(t *testing.T) {
    23  	h, err := NewHandle()
    24  	if err != nil {
    25  		t.Fatal(err)
    26  	}
    27  	for _, f := range nl.SupportedNlFamilies {
    28  		sh, ok := h.sockets[f]
    29  		if !ok {
    30  			t.Fatalf("Handle socket(s) for family %d was not created", f)
    31  		}
    32  		if sh.Socket == nil {
    33  			t.Fatalf("Socket for family %d was not created", f)
    34  		}
    35  	}
    36  
    37  	h.Close()
    38  	if h.sockets != nil {
    39  		t.Fatalf("Handle socket(s) were not closed")
    40  	}
    41  }
    42  
    43  func TestHandleCreateNetns(t *testing.T) {
    44  	skipUnlessRoot(t)
    45  
    46  	id := make([]byte, 4)
    47  	if _, err := io.ReadFull(rand.Reader, id); err != nil {
    48  		t.Fatal(err)
    49  	}
    50  	ifName := "dummy-" + hex.EncodeToString(id)
    51  
    52  	// Create an handle on the current netns
    53  	curNs, err := netns.Get()
    54  	if err != nil {
    55  		t.Fatal(err)
    56  	}
    57  	defer curNs.Close()
    58  
    59  	ch, err := NewHandleAt(curNs)
    60  	if err != nil {
    61  		t.Fatal(err)
    62  	}
    63  	defer ch.Close()
    64  
    65  	// Create an handle on a custom netns
    66  	newNs, err := netns.New()
    67  	if err != nil {
    68  		t.Fatal(err)
    69  	}
    70  	defer newNs.Close()
    71  
    72  	nh, err := NewHandleAt(newNs)
    73  	if err != nil {
    74  		t.Fatal(err)
    75  	}
    76  	defer nh.Close()
    77  
    78  	// Create an interface using the current handle
    79  	err = ch.LinkAdd(&Dummy{LinkAttrs{Name: ifName}})
    80  	if err != nil {
    81  		t.Fatal(err)
    82  	}
    83  	l, err := ch.LinkByName(ifName)
    84  	if err != nil {
    85  		t.Fatal(err)
    86  	}
    87  	if l.Type() != "dummy" {
    88  		t.Fatalf("Unexpected link type: %s", l.Type())
    89  	}
    90  
    91  	// Verify the new handle cannot find the interface
    92  	ll, err := nh.LinkByName(ifName)
    93  	if err == nil {
    94  		t.Fatalf("Unexpected link found on netns %s: %v", newNs, ll)
    95  	}
    96  
    97  	// Move the interface to the new netns
    98  	err = ch.LinkSetNsFd(l, int(newNs))
    99  	if err != nil {
   100  		t.Fatal(err)
   101  	}
   102  
   103  	// Verify new netns handle can find the interface while current cannot
   104  	ll, err = nh.LinkByName(ifName)
   105  	if err != nil {
   106  		t.Fatal(err)
   107  	}
   108  	if ll.Type() != "dummy" {
   109  		t.Fatalf("Unexpected link type: %s", ll.Type())
   110  	}
   111  	ll, err = ch.LinkByName(ifName)
   112  	if err == nil {
   113  		t.Fatalf("Unexpected link found on netns %s: %v", curNs, ll)
   114  	}
   115  }
   116  
   117  func TestHandleTimeout(t *testing.T) {
   118  	h, err := NewHandle()
   119  	if err != nil {
   120  		t.Fatal(err)
   121  	}
   122  	defer h.Close()
   123  
   124  	for _, sh := range h.sockets {
   125  		verifySockTimeVal(t, sh.Socket.GetFd(), unix.Timeval{Sec: 0, Usec: 0})
   126  	}
   127  
   128  	h.SetSocketTimeout(2*time.Second + 8*time.Millisecond)
   129  
   130  	for _, sh := range h.sockets {
   131  		verifySockTimeVal(t, sh.Socket.GetFd(), unix.Timeval{Sec: 2, Usec: 8000})
   132  	}
   133  }
   134  
   135  func TestHandleReceiveBuffer(t *testing.T) {
   136  	h, err := NewHandle()
   137  	if err != nil {
   138  		t.Fatal(err)
   139  	}
   140  	defer h.Close()
   141  	if err := h.SetSocketReceiveBufferSize(65536, false); err != nil {
   142  		t.Fatal(err)
   143  	}
   144  	sizes, err := h.GetSocketReceiveBufferSize()
   145  	if err != nil {
   146  		t.Fatal(err)
   147  	}
   148  	if len(sizes) != len(h.sockets) {
   149  		t.Fatalf("Unexpected number of socket buffer sizes: %d (expected %d)",
   150  			len(sizes), len(h.sockets))
   151  	}
   152  	for _, s := range sizes {
   153  		if s < 65536 || s > 2*65536 {
   154  			t.Fatalf("Unexpected socket receive buffer size: %d (expected around %d)",
   155  				s, 65536)
   156  		}
   157  	}
   158  }
   159  
   160  func verifySockTimeVal(t *testing.T, fd int, tv unix.Timeval) {
   161  	var (
   162  		tr unix.Timeval
   163  		v  = uint32(0x10)
   164  	)
   165  	_, _, errno := unix.Syscall6(unix.SYS_GETSOCKOPT, uintptr(fd), unix.SOL_SOCKET, unix.SO_SNDTIMEO, uintptr(unsafe.Pointer(&tr)), uintptr(unsafe.Pointer(&v)), 0)
   166  	if errno != 0 {
   167  		t.Fatal(errno)
   168  	}
   169  
   170  	if tr.Sec != tv.Sec || tr.Usec != tv.Usec {
   171  		t.Fatalf("Unexpected timeout value read: %v. Expected: %v", tr, tv)
   172  	}
   173  
   174  	_, _, errno = unix.Syscall6(unix.SYS_GETSOCKOPT, uintptr(fd), unix.SOL_SOCKET, unix.SO_RCVTIMEO, uintptr(unsafe.Pointer(&tr)), uintptr(unsafe.Pointer(&v)), 0)
   175  	if errno != 0 {
   176  		t.Fatal(errno)
   177  	}
   178  
   179  	if tr.Sec != tv.Sec || tr.Usec != tv.Usec {
   180  		t.Fatalf("Unexpected timeout value read: %v. Expected: %v", tr, tv)
   181  	}
   182  }
   183  
   184  var (
   185  	iter      = 10
   186  	numThread = uint32(4)
   187  	prefix    = "iface"
   188  	handle1   *Handle
   189  	handle2   *Handle
   190  	ns1       netns.NsHandle
   191  	ns2       netns.NsHandle
   192  	done      uint32
   193  	initError error
   194  	once      sync.Once
   195  )
   196  
   197  func getXfrmState(thread int) *XfrmState {
   198  	return &XfrmState{
   199  		Src:   net.IPv4(byte(192), byte(168), 1, byte(1+thread)),
   200  		Dst:   net.IPv4(byte(192), byte(168), 2, byte(1+thread)),
   201  		Proto: XFRM_PROTO_AH,
   202  		Mode:  XFRM_MODE_TUNNEL,
   203  		Spi:   thread,
   204  		Auth: &XfrmStateAlgo{
   205  			Name: "hmac(sha256)",
   206  			Key:  []byte("abcdefghijklmnopqrstuvwzyzABCDEF"),
   207  		},
   208  	}
   209  }
   210  
   211  func getXfrmPolicy(thread int) *XfrmPolicy {
   212  	return &XfrmPolicy{
   213  		Src:     &net.IPNet{IP: net.IPv4(byte(10), byte(10), byte(thread), 0), Mask: []byte{255, 255, 255, 0}},
   214  		Dst:     &net.IPNet{IP: net.IPv4(byte(10), byte(10), byte(thread), 0), Mask: []byte{255, 255, 255, 0}},
   215  		Proto:   17,
   216  		DstPort: 1234,
   217  		SrcPort: 5678,
   218  		Dir:     XFRM_DIR_OUT,
   219  		Tmpls: []XfrmPolicyTmpl{
   220  			{
   221  				Src:   net.IPv4(byte(192), byte(168), 1, byte(thread)),
   222  				Dst:   net.IPv4(byte(192), byte(168), 2, byte(thread)),
   223  				Proto: XFRM_PROTO_ESP,
   224  				Mode:  XFRM_MODE_TUNNEL,
   225  			},
   226  		},
   227  	}
   228  }
   229  func initParallel() {
   230  	ns1, initError = netns.New()
   231  	if initError != nil {
   232  		return
   233  	}
   234  	handle1, initError = NewHandleAt(ns1)
   235  	if initError != nil {
   236  		return
   237  	}
   238  	ns2, initError = netns.New()
   239  	if initError != nil {
   240  		return
   241  	}
   242  	handle2, initError = NewHandleAt(ns2)
   243  	if initError != nil {
   244  		return
   245  	}
   246  }
   247  
   248  func parallelDone() {
   249  	atomic.AddUint32(&done, 1)
   250  	if done == numThread {
   251  		if ns1.IsOpen() {
   252  			ns1.Close()
   253  		}
   254  		if ns2.IsOpen() {
   255  			ns2.Close()
   256  		}
   257  		if handle1 != nil {
   258  			handle1.Close()
   259  		}
   260  		if handle2 != nil {
   261  			handle2.Close()
   262  		}
   263  	}
   264  }
   265  
   266  // Do few route and xfrm operation on the two handles in parallel
   267  func runParallelTests(t *testing.T, thread int) {
   268  	skipUnlessRoot(t)
   269  	defer parallelDone()
   270  
   271  	t.Parallel()
   272  
   273  	once.Do(initParallel)
   274  	if initError != nil {
   275  		t.Fatal(initError)
   276  	}
   277  
   278  	state := getXfrmState(thread)
   279  	policy := getXfrmPolicy(thread)
   280  	for i := 0; i < iter; i++ {
   281  		ifName := fmt.Sprintf("%s_%d_%d", prefix, thread, i)
   282  		link := &Dummy{LinkAttrs{Name: ifName}}
   283  		err := handle1.LinkAdd(link)
   284  		if err != nil {
   285  			t.Fatal(err)
   286  		}
   287  		l, err := handle1.LinkByName(ifName)
   288  		if err != nil {
   289  			t.Fatal(err)
   290  		}
   291  		err = handle1.LinkSetUp(l)
   292  		if err != nil {
   293  			t.Fatal(err)
   294  		}
   295  		handle1.LinkSetNsFd(l, int(ns2))
   296  		if err != nil {
   297  			t.Fatal(err)
   298  		}
   299  		err = handle1.XfrmStateAdd(state)
   300  		if err != nil {
   301  			t.Fatal(err)
   302  		}
   303  		err = handle1.XfrmPolicyAdd(policy)
   304  		if err != nil {
   305  			t.Fatal(err)
   306  		}
   307  		err = handle2.LinkSetDown(l)
   308  		if err != nil {
   309  			t.Fatal(err)
   310  		}
   311  		err = handle2.XfrmStateAdd(state)
   312  		if err != nil {
   313  			t.Fatal(err)
   314  		}
   315  		err = handle2.XfrmPolicyAdd(policy)
   316  		if err != nil {
   317  			t.Fatal(err)
   318  		}
   319  		_, err = handle2.LinkByName(ifName)
   320  		if err != nil {
   321  			t.Fatal(err)
   322  		}
   323  		handle2.LinkSetNsFd(l, int(ns1))
   324  		if err != nil {
   325  			t.Fatal(err)
   326  		}
   327  		err = handle1.LinkSetUp(l)
   328  		if err != nil {
   329  			t.Fatal(err)
   330  		}
   331  		_, err = handle1.LinkByName(ifName)
   332  		if err != nil {
   333  			t.Fatal(err)
   334  		}
   335  		err = handle1.XfrmPolicyDel(policy)
   336  		if err != nil {
   337  			t.Fatal(err)
   338  		}
   339  		err = handle2.XfrmPolicyDel(policy)
   340  		if err != nil {
   341  			t.Fatal(err)
   342  		}
   343  		err = handle1.XfrmStateDel(state)
   344  		if err != nil {
   345  			t.Fatal(err)
   346  		}
   347  		err = handle2.XfrmStateDel(state)
   348  		if err != nil {
   349  			t.Fatal(err)
   350  		}
   351  	}
   352  }
   353  
   354  func TestHandleParallel1(t *testing.T) {
   355  	runParallelTests(t, 1)
   356  }
   357  
   358  func TestHandleParallel2(t *testing.T) {
   359  	runParallelTests(t, 2)
   360  }
   361  
   362  func TestHandleParallel3(t *testing.T) {
   363  	runParallelTests(t, 3)
   364  }
   365  
   366  func TestHandleParallel4(t *testing.T) {
   367  	runParallelTests(t, 4)
   368  }