Fix the dependency issue (#231)

This commit is contained in:
Robbie Zhang
2018-06-21 12:09:42 -07:00
committed by GitHub
parent 027b76651d
commit 6ec1098bb8
16629 changed files with 74837 additions and 4975021 deletions

View File

@@ -1,8 +0,0 @@
language: go
before_script:
# make sure we keep path in tact when we sudo
- sudo sed -i -e 's/^Defaults\tsecure_path.*$//' /etc/sudoers
# modprobe ip_gre or else the first gre device can't be deleted
- sudo modprobe ip_gre
install:
- go get github.com/vishvananda/netns

View File

@@ -1,29 +0,0 @@
DIRS := \
. \
nl
DEPS = \
github.com/vishvananda/netns
uniq = $(if $1,$(firstword $1) $(call uniq,$(filter-out $(firstword $1),$1)))
testdirs = $(call uniq,$(foreach d,$(1),$(dir $(wildcard $(d)/*_test.go))))
goroot = $(addprefix ../../../,$(1))
unroot = $(subst ../../../,,$(1))
fmt = $(addprefix fmt-,$(1))
all: test
$(call goroot,$(DEPS)):
go get $(call unroot,$@)
.PHONY: $(call testdirs,$(DIRS))
$(call testdirs,$(DIRS)):
sudo -E go test -test.parallel 4 -timeout 60s -v github.com/vishvananda/netlink/$@
$(call fmt,$(call testdirs,$(DIRS))):
! gofmt -l $(subst fmt-,,$@)/*.go | grep ''
.PHONY: fmt
fmt: $(call fmt,$(call testdirs,$(DIRS)))
test: fmt $(call goroot,$(DEPS)) $(call testdirs,$(DIRS))

View File

@@ -1,89 +0,0 @@
# netlink - netlink library for go #
[![Build Status](https://travis-ci.org/vishvananda/netlink.png?branch=master)](https://travis-ci.org/vishvananda/netlink) [![GoDoc](https://godoc.org/github.com/vishvananda/netlink?status.svg)](https://godoc.org/github.com/vishvananda/netlink)
The netlink package provides a simple netlink library for go. Netlink
is the interface a user-space program in linux uses to communicate with
the kernel. It can be used to add and remove interfaces, set ip addresses
and routes, and configure ipsec. Netlink communication requires elevated
privileges, so in most cases this code needs to be run as root. Since
low-level netlink messages are inscrutable at best, the library attempts
to provide an api that is loosely modeled on the CLI provided by iproute2.
Actions like `ip link add` will be accomplished via a similarly named
function like AddLink(). This library began its life as a fork of the
netlink functionality in
[docker/libcontainer](https://github.com/docker/libcontainer) but was
heavily rewritten to improve testability, performance, and to add new
functionality like ipsec xfrm handling.
## Local Build and Test ##
You can use go get command:
go get github.com/vishvananda/netlink
Testing dependencies:
go get github.com/vishvananda/netns
Testing (requires root):
sudo -E go test github.com/vishvananda/netlink
## Examples ##
Add a new bridge and add eth1 into it:
```go
package main
import (
"net"
"github.com/vishvananda/netlink"
)
func main() {
la := netlink.NewLinkAttrs()
la.Name = "foo"
mybridge := &netlink.Bridge{la}}
_ := netlink.LinkAdd(mybridge)
eth1, _ := netlink.LinkByName("eth1")
netlink.LinkSetMaster(eth1, mybridge)
}
```
Note `NewLinkAttrs` constructor, it sets default values in structure. For now
it sets only `TxQLen` to `-1`, so kernel will set default by itself. If you're
using simple initialization(`LinkAttrs{Name: "foo"}`) `TxQLen` will be set to
`0` unless you specify it like `LinkAttrs{Name: "foo", TxQLen: 1000}`.
Add a new ip address to loopback:
```go
package main
import (
"net"
"github.com/vishvananda/netlink"
)
func main() {
lo, _ := netlink.LinkByName("lo")
addr, _ := netlink.ParseAddr("169.254.169.254/32")
netlink.AddrAdd(lo, addr)
}
```
## Future Work ##
Many pieces of netlink are not yet fully supported in the high-level
interface. Aspects of virtually all of the high-level objects don't exist.
Many of the underlying primitives are there, so its a matter of putting
the right fields into the high-level objects and making sure that they
are serialized and deserialized correctly in the Add and List methods.
There are also a few pieces of low level netlink functionality that still
need to be implemented. Routing rules are not in place and some of the
more advanced link types. Hopefully there is decent structure and testing
in place to make these fairly straightforward to add.

View File

@@ -1,112 +0,0 @@
package netlink
import (
"net"
"os"
"syscall"
"testing"
)
func TestAddr(t *testing.T) {
if os.Getenv("TRAVIS_BUILD_DIR") != "" {
t.Skipf("Fails in travis with: addr_test.go:68: Address flags not set properly, got=0, expected=128")
}
// TODO: IFA_F_PERMANENT does not seem to be set by default on older kernels?
var address = &net.IPNet{IP: net.IPv4(127, 0, 0, 2), Mask: net.CIDRMask(24, 32)}
var addrTests = []struct {
addr *Addr
expected *Addr
}{
{
&Addr{IPNet: address},
&Addr{IPNet: address, Label: "lo", Scope: syscall.RT_SCOPE_UNIVERSE, Flags: syscall.IFA_F_PERMANENT},
},
{
&Addr{IPNet: address, Label: "local"},
&Addr{IPNet: address, Label: "local", Scope: syscall.RT_SCOPE_UNIVERSE, Flags: syscall.IFA_F_PERMANENT},
},
{
&Addr{IPNet: address, Flags: syscall.IFA_F_OPTIMISTIC},
&Addr{IPNet: address, Label: "lo", Flags: syscall.IFA_F_OPTIMISTIC | syscall.IFA_F_PERMANENT, Scope: syscall.RT_SCOPE_UNIVERSE},
},
{
&Addr{IPNet: address, Flags: syscall.IFA_F_OPTIMISTIC | syscall.IFA_F_DADFAILED},
&Addr{IPNet: address, Label: "lo", Flags: syscall.IFA_F_OPTIMISTIC | syscall.IFA_F_DADFAILED | syscall.IFA_F_PERMANENT, Scope: syscall.RT_SCOPE_UNIVERSE},
},
{
&Addr{IPNet: address, Scope: syscall.RT_SCOPE_NOWHERE},
&Addr{IPNet: address, Label: "lo", Flags: syscall.IFA_F_PERMANENT, Scope: syscall.RT_SCOPE_NOWHERE},
},
}
tearDown := setUpNetlinkTest(t)
defer tearDown()
link, err := LinkByName("lo")
if err != nil {
t.Fatal(err)
}
for _, tt := range addrTests {
if err = AddrAdd(link, tt.addr); err != nil {
t.Fatal(err)
}
addrs, err := AddrList(link, FAMILY_ALL)
if err != nil {
t.Fatal(err)
}
if len(addrs) != 1 {
t.Fatal("Address not added properly")
}
if !addrs[0].Equal(*tt.expected) {
t.Fatalf("Address ip no set properly, got=%s, expected=%s", addrs[0], tt.expected)
}
if addrs[0].Label != tt.expected.Label {
t.Fatalf("Address label not set properly, got=%s, expected=%s", addrs[0].Label, tt.expected.Label)
}
if addrs[0].Flags != tt.expected.Flags {
t.Fatalf("Address flags not set properly, got=%d, expected=%d", addrs[0].Flags, tt.expected.Flags)
}
if addrs[0].Scope != tt.expected.Scope {
t.Fatalf("Address scope not set properly, got=%d, expected=%d", addrs[0].Scope, tt.expected.Scope)
}
// Pass FAMILY_V4, we should get the same results as FAMILY_ALL
addrs, err = AddrList(link, FAMILY_V4)
if err != nil {
t.Fatal(err)
}
if len(addrs) != 1 {
t.Fatal("Address not added properly")
}
// Pass a wrong family number, we should get nil list
addrs, err = AddrList(link, 0x8)
if err != nil {
t.Fatal(err)
}
if len(addrs) != 0 {
t.Fatal("Address not expected")
}
if err = AddrDel(link, tt.addr); err != nil {
t.Fatal(err)
}
addrs, err = AddrList(link, FAMILY_ALL)
if err != nil {
t.Fatal(err)
}
if len(addrs) != 0 {
t.Fatal("Address not removed properly")
}
}
}

View File

@@ -1,406 +0,0 @@
package netlink
import (
"testing"
)
func TestClassAddDel(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
t.Fatal(err)
}
if err := LinkAdd(&Ifb{LinkAttrs{Name: "bar"}}); err != nil {
t.Fatal(err)
}
link, err := LinkByName("foo")
if err != nil {
t.Fatal(err)
}
if err := LinkSetUp(link); err != nil {
t.Fatal(err)
}
attrs := QdiscAttrs{
LinkIndex: link.Attrs().Index,
Handle: MakeHandle(0xffff, 0),
Parent: HANDLE_ROOT,
}
qdisc := NewHtb(attrs)
if err := QdiscAdd(qdisc); err != nil {
t.Fatal(err)
}
qdiscs, err := QdiscList(link)
if err != nil {
t.Fatal(err)
}
if len(qdiscs) != 1 {
t.Fatal("Failed to add qdisc")
}
_, ok := qdiscs[0].(*Htb)
if !ok {
t.Fatal("Qdisc is the wrong type")
}
classattrs := ClassAttrs{
LinkIndex: link.Attrs().Index,
Parent: MakeHandle(0xffff, 0),
Handle: MakeHandle(0xffff, 2),
}
htbclassattrs := HtbClassAttrs{
Rate: 1234000,
Cbuffer: 1690,
}
class := NewHtbClass(classattrs, htbclassattrs)
if err := ClassAdd(class); err != nil {
t.Fatal(err)
}
classes, err := ClassList(link, MakeHandle(0xffff, 0))
if err != nil {
t.Fatal(err)
}
if len(classes) != 1 {
t.Fatal("Failed to add class")
}
htb, ok := classes[0].(*HtbClass)
if !ok {
t.Fatal("Class is the wrong type")
}
if htb.Rate != class.Rate {
t.Fatal("Rate doesn't match")
}
if htb.Ceil != class.Ceil {
t.Fatal("Ceil doesn't match")
}
if htb.Buffer != class.Buffer {
t.Fatal("Buffer doesn't match")
}
if htb.Cbuffer != class.Cbuffer {
t.Fatal("Cbuffer doesn't match")
}
qattrs := QdiscAttrs{
LinkIndex: link.Attrs().Index,
Handle: MakeHandle(0x2, 0),
Parent: MakeHandle(0xffff, 2),
}
nattrs := NetemQdiscAttrs{
Latency: 20000,
Loss: 23.4,
Duplicate: 14.3,
LossCorr: 8.34,
Jitter: 1000,
DelayCorr: 12.3,
ReorderProb: 23.4,
CorruptProb: 10.0,
CorruptCorr: 10,
}
qdiscnetem := NewNetem(qattrs, nattrs)
if err := QdiscAdd(qdiscnetem); err != nil {
t.Fatal(err)
}
qdiscs, err = QdiscList(link)
if err != nil {
t.Fatal(err)
}
if len(qdiscs) != 2 {
t.Fatal("Failed to add qdisc")
}
_, ok = qdiscs[0].(*Htb)
if !ok {
t.Fatal("Qdisc is the wrong type")
}
netem, ok := qdiscs[1].(*Netem)
if !ok {
t.Fatal("Qdisc is the wrong type")
}
// Compare the record we got from the list with the one we created
if netem.Loss != qdiscnetem.Loss {
t.Fatal("Loss does not match")
}
if netem.Latency != qdiscnetem.Latency {
t.Fatal("Latency does not match")
}
if netem.CorruptProb != qdiscnetem.CorruptProb {
t.Fatal("CorruptProb does not match")
}
if netem.Jitter != qdiscnetem.Jitter {
t.Fatal("Jitter does not match")
}
if netem.LossCorr != qdiscnetem.LossCorr {
t.Fatal("Loss does not match")
}
if netem.DuplicateCorr != qdiscnetem.DuplicateCorr {
t.Fatal("DuplicateCorr does not match")
}
// Deletion
if err := ClassDel(class); err != nil {
t.Fatal(err)
}
classes, err = ClassList(link, MakeHandle(0xffff, 0))
if err != nil {
t.Fatal(err)
}
if len(classes) != 0 {
t.Fatal("Failed to remove class")
}
if err := QdiscDel(qdisc); err != nil {
t.Fatal(err)
}
qdiscs, err = QdiscList(link)
if err != nil {
t.Fatal(err)
}
if len(qdiscs) != 0 {
t.Fatal("Failed to remove qdisc")
}
}
func TestHtbClassAddHtbClassChangeDel(t *testing.T) {
/**
This test first set up a interface ans set up a Htb qdisc
A HTB class is attach to it and a Netem qdisc is attached to that class
Next, we test changing the HTB class in place and confirming the Netem is
still attached. We also check that invoting ClassChange with a non-existing
class will fail.
Finally, we test ClassReplace. We confirm it correctly behave like
ClassChange when the parent/handle pair exists and that it will create a
new class if the handle is modified.
*/
tearDown := setUpNetlinkTest(t)
defer tearDown()
if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
t.Fatal(err)
}
link, err := LinkByName("foo")
if err != nil {
t.Fatal(err)
}
if err := LinkSetUp(link); err != nil {
t.Fatal(err)
}
attrs := QdiscAttrs{
LinkIndex: link.Attrs().Index,
Handle: MakeHandle(0xffff, 0),
Parent: HANDLE_ROOT,
}
qdisc := NewHtb(attrs)
if err := QdiscAdd(qdisc); err != nil {
t.Fatal(err)
}
qdiscs, err := QdiscList(link)
if err != nil {
t.Fatal(err)
}
if len(qdiscs) != 1 {
t.Fatal("Failed to add qdisc")
}
_, ok := qdiscs[0].(*Htb)
if !ok {
t.Fatal("Qdisc is the wrong type")
}
classattrs := ClassAttrs{
LinkIndex: link.Attrs().Index,
Parent: MakeHandle(0xffff, 0),
Handle: MakeHandle(0xffff, 2),
}
htbclassattrs := HtbClassAttrs{
Rate: 1234000,
Cbuffer: 1690,
}
class := NewHtbClass(classattrs, htbclassattrs)
if err := ClassAdd(class); err != nil {
t.Fatal(err)
}
classes, err := ClassList(link, 0)
if err != nil {
t.Fatal(err)
}
if len(classes) != 1 {
t.Fatal("Failed to add class")
}
htb, ok := classes[0].(*HtbClass)
if !ok {
t.Fatal("Class is the wrong type")
}
qattrs := QdiscAttrs{
LinkIndex: link.Attrs().Index,
Handle: MakeHandle(0x2, 0),
Parent: MakeHandle(0xffff, 2),
}
nattrs := NetemQdiscAttrs{
Latency: 20000,
Loss: 23.4,
Duplicate: 14.3,
LossCorr: 8.34,
Jitter: 1000,
DelayCorr: 12.3,
ReorderProb: 23.4,
CorruptProb: 10.0,
CorruptCorr: 10,
}
qdiscnetem := NewNetem(qattrs, nattrs)
if err := QdiscAdd(qdiscnetem); err != nil {
t.Fatal(err)
}
qdiscs, err = QdiscList(link)
if err != nil {
t.Fatal(err)
}
if len(qdiscs) != 2 {
t.Fatal("Failed to add qdisc")
}
_, ok = qdiscs[1].(*Netem)
if !ok {
t.Fatal("Qdisc is the wrong type")
}
// Change
// For change to work, the handle and parent cannot be changed.
// First, test it fails if we change the Handle.
oldHandle := classattrs.Handle
classattrs.Handle = MakeHandle(0xffff, 3)
class = NewHtbClass(classattrs, htbclassattrs)
if err := ClassChange(class); err == nil {
t.Fatal("ClassChange should not work when using a different handle.")
}
// It should work with the same handle
classattrs.Handle = oldHandle
htbclassattrs.Rate = 4321000
class = NewHtbClass(classattrs, htbclassattrs)
if err := ClassChange(class); err != nil {
t.Fatal(err)
}
classes, err = ClassList(link, MakeHandle(0xffff, 0))
if err != nil {
t.Fatal(err)
}
if len(classes) != 1 {
t.Fatalf(
"1 class expected, %d found",
len(classes),
)
}
htb, ok = classes[0].(*HtbClass)
if !ok {
t.Fatal("Class is the wrong type")
}
// Verify that the rate value has changed.
if htb.Rate != class.Rate {
t.Fatal("Rate did not get changed while changing the class.")
}
// Check that we still have the netem child qdisc
qdiscs, err = QdiscList(link)
if err != nil {
t.Fatal(err)
}
if len(qdiscs) != 2 {
t.Fatalf("2 qdisc expected, %d found", len(qdiscs))
}
_, ok = qdiscs[0].(*Htb)
if !ok {
t.Fatal("Qdisc is the wrong type")
}
_, ok = qdiscs[1].(*Netem)
if !ok {
t.Fatal("Qdisc is the wrong type")
}
// Replace
// First replace by keeping the same handle, class will be changed.
// Then, replace by providing a new handle, n new class will be created.
// Replace acting as Change
class = NewHtbClass(classattrs, htbclassattrs)
if err := ClassReplace(class); err != nil {
t.Fatal("Failed to replace class that is existing.")
}
classes, err = ClassList(link, MakeHandle(0xffff, 0))
if err != nil {
t.Fatal(err)
}
if len(classes) != 1 {
t.Fatalf(
"1 class expected, %d found",
len(classes),
)
}
htb, ok = classes[0].(*HtbClass)
if !ok {
t.Fatal("Class is the wrong type")
}
// Verify that the rate value has changed.
if htb.Rate != class.Rate {
t.Fatal("Rate did not get changed while changing the class.")
}
// It should work with the same handle
classattrs.Handle = MakeHandle(0xffff, 3)
class = NewHtbClass(classattrs, htbclassattrs)
if err := ClassReplace(class); err != nil {
t.Fatal(err)
}
classes, err = ClassList(link, MakeHandle(0xffff, 0))
if err != nil {
t.Fatal(err)
}
if len(classes) != 2 {
t.Fatalf(
"2 classes expected, %d found",
len(classes),
)
}
htb, ok = classes[1].(*HtbClass)
if !ok {
t.Fatal("Class is the wrong type")
}
// Verify that the rate value has changed.
if htb.Rate != class.Rate {
t.Fatal("Rate did not get changed while changing the class.")
}
// Deletion
for _, class := range classes {
if err := ClassDel(class); err != nil {
t.Fatal(err)
}
}
classes, err = ClassList(link, MakeHandle(0xffff, 0))
if err != nil {
t.Fatal(err)
}
if len(classes) != 0 {
t.Fatal("Failed to remove class")
}
if err := QdiscDel(qdisc); err != nil {
t.Fatal(err)
}
qdiscs, err = QdiscList(link)
if err != nil {
t.Fatal(err)
}
if len(qdiscs) != 0 {
t.Fatal("Failed to remove qdisc")
}
}

View File

@@ -1,472 +0,0 @@
package netlink
import (
"syscall"
"testing"
)
func TestFilterAddDel(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
t.Fatal(err)
}
if err := LinkAdd(&Ifb{LinkAttrs{Name: "bar"}}); err != nil {
t.Fatal(err)
}
link, err := LinkByName("foo")
if err != nil {
t.Fatal(err)
}
if err := LinkSetUp(link); err != nil {
t.Fatal(err)
}
redir, err := LinkByName("bar")
if err != nil {
t.Fatal(err)
}
if err := LinkSetUp(redir); err != nil {
t.Fatal(err)
}
qdisc := &Ingress{
QdiscAttrs: QdiscAttrs{
LinkIndex: link.Attrs().Index,
Handle: MakeHandle(0xffff, 0),
Parent: HANDLE_INGRESS,
},
}
if err := QdiscAdd(qdisc); err != nil {
t.Fatal(err)
}
qdiscs, err := QdiscList(link)
if err != nil {
t.Fatal(err)
}
if len(qdiscs) != 1 {
t.Fatal("Failed to add qdisc")
}
_, ok := qdiscs[0].(*Ingress)
if !ok {
t.Fatal("Qdisc is the wrong type")
}
filter := &U32{
FilterAttrs: FilterAttrs{
LinkIndex: link.Attrs().Index,
Parent: MakeHandle(0xffff, 0),
Priority: 1,
Protocol: syscall.ETH_P_IP,
},
RedirIndex: redir.Attrs().Index,
}
if err := FilterAdd(filter); err != nil {
t.Fatal(err)
}
filters, err := FilterList(link, MakeHandle(0xffff, 0))
if err != nil {
t.Fatal(err)
}
if len(filters) != 1 {
t.Fatal("Failed to add filter")
}
if err := FilterDel(filter); err != nil {
t.Fatal(err)
}
filters, err = FilterList(link, MakeHandle(0xffff, 0))
if err != nil {
t.Fatal(err)
}
if len(filters) != 0 {
t.Fatal("Failed to remove filter")
}
if err := QdiscDel(qdisc); err != nil {
t.Fatal(err)
}
qdiscs, err = QdiscList(link)
if err != nil {
t.Fatal(err)
}
if len(qdiscs) != 0 {
t.Fatal("Failed to remove qdisc")
}
}
func TestFilterFwAddDel(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
t.Fatal(err)
}
if err := LinkAdd(&Ifb{LinkAttrs{Name: "bar"}}); err != nil {
t.Fatal(err)
}
link, err := LinkByName("foo")
if err != nil {
t.Fatal(err)
}
if err := LinkSetUp(link); err != nil {
t.Fatal(err)
}
redir, err := LinkByName("bar")
if err != nil {
t.Fatal(err)
}
if err := LinkSetUp(redir); err != nil {
t.Fatal(err)
}
attrs := QdiscAttrs{
LinkIndex: link.Attrs().Index,
Handle: MakeHandle(0xffff, 0),
Parent: HANDLE_ROOT,
}
qdisc := NewHtb(attrs)
if err := QdiscAdd(qdisc); err != nil {
t.Fatal(err)
}
qdiscs, err := QdiscList(link)
if err != nil {
t.Fatal(err)
}
if len(qdiscs) != 1 {
t.Fatal("Failed to add qdisc")
}
_, ok := qdiscs[0].(*Htb)
if !ok {
t.Fatal("Qdisc is the wrong type")
}
classattrs := ClassAttrs{
LinkIndex: link.Attrs().Index,
Parent: MakeHandle(0xffff, 0),
Handle: MakeHandle(0xffff, 2),
}
htbclassattrs := HtbClassAttrs{
Rate: 1234000,
Cbuffer: 1690,
}
class := NewHtbClass(classattrs, htbclassattrs)
if err := ClassAdd(class); err != nil {
t.Fatal(err)
}
classes, err := ClassList(link, MakeHandle(0xffff, 2))
if err != nil {
t.Fatal(err)
}
if len(classes) != 1 {
t.Fatal("Failed to add class")
}
filterattrs := FilterAttrs{
LinkIndex: link.Attrs().Index,
Parent: MakeHandle(0xffff, 0),
Handle: MakeHandle(0, 0x6),
Priority: 1,
Protocol: syscall.ETH_P_IP,
}
fwattrs := FilterFwAttrs{
Buffer: 12345,
Rate: 1234,
PeakRate: 2345,
Action: TC_POLICE_SHOT,
ClassId: MakeHandle(0xffff, 2),
}
filter, err := NewFw(filterattrs, fwattrs)
if err != nil {
t.Fatal(err)
}
if err := FilterAdd(filter); err != nil {
t.Fatal(err)
}
filters, err := FilterList(link, MakeHandle(0xffff, 0))
if err != nil {
t.Fatal(err)
}
if len(filters) != 1 {
t.Fatal("Failed to add filter")
}
fw, ok := filters[0].(*Fw)
if !ok {
t.Fatal("Filter is the wrong type")
}
if fw.Police.Rate.Rate != filter.Police.Rate.Rate {
t.Fatal("Police Rate doesn't match")
}
for i := range fw.Rtab {
if fw.Rtab[i] != filter.Rtab[i] {
t.Fatal("Rtab doesn't match")
}
if fw.Ptab[i] != filter.Ptab[i] {
t.Fatal("Ptab doesn't match")
}
}
if fw.ClassId != filter.ClassId {
t.Fatal("ClassId doesn't match")
}
if fw.InDev != filter.InDev {
t.Fatal("InDev doesn't match")
}
if fw.AvRate != filter.AvRate {
t.Fatal("AvRate doesn't match")
}
if err := FilterDel(filter); err != nil {
t.Fatal(err)
}
filters, err = FilterList(link, MakeHandle(0xffff, 0))
if err != nil {
t.Fatal(err)
}
if len(filters) != 0 {
t.Fatal("Failed to remove filter")
}
if err := ClassDel(class); err != nil {
t.Fatal(err)
}
classes, err = ClassList(link, MakeHandle(0xffff, 0))
if err != nil {
t.Fatal(err)
}
if len(classes) != 0 {
t.Fatal("Failed to remove class")
}
if err := QdiscDel(qdisc); err != nil {
t.Fatal(err)
}
qdiscs, err = QdiscList(link)
if err != nil {
t.Fatal(err)
}
if len(qdiscs) != 0 {
t.Fatal("Failed to remove qdisc")
}
}
func TestFilterU32BpfAddDel(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
t.Fatal(err)
}
if err := LinkAdd(&Ifb{LinkAttrs{Name: "bar"}}); err != nil {
t.Fatal(err)
}
link, err := LinkByName("foo")
if err != nil {
t.Fatal(err)
}
if err := LinkSetUp(link); err != nil {
t.Fatal(err)
}
redir, err := LinkByName("bar")
if err != nil {
t.Fatal(err)
}
if err := LinkSetUp(redir); err != nil {
t.Fatal(err)
}
qdisc := &Ingress{
QdiscAttrs: QdiscAttrs{
LinkIndex: link.Attrs().Index,
Handle: MakeHandle(0xffff, 0),
Parent: HANDLE_INGRESS,
},
}
if err := QdiscAdd(qdisc); err != nil {
t.Fatal(err)
}
qdiscs, err := QdiscList(link)
if err != nil {
t.Fatal(err)
}
if len(qdiscs) != 1 {
t.Fatal("Failed to add qdisc")
}
_, ok := qdiscs[0].(*Ingress)
if !ok {
t.Fatal("Qdisc is the wrong type")
}
fd, err := loadSimpleBpf(BPF_PROG_TYPE_SCHED_ACT, 1)
if err != nil {
t.Skipf("Loading bpf program failed: %s", err)
}
filter := &U32{
FilterAttrs: FilterAttrs{
LinkIndex: link.Attrs().Index,
Parent: MakeHandle(0xffff, 0),
Priority: 1,
Protocol: syscall.ETH_P_ALL,
},
ClassId: MakeHandle(1, 1),
Actions: []Action{
&BpfAction{Fd: fd, Name: "simple"},
&MirredAction{
ActionAttrs: ActionAttrs{
Action: TC_ACT_STOLEN,
},
MirredAction: TCA_EGRESS_REDIR,
Ifindex: redir.Attrs().Index,
},
},
}
if err := FilterAdd(filter); err != nil {
t.Fatal(err)
}
filters, err := FilterList(link, MakeHandle(0xffff, 0))
if err != nil {
t.Fatal(err)
}
if len(filters) != 1 {
t.Fatal("Failed to add filter")
}
u32, ok := filters[0].(*U32)
if !ok {
t.Fatal("Filter is the wrong type")
}
if len(u32.Actions) != 2 {
t.Fatalf("Too few Actions in filter")
}
bpfAction, ok := u32.Actions[0].(*BpfAction)
if !ok {
t.Fatal("Action[0] is the wrong type")
}
if bpfAction.Fd != fd {
t.Fatal("Action Fd does not match")
}
if _, ok := u32.Actions[1].(*MirredAction); !ok {
t.Fatal("Action[1] is the wrong type")
}
if err := FilterDel(filter); err != nil {
t.Fatal(err)
}
filters, err = FilterList(link, MakeHandle(0xffff, 0))
if err != nil {
t.Fatal(err)
}
if len(filters) != 0 {
t.Fatal("Failed to remove filter")
}
if err := QdiscDel(qdisc); err != nil {
t.Fatal(err)
}
qdiscs, err = QdiscList(link)
if err != nil {
t.Fatal(err)
}
if len(qdiscs) != 0 {
t.Fatal("Failed to remove qdisc")
}
}
func TestFilterClsActBpfAddDel(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
t.Fatal(err)
}
link, err := LinkByName("foo")
if err != nil {
t.Fatal(err)
}
if err := LinkSetUp(link); err != nil {
t.Fatal(err)
}
attrs := QdiscAttrs{
LinkIndex: link.Attrs().Index,
Handle: MakeHandle(0xffff, 0),
Parent: HANDLE_CLSACT,
}
qdisc := &GenericQdisc{
QdiscAttrs: attrs,
QdiscType: "clsact",
}
// This feature was added in kernel 4.5
if err := QdiscAdd(qdisc); err != nil {
t.Skipf("Failed adding clsact qdisc, unsupported kernel")
}
qdiscs, err := QdiscList(link)
if err != nil {
t.Fatal(err)
}
if len(qdiscs) != 1 {
t.Fatal("Failed to add qdisc")
}
if q, ok := qdiscs[0].(*GenericQdisc); !ok || q.Type() != "clsact" {
t.Fatal("qdisc is the wrong type")
}
filterattrs := FilterAttrs{
LinkIndex: link.Attrs().Index,
Parent: HANDLE_MIN_EGRESS,
Handle: MakeHandle(0, 1),
Protocol: syscall.ETH_P_ALL,
Priority: 1,
}
fd, err := loadSimpleBpf(BPF_PROG_TYPE_SCHED_CLS, 1)
if err != nil {
t.Skipf("Loading bpf program failed: %s", err)
}
filter := &BpfFilter{
FilterAttrs: filterattrs,
Fd: fd,
Name: "simple",
DirectAction: true,
}
if filter.Fd < 0 {
t.Skipf("Failed to load bpf program")
}
if err := FilterAdd(filter); err != nil {
t.Fatal(err)
}
filters, err := FilterList(link, HANDLE_MIN_EGRESS)
if err != nil {
t.Fatal(err)
}
if len(filters) != 1 {
t.Fatal("Failed to add filter")
}
bpf, ok := filters[0].(*BpfFilter)
if !ok {
t.Fatal("Filter is the wrong type")
}
if bpf.Fd != filter.Fd {
t.Fatal("Filter Fd does not match")
}
if bpf.DirectAction != filter.DirectAction {
t.Fatal("Filter DirectAction does not match")
}
if err := FilterDel(filter); err != nil {
t.Fatal(err)
}
filters, err = FilterList(link, HANDLE_MIN_EGRESS)
if err != nil {
t.Fatal(err)
}
if len(filters) != 0 {
t.Fatal("Failed to remove filter")
}
if err := QdiscDel(qdisc); err != nil {
t.Fatal(err)
}
qdiscs, err = QdiscList(link)
if err != nil {
t.Fatal(err)
}
if len(qdiscs) != 0 {
t.Fatal("Failed to remove qdisc")
}
}

View File

@@ -1,338 +0,0 @@
package netlink
import (
"crypto/rand"
"encoding/hex"
"fmt"
"io"
"net"
"sync"
"sync/atomic"
"syscall"
"testing"
"time"
"unsafe"
"github.com/vishvananda/netlink/nl"
"github.com/vishvananda/netns"
)
func TestHandleCreateDelete(t *testing.T) {
h, err := NewHandle()
if err != nil {
t.Fatal(err)
}
for _, f := range nl.SupportedNlFamilies {
sh, ok := h.sockets[f]
if !ok {
t.Fatalf("Handle socket(s) for family %d was not created", f)
}
if sh.Socket == nil {
t.Fatalf("Socket for family %d was not created", f)
}
}
h.Delete()
if h.sockets != nil {
t.Fatalf("Handle socket(s) were not destroyed")
}
}
func TestHandleCreateNetns(t *testing.T) {
id := make([]byte, 4)
if _, err := io.ReadFull(rand.Reader, id); err != nil {
t.Fatal(err)
}
ifName := "dummy-" + hex.EncodeToString(id)
// Create an handle on the current netns
curNs, err := netns.Get()
if err != nil {
t.Fatal(err)
}
defer curNs.Close()
ch, err := NewHandleAt(curNs)
if err != nil {
t.Fatal(err)
}
defer ch.Delete()
// Create an handle on a custom netns
newNs, err := netns.New()
if err != nil {
t.Fatal(err)
}
defer newNs.Close()
nh, err := NewHandleAt(newNs)
if err != nil {
t.Fatal(err)
}
defer nh.Delete()
// Create an interface using the current handle
err = ch.LinkAdd(&Dummy{LinkAttrs{Name: ifName}})
if err != nil {
t.Fatal(err)
}
l, err := ch.LinkByName(ifName)
if err != nil {
t.Fatal(err)
}
if l.Type() != "dummy" {
t.Fatalf("Unexpected link type: %s", l.Type())
}
// Verify the new handle cannot find the interface
ll, err := nh.LinkByName(ifName)
if err == nil {
t.Fatalf("Unexpected link found on netns %s: %v", newNs, ll)
}
// Move the interface to the new netns
err = ch.LinkSetNsFd(l, int(newNs))
if err != nil {
t.Fatal(err)
}
// Verify new netns handle can find the interface while current cannot
ll, err = nh.LinkByName(ifName)
if err != nil {
t.Fatal(err)
}
if ll.Type() != "dummy" {
t.Fatalf("Unexpected link type: %s", ll.Type())
}
ll, err = ch.LinkByName(ifName)
if err == nil {
t.Fatalf("Unexpected link found on netns %s: %v", curNs, ll)
}
}
func TestHandleTimeout(t *testing.T) {
h, err := NewHandle()
if err != nil {
t.Fatal(err)
}
defer h.Delete()
for _, sh := range h.sockets {
verifySockTimeVal(t, sh.Socket.GetFd(), syscall.Timeval{Sec: 0, Usec: 0})
}
h.SetSocketTimeout(2*time.Second + 8*time.Millisecond)
for _, sh := range h.sockets {
verifySockTimeVal(t, sh.Socket.GetFd(), syscall.Timeval{Sec: 2, Usec: 8000})
}
}
func verifySockTimeVal(t *testing.T, fd int, tv syscall.Timeval) {
var (
tr syscall.Timeval
v = uint32(0x10)
)
_, _, errno := syscall.Syscall6(syscall.SYS_GETSOCKOPT, uintptr(fd), syscall.SOL_SOCKET, syscall.SO_SNDTIMEO, uintptr(unsafe.Pointer(&tr)), uintptr(unsafe.Pointer(&v)), 0)
if errno != 0 {
t.Fatal(errno)
}
if tr.Sec != tv.Sec || tr.Usec != tv.Usec {
t.Fatalf("Unexpected timeout value read: %v. Expected: %v", tr, tv)
}
_, _, errno = syscall.Syscall6(syscall.SYS_GETSOCKOPT, uintptr(fd), syscall.SOL_SOCKET, syscall.SO_RCVTIMEO, uintptr(unsafe.Pointer(&tr)), uintptr(unsafe.Pointer(&v)), 0)
if errno != 0 {
t.Fatal(errno)
}
if tr.Sec != tv.Sec || tr.Usec != tv.Usec {
t.Fatalf("Unexpected timeout value read: %v. Expected: %v", tr, tv)
}
}
var (
iter = 10
numThread = uint32(4)
prefix = "iface"
handle1 *Handle
handle2 *Handle
ns1 netns.NsHandle
ns2 netns.NsHandle
done uint32
initError error
once sync.Once
)
func getXfrmState(thread int) *XfrmState {
return &XfrmState{
Src: net.IPv4(byte(192), byte(168), 1, byte(1+thread)),
Dst: net.IPv4(byte(192), byte(168), 2, byte(1+thread)),
Proto: XFRM_PROTO_AH,
Mode: XFRM_MODE_TUNNEL,
Spi: thread,
Auth: &XfrmStateAlgo{
Name: "hmac(sha256)",
Key: []byte("abcdefghijklmnopqrstuvwzyzABCDEF"),
},
}
}
func getXfrmPolicy(thread int) *XfrmPolicy {
return &XfrmPolicy{
Src: &net.IPNet{IP: net.IPv4(byte(10), byte(10), byte(thread), 0), Mask: []byte{255, 255, 255, 0}},
Dst: &net.IPNet{IP: net.IPv4(byte(10), byte(10), byte(thread), 0), Mask: []byte{255, 255, 255, 0}},
Proto: 17,
DstPort: 1234,
SrcPort: 5678,
Dir: XFRM_DIR_OUT,
Tmpls: []XfrmPolicyTmpl{
{
Src: net.IPv4(byte(192), byte(168), 1, byte(thread)),
Dst: net.IPv4(byte(192), byte(168), 2, byte(thread)),
Proto: XFRM_PROTO_ESP,
Mode: XFRM_MODE_TUNNEL,
},
},
}
}
func initParallel() {
ns1, initError = netns.New()
if initError != nil {
return
}
handle1, initError = NewHandleAt(ns1)
if initError != nil {
return
}
ns2, initError = netns.New()
if initError != nil {
return
}
handle2, initError = NewHandleAt(ns2)
if initError != nil {
return
}
}
func parallelDone() {
atomic.AddUint32(&done, 1)
if done == numThread {
if ns1.IsOpen() {
ns1.Close()
}
if ns2.IsOpen() {
ns2.Close()
}
if handle1 != nil {
handle1.Delete()
}
if handle2 != nil {
handle2.Delete()
}
}
}
// Do few route and xfrm operation on the two handles in parallel
func runParallelTests(t *testing.T, thread int) {
defer parallelDone()
t.Parallel()
once.Do(initParallel)
if initError != nil {
t.Fatal(initError)
}
state := getXfrmState(thread)
policy := getXfrmPolicy(thread)
for i := 0; i < iter; i++ {
ifName := fmt.Sprintf("%s_%d_%d", prefix, thread, i)
link := &Dummy{LinkAttrs{Name: ifName}}
err := handle1.LinkAdd(link)
if err != nil {
t.Fatal(err)
}
l, err := handle1.LinkByName(ifName)
if err != nil {
t.Fatal(err)
}
err = handle1.LinkSetUp(l)
if err != nil {
t.Fatal(err)
}
handle1.LinkSetNsFd(l, int(ns2))
if err != nil {
t.Fatal(err)
}
err = handle1.XfrmStateAdd(state)
if err != nil {
t.Fatal(err)
}
err = handle1.XfrmPolicyAdd(policy)
if err != nil {
t.Fatal(err)
}
err = handle2.LinkSetDown(l)
if err != nil {
t.Fatal(err)
}
err = handle2.XfrmStateAdd(state)
if err != nil {
t.Fatal(err)
}
err = handle2.XfrmPolicyAdd(policy)
if err != nil {
t.Fatal(err)
}
_, err = handle2.LinkByName(ifName)
if err != nil {
t.Fatal(err)
}
handle2.LinkSetNsFd(l, int(ns1))
if err != nil {
t.Fatal(err)
}
err = handle1.LinkSetUp(l)
if err != nil {
t.Fatal(err)
}
l, err = handle1.LinkByName(ifName)
if err != nil {
t.Fatal(err)
}
err = handle1.XfrmPolicyDel(policy)
if err != nil {
t.Fatal(err)
}
err = handle2.XfrmPolicyDel(policy)
if err != nil {
t.Fatal(err)
}
err = handle1.XfrmStateDel(state)
if err != nil {
t.Fatal(err)
}
err = handle2.XfrmStateDel(state)
if err != nil {
t.Fatal(err)
}
}
}
func TestHandleParallel1(t *testing.T) {
runParallelTests(t, 1)
}
func TestHandleParallel2(t *testing.T) {
runParallelTests(t, 2)
}
func TestHandleParallel3(t *testing.T) {
runParallelTests(t, 3)
}
func TestHandleParallel4(t *testing.T) {
runParallelTests(t, 4)
}

View File

@@ -1,971 +0,0 @@
package netlink
import (
"bytes"
"net"
"os"
"syscall"
"testing"
"time"
"github.com/vishvananda/netns"
)
const (
testTxQLen int = 100
defaultTxQLen int = 1000
)
func testLinkAddDel(t *testing.T, link Link) {
links, err := LinkList()
if err != nil {
t.Fatal(err)
}
num := len(links)
if err := LinkAdd(link); err != nil {
t.Fatal(err)
}
base := link.Attrs()
result, err := LinkByName(base.Name)
if err != nil {
t.Fatal(err)
}
rBase := result.Attrs()
if vlan, ok := link.(*Vlan); ok {
other, ok := result.(*Vlan)
if !ok {
t.Fatal("Result of create is not a vlan")
}
if vlan.VlanId != other.VlanId {
t.Fatal("Link.VlanId id doesn't match")
}
}
if veth, ok := result.(*Veth); ok {
if rBase.TxQLen != base.TxQLen {
t.Fatalf("qlen is %d, should be %d", rBase.TxQLen, base.TxQLen)
}
if rBase.MTU != base.MTU {
t.Fatalf("MTU is %d, should be %d", rBase.MTU, base.MTU)
}
if original, ok := link.(*Veth); ok {
if original.PeerName != "" {
var peer *Veth
other, err := LinkByName(original.PeerName)
if err != nil {
t.Fatalf("Peer %s not created", veth.PeerName)
}
if peer, ok = other.(*Veth); !ok {
t.Fatalf("Peer %s is incorrect type", veth.PeerName)
}
if peer.TxQLen != testTxQLen {
t.Fatalf("TxQLen of peer is %d, should be %d", peer.TxQLen, testTxQLen)
}
}
}
} else {
// recent kernels set the parent index for veths in the response
if rBase.ParentIndex == 0 && base.ParentIndex != 0 {
t.Fatalf("Created link doesn't have parent %d but it should", base.ParentIndex)
} else if rBase.ParentIndex != 0 && base.ParentIndex == 0 {
t.Fatalf("Created link has parent %d but it shouldn't", rBase.ParentIndex)
} else if rBase.ParentIndex != 0 && base.ParentIndex != 0 {
if rBase.ParentIndex != base.ParentIndex {
t.Fatalf("Link.ParentIndex doesn't match %d != %d", rBase.ParentIndex, base.ParentIndex)
}
}
}
if vxlan, ok := link.(*Vxlan); ok {
other, ok := result.(*Vxlan)
if !ok {
t.Fatal("Result of create is not a vxlan")
}
compareVxlan(t, vxlan, other)
}
if ipv, ok := link.(*IPVlan); ok {
other, ok := result.(*IPVlan)
if !ok {
t.Fatal("Result of create is not a ipvlan")
}
if ipv.Mode != other.Mode {
t.Fatalf("Got unexpected mode: %d, expected: %d", other.Mode, ipv.Mode)
}
}
if macv, ok := link.(*Macvlan); ok {
other, ok := result.(*Macvlan)
if !ok {
t.Fatal("Result of create is not a macvlan")
}
if macv.Mode != other.Mode {
t.Fatalf("Got unexpected mode: %d, expected: %d", other.Mode, macv.Mode)
}
}
if macv, ok := link.(*Macvtap); ok {
other, ok := result.(*Macvtap)
if !ok {
t.Fatal("Result of create is not a macvtap")
}
if macv.Mode != other.Mode {
t.Fatalf("Got unexpected mode: %d, expected: %d", other.Mode, macv.Mode)
}
}
if err = LinkDel(link); err != nil {
t.Fatal(err)
}
links, err = LinkList()
if err != nil {
t.Fatal(err)
}
if len(links) != num {
t.Fatal("Link not removed properly")
return
}
}
func compareVxlan(t *testing.T, expected, actual *Vxlan) {
if actual.VxlanId != expected.VxlanId {
t.Fatal("Vxlan.VxlanId doesn't match")
}
if expected.SrcAddr != nil && !actual.SrcAddr.Equal(expected.SrcAddr) {
t.Fatal("Vxlan.SrcAddr doesn't match")
}
if expected.Group != nil && !actual.Group.Equal(expected.Group) {
t.Fatal("Vxlan.Group doesn't match")
}
if expected.TTL != -1 && actual.TTL != expected.TTL {
t.Fatal("Vxlan.TTL doesn't match")
}
if expected.TOS != -1 && actual.TOS != expected.TOS {
t.Fatal("Vxlan.TOS doesn't match")
}
if actual.Learning != expected.Learning {
t.Fatal("Vxlan.Learning doesn't match")
}
if actual.Proxy != expected.Proxy {
t.Fatal("Vxlan.Proxy doesn't match")
}
if actual.RSC != expected.RSC {
t.Fatal("Vxlan.RSC doesn't match")
}
if actual.L2miss != expected.L2miss {
t.Fatal("Vxlan.L2miss doesn't match")
}
if actual.L3miss != expected.L3miss {
t.Fatal("Vxlan.L3miss doesn't match")
}
if actual.GBP != expected.GBP {
t.Fatal("Vxlan.GBP doesn't match")
}
if expected.NoAge {
if !actual.NoAge {
t.Fatal("Vxlan.NoAge doesn't match")
}
} else if expected.Age > 0 && actual.Age != expected.Age {
t.Fatal("Vxlan.Age doesn't match")
}
if expected.Limit > 0 && actual.Limit != expected.Limit {
t.Fatal("Vxlan.Limit doesn't match")
}
if expected.Port > 0 && actual.Port != expected.Port {
t.Fatal("Vxlan.Port doesn't match")
}
if expected.PortLow > 0 || expected.PortHigh > 0 {
if actual.PortLow != expected.PortLow {
t.Fatal("Vxlan.PortLow doesn't match")
}
if actual.PortHigh != expected.PortHigh {
t.Fatal("Vxlan.PortHigh doesn't match")
}
}
}
func TestLinkAddDelDummy(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
testLinkAddDel(t, &Dummy{LinkAttrs{Name: "foo"}})
}
func TestLinkAddDelIfb(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
testLinkAddDel(t, &Ifb{LinkAttrs{Name: "foo"}})
}
func TestLinkAddDelBridge(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
testLinkAddDel(t, &Bridge{LinkAttrs{Name: "foo", MTU: 1400}})
}
func TestLinkAddDelGretap(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
testLinkAddDel(t, &Gretap{
LinkAttrs: LinkAttrs{Name: "foo"},
IKey: 0x101,
OKey: 0x101,
PMtuDisc: 1,
Local: net.IPv4(127, 0, 0, 1),
Remote: net.IPv4(127, 0, 0, 1)})
}
func TestLinkAddDelVlan(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
parent := &Dummy{LinkAttrs{Name: "foo"}}
if err := LinkAdd(parent); err != nil {
t.Fatal(err)
}
testLinkAddDel(t, &Vlan{LinkAttrs{Name: "bar", ParentIndex: parent.Attrs().Index}, 900})
if err := LinkDel(parent); err != nil {
t.Fatal(err)
}
}
func TestLinkAddDelMacvlan(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
parent := &Dummy{LinkAttrs{Name: "foo"}}
if err := LinkAdd(parent); err != nil {
t.Fatal(err)
}
testLinkAddDel(t, &Macvlan{
LinkAttrs: LinkAttrs{Name: "bar", ParentIndex: parent.Attrs().Index},
Mode: MACVLAN_MODE_PRIVATE,
})
testLinkAddDel(t, &Macvlan{
LinkAttrs: LinkAttrs{Name: "bar", ParentIndex: parent.Attrs().Index},
Mode: MACVLAN_MODE_BRIDGE,
})
testLinkAddDel(t, &Macvlan{
LinkAttrs: LinkAttrs{Name: "bar", ParentIndex: parent.Attrs().Index},
Mode: MACVLAN_MODE_VEPA,
})
if err := LinkDel(parent); err != nil {
t.Fatal(err)
}
}
func TestLinkAddDelMacvtap(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
parent := &Dummy{LinkAttrs{Name: "foo"}}
if err := LinkAdd(parent); err != nil {
t.Fatal(err)
}
testLinkAddDel(t, &Macvtap{
Macvlan: Macvlan{
LinkAttrs: LinkAttrs{Name: "bar", ParentIndex: parent.Attrs().Index},
Mode: MACVLAN_MODE_PRIVATE,
},
})
testLinkAddDel(t, &Macvtap{
Macvlan: Macvlan{
LinkAttrs: LinkAttrs{Name: "bar", ParentIndex: parent.Attrs().Index},
Mode: MACVLAN_MODE_BRIDGE,
},
})
testLinkAddDel(t, &Macvtap{
Macvlan: Macvlan{
LinkAttrs: LinkAttrs{Name: "bar", ParentIndex: parent.Attrs().Index},
Mode: MACVLAN_MODE_VEPA,
},
})
if err := LinkDel(parent); err != nil {
t.Fatal(err)
}
}
func TestLinkAddDelVeth(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
veth := &Veth{LinkAttrs: LinkAttrs{Name: "foo", TxQLen: testTxQLen, MTU: 1400}, PeerName: "bar"}
testLinkAddDel(t, veth)
}
func TestLinkAddDelBond(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
testLinkAddDel(t, NewLinkBond(LinkAttrs{Name: "foo"}))
}
func TestLinkAddVethWithDefaultTxQLen(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
la := NewLinkAttrs()
la.Name = "foo"
veth := &Veth{LinkAttrs: la, PeerName: "bar"}
if err := LinkAdd(veth); err != nil {
t.Fatal(err)
}
link, err := LinkByName("foo")
if err != nil {
t.Fatal(err)
}
if veth, ok := link.(*Veth); !ok {
t.Fatalf("unexpected link type: %T", link)
} else {
if veth.TxQLen != defaultTxQLen {
t.Fatalf("TxQLen is %d, should be %d", veth.TxQLen, defaultTxQLen)
}
}
peer, err := LinkByName("bar")
if err != nil {
t.Fatal(err)
}
if veth, ok := peer.(*Veth); !ok {
t.Fatalf("unexpected link type: %T", link)
} else {
if veth.TxQLen != defaultTxQLen {
t.Fatalf("TxQLen is %d, should be %d", veth.TxQLen, defaultTxQLen)
}
}
}
func TestLinkAddVethWithZeroTxQLen(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
la := NewLinkAttrs()
la.Name = "foo"
la.TxQLen = 0
veth := &Veth{LinkAttrs: la, PeerName: "bar"}
if err := LinkAdd(veth); err != nil {
t.Fatal(err)
}
link, err := LinkByName("foo")
if err != nil {
t.Fatal(err)
}
if veth, ok := link.(*Veth); !ok {
t.Fatalf("unexpected link type: %T", link)
} else {
if veth.TxQLen != 0 {
t.Fatalf("TxQLen is %d, should be %d", veth.TxQLen, 0)
}
}
peer, err := LinkByName("bar")
if err != nil {
t.Fatal(err)
}
if veth, ok := peer.(*Veth); !ok {
t.Fatalf("unexpected link type: %T", link)
} else {
if veth.TxQLen != 0 {
t.Fatalf("TxQLen is %d, should be %d", veth.TxQLen, 0)
}
}
}
func TestLinkAddDummyWithTxQLen(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
la := NewLinkAttrs()
la.Name = "foo"
la.TxQLen = 1500
dummy := &Dummy{LinkAttrs: la}
if err := LinkAdd(dummy); err != nil {
t.Fatal(err)
}
link, err := LinkByName("foo")
if err != nil {
t.Fatal(err)
}
if dummy, ok := link.(*Dummy); !ok {
t.Fatalf("unexpected link type: %T", link)
} else {
if dummy.TxQLen != 1500 {
t.Fatalf("TxQLen is %d, should be %d", dummy.TxQLen, 1500)
}
}
}
func TestLinkAddDelBridgeMaster(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
master := &Bridge{LinkAttrs{Name: "foo"}}
if err := LinkAdd(master); err != nil {
t.Fatal(err)
}
testLinkAddDel(t, &Dummy{LinkAttrs{Name: "bar", MasterIndex: master.Attrs().Index}})
if err := LinkDel(master); err != nil {
t.Fatal(err)
}
}
func TestLinkSetUnsetResetMaster(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
master := &Bridge{LinkAttrs{Name: "foo"}}
if err := LinkAdd(master); err != nil {
t.Fatal(err)
}
newmaster := &Bridge{LinkAttrs{Name: "bar"}}
if err := LinkAdd(newmaster); err != nil {
t.Fatal(err)
}
slave := &Dummy{LinkAttrs{Name: "baz"}}
if err := LinkAdd(slave); err != nil {
t.Fatal(err)
}
nonexistsmaster := &Bridge{LinkAttrs{Name: "foobar"}}
if err := LinkSetMaster(slave, nonexistsmaster); err == nil {
t.Fatal("error expected")
}
if err := LinkSetMaster(slave, master); err != nil {
t.Fatal(err)
}
link, err := LinkByName("baz")
if err != nil {
t.Fatal(err)
}
if link.Attrs().MasterIndex != master.Attrs().Index {
t.Fatal("Master not set properly")
}
if err := LinkSetMaster(slave, newmaster); err != nil {
t.Fatal(err)
}
link, err = LinkByName("baz")
if err != nil {
t.Fatal(err)
}
if link.Attrs().MasterIndex != newmaster.Attrs().Index {
t.Fatal("Master not reset properly")
}
if err := LinkSetNoMaster(slave); err != nil {
t.Fatal(err)
}
link, err = LinkByName("baz")
if err != nil {
t.Fatal(err)
}
if link.Attrs().MasterIndex != 0 {
t.Fatal("Master not unset properly")
}
if err := LinkDel(slave); err != nil {
t.Fatal(err)
}
if err := LinkDel(newmaster); err != nil {
t.Fatal(err)
}
if err := LinkDel(master); err != nil {
t.Fatal(err)
}
}
func TestLinkSetNs(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
basens, err := netns.Get()
if err != nil {
t.Fatal("Failed to get basens")
}
defer basens.Close()
newns, err := netns.New()
if err != nil {
t.Fatal("Failed to create newns")
}
defer newns.Close()
link := &Veth{LinkAttrs{Name: "foo"}, "bar"}
if err := LinkAdd(link); err != nil {
t.Fatal(err)
}
peer, err := LinkByName("bar")
if err != nil {
t.Fatal(err)
}
LinkSetNsFd(peer, int(basens))
if err != nil {
t.Fatal("Failed to set newns for link")
}
_, err = LinkByName("bar")
if err == nil {
t.Fatal("Link bar is still in newns")
}
err = netns.Set(basens)
if err != nil {
t.Fatal("Failed to set basens")
}
peer, err = LinkByName("bar")
if err != nil {
t.Fatal("Link is not in basens")
}
if err := LinkDel(peer); err != nil {
t.Fatal(err)
}
err = netns.Set(newns)
if err != nil {
t.Fatal("Failed to set newns")
}
_, err = LinkByName("foo")
if err == nil {
t.Fatal("Other half of veth pair not deleted")
}
}
func TestLinkAddDelVxlan(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
parent := &Dummy{
LinkAttrs{Name: "foo"},
}
if err := LinkAdd(parent); err != nil {
t.Fatal(err)
}
vxlan := Vxlan{
LinkAttrs: LinkAttrs{
Name: "bar",
},
VxlanId: 10,
VtepDevIndex: parent.Index,
Learning: true,
L2miss: true,
L3miss: true,
}
testLinkAddDel(t, &vxlan)
if err := LinkDel(parent); err != nil {
t.Fatal(err)
}
}
func TestLinkAddDelVxlanGbp(t *testing.T) {
if os.Getenv("TRAVIS_BUILD_DIR") != "" {
t.Skipf("Kernel in travis is too old for this test")
}
tearDown := setUpNetlinkTest(t)
defer tearDown()
parent := &Dummy{
LinkAttrs{Name: "foo"},
}
if err := LinkAdd(parent); err != nil {
t.Fatal(err)
}
vxlan := Vxlan{
LinkAttrs: LinkAttrs{
Name: "bar",
},
VxlanId: 10,
VtepDevIndex: parent.Index,
Learning: true,
L2miss: true,
L3miss: true,
GBP: true,
}
testLinkAddDel(t, &vxlan)
if err := LinkDel(parent); err != nil {
t.Fatal(err)
}
}
func TestLinkAddDelIPVlanL2(t *testing.T) {
if os.Getenv("TRAVIS_BUILD_DIR") != "" {
t.Skipf("Kernel in travis is too old for this test")
}
tearDown := setUpNetlinkTest(t)
defer tearDown()
parent := &Dummy{LinkAttrs{Name: "foo"}}
if err := LinkAdd(parent); err != nil {
t.Fatal(err)
}
ipv := IPVlan{
LinkAttrs: LinkAttrs{
Name: "bar",
ParentIndex: parent.Index,
},
Mode: IPVLAN_MODE_L2,
}
testLinkAddDel(t, &ipv)
}
func TestLinkAddDelIPVlanL3(t *testing.T) {
if os.Getenv("TRAVIS_BUILD_DIR") != "" {
t.Skipf("Kernel in travis is too old for this test")
}
tearDown := setUpNetlinkTest(t)
defer tearDown()
parent := &Dummy{LinkAttrs{Name: "foo"}}
if err := LinkAdd(parent); err != nil {
t.Fatal(err)
}
ipv := IPVlan{
LinkAttrs: LinkAttrs{
Name: "bar",
ParentIndex: parent.Index,
},
Mode: IPVLAN_MODE_L3,
}
testLinkAddDel(t, &ipv)
}
func TestLinkAddDelIPVlanNoParent(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
ipv := IPVlan{
LinkAttrs: LinkAttrs{
Name: "bar",
},
Mode: IPVLAN_MODE_L3,
}
err := LinkAdd(&ipv)
if err == nil {
t.Fatal("Add should fail if ipvlan creating without ParentIndex")
}
if err.Error() != "Can't create ipvlan link without ParentIndex" {
t.Fatalf("Error should be about missing ParentIndex, got %q", err)
}
}
func TestLinkByIndex(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
dummy := &Dummy{LinkAttrs{Name: "dummy"}}
if err := LinkAdd(dummy); err != nil {
t.Fatal(err)
}
found, err := LinkByIndex(dummy.Index)
if err != nil {
t.Fatal(err)
}
if found.Attrs().Index != dummy.Attrs().Index {
t.Fatalf("Indices don't match: %v != %v", found.Attrs().Index, dummy.Attrs().Index)
}
LinkDel(dummy)
// test not found
_, err = LinkByIndex(dummy.Attrs().Index)
if err == nil {
t.Fatalf("LinkByIndex(%v) found deleted link", err)
}
}
func TestLinkSet(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
iface := &Dummy{LinkAttrs{Name: "foo"}}
if err := LinkAdd(iface); err != nil {
t.Fatal(err)
}
link, err := LinkByName("foo")
if err != nil {
t.Fatal(err)
}
err = LinkSetName(link, "bar")
if err != nil {
t.Fatalf("Could not change interface name: %v", err)
}
link, err = LinkByName("bar")
if err != nil {
t.Fatalf("Interface name not changed: %v", err)
}
err = LinkSetMTU(link, 1400)
if err != nil {
t.Fatalf("Could not set MTU: %v", err)
}
link, err = LinkByName("bar")
if err != nil {
t.Fatal(err)
}
if link.Attrs().MTU != 1400 {
t.Fatal("MTU not changed!")
}
addr, err := net.ParseMAC("00:12:34:56:78:AB")
if err != nil {
t.Fatal(err)
}
err = LinkSetHardwareAddr(link, addr)
if err != nil {
t.Fatal(err)
}
link, err = LinkByName("bar")
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(link.Attrs().HardwareAddr, addr) {
t.Fatalf("hardware address not changed!")
}
err = LinkSetAlias(link, "barAlias")
if err != nil {
t.Fatalf("Could not set alias: %v", err)
}
link, err = LinkByName("bar")
if err != nil {
t.Fatal(err)
}
if link.Attrs().Alias != "barAlias" {
t.Fatalf("alias not changed!")
}
link, err = LinkByAlias("barAlias")
if err != nil {
t.Fatal(err)
}
}
func expectLinkUpdate(ch <-chan LinkUpdate, ifaceName string, up bool) bool {
for {
timeout := time.After(time.Minute)
select {
case update := <-ch:
if ifaceName == update.Link.Attrs().Name && (update.IfInfomsg.Flags&syscall.IFF_UP != 0) == up {
return true
}
case <-timeout:
return false
}
}
}
func TestLinkSubscribe(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
ch := make(chan LinkUpdate)
done := make(chan struct{})
defer close(done)
if err := LinkSubscribe(ch, done); err != nil {
t.Fatal(err)
}
link := &Veth{LinkAttrs{Name: "foo", TxQLen: testTxQLen, MTU: 1400}, "bar"}
if err := LinkAdd(link); err != nil {
t.Fatal(err)
}
if !expectLinkUpdate(ch, "foo", false) {
t.Fatal("Add update not received as expected")
}
if err := LinkSetUp(link); err != nil {
t.Fatal(err)
}
if !expectLinkUpdate(ch, "foo", true) {
t.Fatal("Link Up update not received as expected")
}
if err := LinkDel(link); err != nil {
t.Fatal(err)
}
if !expectLinkUpdate(ch, "foo", false) {
t.Fatal("Del update not received as expected")
}
}
func TestLinkSubscribeAt(t *testing.T) {
// Create an handle on a custom netns
newNs, err := netns.New()
if err != nil {
t.Fatal(err)
}
defer newNs.Close()
nh, err := NewHandleAt(newNs)
if err != nil {
t.Fatal(err)
}
defer nh.Delete()
// Subscribe for Link events on the custom netns
ch := make(chan LinkUpdate)
done := make(chan struct{})
defer close(done)
if err := LinkSubscribeAt(newNs, ch, done); err != nil {
t.Fatal(err)
}
link := &Veth{LinkAttrs{Name: "test", TxQLen: testTxQLen, MTU: 1400}, "bar"}
if err := nh.LinkAdd(link); err != nil {
t.Fatal(err)
}
if !expectLinkUpdate(ch, "test", false) {
t.Fatal("Add update not received as expected")
}
if err := nh.LinkSetUp(link); err != nil {
t.Fatal(err)
}
if !expectLinkUpdate(ch, "test", true) {
t.Fatal("Link Up update not received as expected")
}
if err := nh.LinkDel(link); err != nil {
t.Fatal(err)
}
if !expectLinkUpdate(ch, "test", false) {
t.Fatal("Del update not received as expected")
}
}
func TestLinkStats(t *testing.T) {
defer setUpNetlinkTest(t)()
// Create a veth pair and verify the cross-stats once both
// ends are brought up and some ICMPv6 packets are exchanged
v0 := "v0"
v1 := "v1"
vethLink := &Veth{LinkAttrs: LinkAttrs{Name: v0}, PeerName: v1}
if err := LinkAdd(vethLink); err != nil {
t.Fatal(err)
}
veth0, err := LinkByName(v0)
if err != nil {
t.Fatal(err)
}
if err := LinkSetUp(veth0); err != nil {
t.Fatal(err)
}
veth1, err := LinkByName(v1)
if err != nil {
t.Fatal(err)
}
if err := LinkSetUp(veth1); err != nil {
t.Fatal(err)
}
time.Sleep(2 * time.Second)
// verify statistics
veth0, err = LinkByName(v0)
if err != nil {
t.Fatal(err)
}
veth1, err = LinkByName(v1)
if err != nil {
t.Fatal(err)
}
v0Stats := veth0.Attrs().Statistics
v1Stats := veth1.Attrs().Statistics
if v0Stats.RxPackets != v1Stats.TxPackets || v0Stats.TxPackets != v1Stats.RxPackets ||
v0Stats.RxBytes != v1Stats.TxBytes || v0Stats.TxBytes != v1Stats.RxBytes {
t.Fatalf("veth ends counters differ:\n%v\n%v", v0Stats, v1Stats)
}
}
func TestLinkXdp(t *testing.T) {
links, err := LinkList()
if err != nil {
t.Fatal(err)
}
var testXdpLink Link
for _, link := range links {
if link.Attrs().Xdp != nil && !link.Attrs().Xdp.Attached {
testXdpLink = link
break
}
}
if testXdpLink == nil {
t.Skipf("No link supporting XDP found")
}
fd, err := loadSimpleBpf(BPF_PROG_TYPE_XDP, 2 /*XDP_PASS*/)
if err != nil {
t.Skipf("Loading bpf program failed: %s", err)
}
if err := LinkSetXdpFd(testXdpLink, fd); err != nil {
t.Fatal(err)
}
if err := LinkSetXdpFd(testXdpLink, -1); err != nil {
t.Fatal(err)
}
}

View File

@@ -1,192 +0,0 @@
package netlink
import (
"net"
"testing"
)
type arpEntry struct {
ip net.IP
mac net.HardwareAddr
}
type proxyEntry struct {
ip net.IP
dev int
}
func parseMAC(s string) net.HardwareAddr {
m, err := net.ParseMAC(s)
if err != nil {
panic(err)
}
return m
}
func dumpContains(dump []Neigh, e arpEntry) bool {
for _, n := range dump {
if n.IP.Equal(e.ip) && (n.State&NUD_INCOMPLETE) == 0 {
return true
}
}
return false
}
func dumpContainsProxy(dump []Neigh, p proxyEntry) bool {
for _, n := range dump {
if n.IP.Equal(p.ip) && (n.LinkIndex == p.dev) && (n.Flags&NTF_PROXY) == NTF_PROXY {
return true
}
}
return false
}
func TestNeighAddDel(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
dummy := Dummy{LinkAttrs{Name: "neigh0"}}
if err := LinkAdd(&dummy); err != nil {
t.Fatal(err)
}
ensureIndex(dummy.Attrs())
arpTable := []arpEntry{
{net.ParseIP("10.99.0.1"), parseMAC("aa:bb:cc:dd:00:01")},
{net.ParseIP("10.99.0.2"), parseMAC("aa:bb:cc:dd:00:02")},
{net.ParseIP("10.99.0.3"), parseMAC("aa:bb:cc:dd:00:03")},
{net.ParseIP("10.99.0.4"), parseMAC("aa:bb:cc:dd:00:04")},
{net.ParseIP("10.99.0.5"), parseMAC("aa:bb:cc:dd:00:05")},
}
// Add the arpTable
for _, entry := range arpTable {
err := NeighAdd(&Neigh{
LinkIndex: dummy.Index,
State: NUD_REACHABLE,
IP: entry.ip,
HardwareAddr: entry.mac,
})
if err != nil {
t.Errorf("Failed to NeighAdd: %v", err)
}
}
// Dump and see that all added entries are there
dump, err := NeighList(dummy.Index, 0)
if err != nil {
t.Errorf("Failed to NeighList: %v", err)
}
for _, entry := range arpTable {
if !dumpContains(dump, entry) {
t.Errorf("Dump does not contain: %v", entry)
}
}
// Delete the arpTable
for _, entry := range arpTable {
err := NeighDel(&Neigh{
LinkIndex: dummy.Index,
IP: entry.ip,
HardwareAddr: entry.mac,
})
if err != nil {
t.Errorf("Failed to NeighDel: %v", err)
}
}
// TODO: seems not working because of cache
//// Dump and see that none of deleted entries are there
//dump, err = NeighList(dummy.Index, 0)
//if err != nil {
//t.Errorf("Failed to NeighList: %v", err)
//}
//for _, entry := range arpTable {
//if dumpContains(dump, entry) {
//t.Errorf("Dump contains: %v", entry)
//}
//}
if err := LinkDel(&dummy); err != nil {
t.Fatal(err)
}
}
func TestNeighAddDelProxy(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
dummy := Dummy{LinkAttrs{Name: "neigh0"}}
if err := LinkAdd(&dummy); err != nil {
t.Fatal(err)
}
ensureIndex(dummy.Attrs())
proxyTable := []proxyEntry{
{net.ParseIP("10.99.0.1"), dummy.Index},
{net.ParseIP("10.99.0.2"), dummy.Index},
{net.ParseIP("10.99.0.3"), dummy.Index},
{net.ParseIP("10.99.0.4"), dummy.Index},
{net.ParseIP("10.99.0.5"), dummy.Index},
}
// Add the proxyTable
for _, entry := range proxyTable {
err := NeighAdd(&Neigh{
LinkIndex: dummy.Index,
Flags: NTF_PROXY,
IP: entry.ip,
})
if err != nil {
t.Errorf("Failed to NeighAdd: %v", err)
}
}
// Dump and see that all added entries are there
dump, err := NeighProxyList(dummy.Index, 0)
if err != nil {
t.Errorf("Failed to NeighList: %v", err)
}
for _, entry := range proxyTable {
if !dumpContainsProxy(dump, entry) {
t.Errorf("Dump does not contain: %v", entry)
}
}
// Delete the proxyTable
for _, entry := range proxyTable {
err := NeighDel(&Neigh{
LinkIndex: dummy.Index,
Flags: NTF_PROXY,
IP: entry.ip,
})
if err != nil {
t.Errorf("Failed to NeighDel: %v", err)
}
}
// Dump and see that none of deleted entries are there
dump, err = NeighProxyList(dummy.Index, 0)
if err != nil {
t.Errorf("Failed to NeighList: %v", err)
}
for _, entry := range proxyTable {
if dumpContainsProxy(dump, entry) {
t.Errorf("Dump contains: %v", entry)
}
}
if err := LinkDel(&dummy); err != nil {
t.Fatal(err)
}
}

View File

@@ -1,34 +0,0 @@
package netlink
import (
"log"
"os"
"runtime"
"testing"
"github.com/vishvananda/netns"
)
type tearDownNetlinkTest func()
func setUpNetlinkTest(t *testing.T) tearDownNetlinkTest {
if os.Getuid() != 0 {
msg := "Skipped test because it requires root privileges."
log.Printf(msg)
t.Skip(msg)
}
// new temporary namespace so we don't pollute the host
// lock thread since the namespace is thread local
runtime.LockOSThread()
var err error
ns, err := netns.New()
if err != nil {
t.Fatal("Failed to create newns", ns)
}
return func() {
ns.Close()
runtime.UnlockOSThread()
}
}

View File

@@ -1,39 +0,0 @@
package nl
import (
"bytes"
"crypto/rand"
"encoding/binary"
"syscall"
"testing"
)
func (msg *IfAddrmsg) write(b []byte) {
native := NativeEndian()
b[0] = msg.Family
b[1] = msg.Prefixlen
b[2] = msg.Flags
b[3] = msg.Scope
native.PutUint32(b[4:8], msg.Index)
}
func (msg *IfAddrmsg) serializeSafe() []byte {
len := syscall.SizeofIfAddrmsg
b := make([]byte, len)
msg.write(b)
return b
}
func deserializeIfAddrmsgSafe(b []byte) *IfAddrmsg {
var msg = IfAddrmsg{}
binary.Read(bytes.NewReader(b[0:syscall.SizeofIfAddrmsg]), NativeEndian(), &msg)
return &msg
}
func TestIfAddrmsgDeserializeSerialize(t *testing.T) {
var orig = make([]byte, syscall.SizeofIfAddrmsg)
rand.Read(orig)
safemsg := deserializeIfAddrmsgSafe(orig)
msg := DeserializeIfAddrmsg(orig)
testDeserializeSerialize(t, orig, safemsg, msg)
}

View File

@@ -1,199 +0,0 @@
package nl
import (
"bytes"
"crypto/rand"
"encoding/binary"
"testing"
)
func (msg *VfMac) write(b []byte) {
native := NativeEndian()
native.PutUint32(b[0:4], uint32(msg.Vf))
copy(b[4:36], msg.Mac[:])
}
func (msg *VfMac) serializeSafe() []byte {
length := SizeofVfMac
b := make([]byte, length)
msg.write(b)
return b
}
func deserializeVfMacSafe(b []byte) *VfMac {
var msg = VfMac{}
binary.Read(bytes.NewReader(b[0:SizeofVfMac]), NativeEndian(), &msg)
return &msg
}
func TestVfMacDeserializeSerialize(t *testing.T) {
var orig = make([]byte, SizeofVfMac)
rand.Read(orig)
safemsg := deserializeVfMacSafe(orig)
msg := DeserializeVfMac(orig)
testDeserializeSerialize(t, orig, safemsg, msg)
}
func (msg *VfVlan) write(b []byte) {
native := NativeEndian()
native.PutUint32(b[0:4], uint32(msg.Vf))
native.PutUint32(b[4:8], uint32(msg.Vlan))
native.PutUint32(b[8:12], uint32(msg.Qos))
}
func (msg *VfVlan) serializeSafe() []byte {
length := SizeofVfVlan
b := make([]byte, length)
msg.write(b)
return b
}
func deserializeVfVlanSafe(b []byte) *VfVlan {
var msg = VfVlan{}
binary.Read(bytes.NewReader(b[0:SizeofVfVlan]), NativeEndian(), &msg)
return &msg
}
func TestVfVlanDeserializeSerialize(t *testing.T) {
var orig = make([]byte, SizeofVfVlan)
rand.Read(orig)
safemsg := deserializeVfVlanSafe(orig)
msg := DeserializeVfVlan(orig)
testDeserializeSerialize(t, orig, safemsg, msg)
}
func (msg *VfTxRate) write(b []byte) {
native := NativeEndian()
native.PutUint32(b[0:4], uint32(msg.Vf))
native.PutUint32(b[4:8], uint32(msg.Rate))
}
func (msg *VfTxRate) serializeSafe() []byte {
length := SizeofVfTxRate
b := make([]byte, length)
msg.write(b)
return b
}
func deserializeVfTxRateSafe(b []byte) *VfTxRate {
var msg = VfTxRate{}
binary.Read(bytes.NewReader(b[0:SizeofVfTxRate]), NativeEndian(), &msg)
return &msg
}
func TestVfTxRateDeserializeSerialize(t *testing.T) {
var orig = make([]byte, SizeofVfTxRate)
rand.Read(orig)
safemsg := deserializeVfTxRateSafe(orig)
msg := DeserializeVfTxRate(orig)
testDeserializeSerialize(t, orig, safemsg, msg)
}
func (msg *VfRate) write(b []byte) {
native := NativeEndian()
native.PutUint32(b[0:4], uint32(msg.Vf))
native.PutUint32(b[4:8], uint32(msg.MinTxRate))
native.PutUint32(b[8:12], uint32(msg.MaxTxRate))
}
func (msg *VfRate) serializeSafe() []byte {
length := SizeofVfRate
b := make([]byte, length)
msg.write(b)
return b
}
func deserializeVfRateSafe(b []byte) *VfRate {
var msg = VfRate{}
binary.Read(bytes.NewReader(b[0:SizeofVfRate]), NativeEndian(), &msg)
return &msg
}
func TestVfRateDeserializeSerialize(t *testing.T) {
var orig = make([]byte, SizeofVfRate)
rand.Read(orig)
safemsg := deserializeVfRateSafe(orig)
msg := DeserializeVfRate(orig)
testDeserializeSerialize(t, orig, safemsg, msg)
}
func (msg *VfSpoofchk) write(b []byte) {
native := NativeEndian()
native.PutUint32(b[0:4], uint32(msg.Vf))
native.PutUint32(b[4:8], uint32(msg.Setting))
}
func (msg *VfSpoofchk) serializeSafe() []byte {
length := SizeofVfSpoofchk
b := make([]byte, length)
msg.write(b)
return b
}
func deserializeVfSpoofchkSafe(b []byte) *VfSpoofchk {
var msg = VfSpoofchk{}
binary.Read(bytes.NewReader(b[0:SizeofVfSpoofchk]), NativeEndian(), &msg)
return &msg
}
func TestVfSpoofchkDeserializeSerialize(t *testing.T) {
var orig = make([]byte, SizeofVfSpoofchk)
rand.Read(orig)
safemsg := deserializeVfSpoofchkSafe(orig)
msg := DeserializeVfSpoofchk(orig)
testDeserializeSerialize(t, orig, safemsg, msg)
}
func (msg *VfLinkState) write(b []byte) {
native := NativeEndian()
native.PutUint32(b[0:4], uint32(msg.Vf))
native.PutUint32(b[4:8], uint32(msg.LinkState))
}
func (msg *VfLinkState) serializeSafe() []byte {
length := SizeofVfLinkState
b := make([]byte, length)
msg.write(b)
return b
}
func deserializeVfLinkStateSafe(b []byte) *VfLinkState {
var msg = VfLinkState{}
binary.Read(bytes.NewReader(b[0:SizeofVfLinkState]), NativeEndian(), &msg)
return &msg
}
func TestVfLinkStateDeserializeSerialize(t *testing.T) {
var orig = make([]byte, SizeofVfLinkState)
rand.Read(orig)
safemsg := deserializeVfLinkStateSafe(orig)
msg := DeserializeVfLinkState(orig)
testDeserializeSerialize(t, orig, safemsg, msg)
}
func (msg *VfRssQueryEn) write(b []byte) {
native := NativeEndian()
native.PutUint32(b[0:4], uint32(msg.Vf))
native.PutUint32(b[4:8], uint32(msg.Setting))
}
func (msg *VfRssQueryEn) serializeSafe() []byte {
length := SizeofVfRssQueryEn
b := make([]byte, length)
msg.write(b)
return b
}
func deserializeVfRssQueryEnSafe(b []byte) *VfRssQueryEn {
var msg = VfRssQueryEn{}
binary.Read(bytes.NewReader(b[0:SizeofVfRssQueryEn]), NativeEndian(), &msg)
return &msg
}
func TestVfRssQueryEnDeserializeSerialize(t *testing.T) {
var orig = make([]byte, SizeofVfRssQueryEn)
rand.Read(orig)
safemsg := deserializeVfRssQueryEnSafe(orig)
msg := DeserializeVfRssQueryEn(orig)
testDeserializeSerialize(t, orig, safemsg, msg)
}

View File

@@ -1,60 +0,0 @@
package nl
import (
"bytes"
"crypto/rand"
"encoding/binary"
"reflect"
"syscall"
"testing"
)
type testSerializer interface {
serializeSafe() []byte
Serialize() []byte
}
func testDeserializeSerialize(t *testing.T, orig []byte, safemsg testSerializer, msg testSerializer) {
if !reflect.DeepEqual(safemsg, msg) {
t.Fatal("Deserialization failed.\n", safemsg, "\n", msg)
}
safe := msg.serializeSafe()
if !bytes.Equal(safe, orig) {
t.Fatal("Safe serialization failed.\n", safe, "\n", orig)
}
b := msg.Serialize()
if !bytes.Equal(b, safe) {
t.Fatal("Serialization failed.\n", b, "\n", safe)
}
}
func (msg *IfInfomsg) write(b []byte) {
native := NativeEndian()
b[0] = msg.Family
b[1] = msg.X__ifi_pad
native.PutUint16(b[2:4], msg.Type)
native.PutUint32(b[4:8], uint32(msg.Index))
native.PutUint32(b[8:12], msg.Flags)
native.PutUint32(b[12:16], msg.Change)
}
func (msg *IfInfomsg) serializeSafe() []byte {
length := syscall.SizeofIfInfomsg
b := make([]byte, length)
msg.write(b)
return b
}
func deserializeIfInfomsgSafe(b []byte) *IfInfomsg {
var msg = IfInfomsg{}
binary.Read(bytes.NewReader(b[0:syscall.SizeofIfInfomsg]), NativeEndian(), &msg)
return &msg
}
func TestIfInfomsgDeserializeSerialize(t *testing.T) {
var orig = make([]byte, syscall.SizeofIfInfomsg)
rand.Read(orig)
safemsg := deserializeIfInfomsgSafe(orig)
msg := DeserializeIfInfomsg(orig)
testDeserializeSerialize(t, orig, safemsg, msg)
}

View File

@@ -1,43 +0,0 @@
package nl
import (
"bytes"
"crypto/rand"
"encoding/binary"
"syscall"
"testing"
)
func (msg *RtMsg) write(b []byte) {
native := NativeEndian()
b[0] = msg.Family
b[1] = msg.Dst_len
b[2] = msg.Src_len
b[3] = msg.Tos
b[4] = msg.Table
b[5] = msg.Protocol
b[6] = msg.Scope
b[7] = msg.Type
native.PutUint32(b[8:12], msg.Flags)
}
func (msg *RtMsg) serializeSafe() []byte {
len := syscall.SizeofRtMsg
b := make([]byte, len)
msg.write(b)
return b
}
func deserializeRtMsgSafe(b []byte) *RtMsg {
var msg = RtMsg{}
binary.Read(bytes.NewReader(b[0:syscall.SizeofRtMsg]), NativeEndian(), &msg)
return &msg
}
func TestRtMsgDeserializeSerialize(t *testing.T) {
var orig = make([]byte, syscall.SizeofRtMsg)
rand.Read(orig)
safemsg := deserializeRtMsgSafe(orig)
msg := DeserializeRtMsg(orig)
testDeserializeSerialize(t, orig, safemsg, msg)
}

View File

@@ -1,173 +0,0 @@
package nl
import (
"bytes"
"crypto/rand"
"encoding/binary"
"testing"
)
/* TcMsg */
func (msg *TcMsg) write(b []byte) {
native := NativeEndian()
b[0] = msg.Family
copy(b[1:4], msg.Pad[:])
native.PutUint32(b[4:8], uint32(msg.Ifindex))
native.PutUint32(b[8:12], msg.Handle)
native.PutUint32(b[12:16], msg.Parent)
native.PutUint32(b[16:20], msg.Info)
}
func (msg *TcMsg) serializeSafe() []byte {
length := SizeofTcMsg
b := make([]byte, length)
msg.write(b)
return b
}
func deserializeTcMsgSafe(b []byte) *TcMsg {
var msg = TcMsg{}
binary.Read(bytes.NewReader(b[0:SizeofTcMsg]), NativeEndian(), &msg)
return &msg
}
func TestTcMsgDeserializeSerialize(t *testing.T) {
var orig = make([]byte, SizeofTcMsg)
rand.Read(orig)
safemsg := deserializeTcMsgSafe(orig)
msg := DeserializeTcMsg(orig)
testDeserializeSerialize(t, orig, safemsg, msg)
}
/* TcActionMsg */
func (msg *TcActionMsg) write(b []byte) {
b[0] = msg.Family
copy(b[1:4], msg.Pad[:])
}
func (msg *TcActionMsg) serializeSafe() []byte {
length := SizeofTcActionMsg
b := make([]byte, length)
msg.write(b)
return b
}
func deserializeTcActionMsgSafe(b []byte) *TcActionMsg {
var msg = TcActionMsg{}
binary.Read(bytes.NewReader(b[0:SizeofTcActionMsg]), NativeEndian(), &msg)
return &msg
}
func TestTcActionMsgDeserializeSerialize(t *testing.T) {
var orig = make([]byte, SizeofTcActionMsg)
rand.Read(orig)
safemsg := deserializeTcActionMsgSafe(orig)
msg := DeserializeTcActionMsg(orig)
testDeserializeSerialize(t, orig, safemsg, msg)
}
/* TcRateSpec */
func (msg *TcRateSpec) write(b []byte) {
native := NativeEndian()
b[0] = msg.CellLog
b[1] = msg.Linklayer
native.PutUint16(b[2:4], msg.Overhead)
native.PutUint16(b[4:6], uint16(msg.CellAlign))
native.PutUint16(b[6:8], msg.Mpu)
native.PutUint32(b[8:12], msg.Rate)
}
func (msg *TcRateSpec) serializeSafe() []byte {
length := SizeofTcRateSpec
b := make([]byte, length)
msg.write(b)
return b
}
func deserializeTcRateSpecSafe(b []byte) *TcRateSpec {
var msg = TcRateSpec{}
binary.Read(bytes.NewReader(b[0:SizeofTcRateSpec]), NativeEndian(), &msg)
return &msg
}
func TestTcRateSpecDeserializeSerialize(t *testing.T) {
var orig = make([]byte, SizeofTcRateSpec)
rand.Read(orig)
safemsg := deserializeTcRateSpecSafe(orig)
msg := DeserializeTcRateSpec(orig)
testDeserializeSerialize(t, orig, safemsg, msg)
}
/* TcTbfQopt */
func (msg *TcTbfQopt) write(b []byte) {
native := NativeEndian()
msg.Rate.write(b[0:SizeofTcRateSpec])
start := SizeofTcRateSpec
msg.Peakrate.write(b[start : start+SizeofTcRateSpec])
start += SizeofTcRateSpec
native.PutUint32(b[start:start+4], msg.Limit)
start += 4
native.PutUint32(b[start:start+4], msg.Buffer)
start += 4
native.PutUint32(b[start:start+4], msg.Mtu)
}
func (msg *TcTbfQopt) serializeSafe() []byte {
length := SizeofTcTbfQopt
b := make([]byte, length)
msg.write(b)
return b
}
func deserializeTcTbfQoptSafe(b []byte) *TcTbfQopt {
var msg = TcTbfQopt{}
binary.Read(bytes.NewReader(b[0:SizeofTcTbfQopt]), NativeEndian(), &msg)
return &msg
}
func TestTcTbfQoptDeserializeSerialize(t *testing.T) {
var orig = make([]byte, SizeofTcTbfQopt)
rand.Read(orig)
safemsg := deserializeTcTbfQoptSafe(orig)
msg := DeserializeTcTbfQopt(orig)
testDeserializeSerialize(t, orig, safemsg, msg)
}
/* TcHtbCopt */
func (msg *TcHtbCopt) write(b []byte) {
native := NativeEndian()
msg.Rate.write(b[0:SizeofTcRateSpec])
start := SizeofTcRateSpec
msg.Ceil.write(b[start : start+SizeofTcRateSpec])
start += SizeofTcRateSpec
native.PutUint32(b[start:start+4], msg.Buffer)
start += 4
native.PutUint32(b[start:start+4], msg.Cbuffer)
start += 4
native.PutUint32(b[start:start+4], msg.Quantum)
start += 4
native.PutUint32(b[start:start+4], msg.Level)
start += 4
native.PutUint32(b[start:start+4], msg.Prio)
}
func (msg *TcHtbCopt) serializeSafe() []byte {
length := SizeofTcHtbCopt
b := make([]byte, length)
msg.write(b)
return b
}
func deserializeTcHtbCoptSafe(b []byte) *TcHtbCopt {
var msg = TcHtbCopt{}
binary.Read(bytes.NewReader(b[0:SizeofTcHtbCopt]), NativeEndian(), &msg)
return &msg
}
func TestTcHtbCoptDeserializeSerialize(t *testing.T) {
var orig = make([]byte, SizeofTcHtbCopt)
rand.Read(orig)
safemsg := deserializeTcHtbCoptSafe(orig)
msg := DeserializeTcHtbCopt(orig)
testDeserializeSerialize(t, orig, safemsg, msg)
}

View File

@@ -1,161 +0,0 @@
package nl
import (
"bytes"
"crypto/rand"
"encoding/binary"
"testing"
)
func (msg *XfrmAddress) write(b []byte) {
copy(b[0:SizeofXfrmAddress], msg[:])
}
func (msg *XfrmAddress) serializeSafe() []byte {
b := make([]byte, SizeofXfrmAddress)
msg.write(b)
return b
}
func deserializeXfrmAddressSafe(b []byte) *XfrmAddress {
var msg = XfrmAddress{}
binary.Read(bytes.NewReader(b[0:SizeofXfrmAddress]), NativeEndian(), &msg)
return &msg
}
func TestXfrmAddressDeserializeSerialize(t *testing.T) {
var orig = make([]byte, SizeofXfrmAddress)
rand.Read(orig)
safemsg := deserializeXfrmAddressSafe(orig)
msg := DeserializeXfrmAddress(orig)
testDeserializeSerialize(t, orig, safemsg, msg)
}
func (msg *XfrmSelector) write(b []byte) {
const AddrEnd = SizeofXfrmAddress * 2
native := NativeEndian()
msg.Daddr.write(b[0:SizeofXfrmAddress])
msg.Saddr.write(b[SizeofXfrmAddress:AddrEnd])
native.PutUint16(b[AddrEnd:AddrEnd+2], msg.Dport)
native.PutUint16(b[AddrEnd+2:AddrEnd+4], msg.DportMask)
native.PutUint16(b[AddrEnd+4:AddrEnd+6], msg.Sport)
native.PutUint16(b[AddrEnd+6:AddrEnd+8], msg.SportMask)
native.PutUint16(b[AddrEnd+8:AddrEnd+10], msg.Family)
b[AddrEnd+10] = msg.PrefixlenD
b[AddrEnd+11] = msg.PrefixlenS
b[AddrEnd+12] = msg.Proto
copy(b[AddrEnd+13:AddrEnd+16], msg.Pad[:])
native.PutUint32(b[AddrEnd+16:AddrEnd+20], uint32(msg.Ifindex))
native.PutUint32(b[AddrEnd+20:AddrEnd+24], msg.User)
}
func (msg *XfrmSelector) serializeSafe() []byte {
length := SizeofXfrmSelector
b := make([]byte, length)
msg.write(b)
return b
}
func deserializeXfrmSelectorSafe(b []byte) *XfrmSelector {
var msg = XfrmSelector{}
binary.Read(bytes.NewReader(b[0:SizeofXfrmSelector]), NativeEndian(), &msg)
return &msg
}
func TestXfrmSelectorDeserializeSerialize(t *testing.T) {
var orig = make([]byte, SizeofXfrmSelector)
rand.Read(orig)
safemsg := deserializeXfrmSelectorSafe(orig)
msg := DeserializeXfrmSelector(orig)
testDeserializeSerialize(t, orig, safemsg, msg)
}
func (msg *XfrmLifetimeCfg) write(b []byte) {
native := NativeEndian()
native.PutUint64(b[0:8], msg.SoftByteLimit)
native.PutUint64(b[8:16], msg.HardByteLimit)
native.PutUint64(b[16:24], msg.SoftPacketLimit)
native.PutUint64(b[24:32], msg.HardPacketLimit)
native.PutUint64(b[32:40], msg.SoftAddExpiresSeconds)
native.PutUint64(b[40:48], msg.HardAddExpiresSeconds)
native.PutUint64(b[48:56], msg.SoftUseExpiresSeconds)
native.PutUint64(b[56:64], msg.HardUseExpiresSeconds)
}
func (msg *XfrmLifetimeCfg) serializeSafe() []byte {
length := SizeofXfrmLifetimeCfg
b := make([]byte, length)
msg.write(b)
return b
}
func deserializeXfrmLifetimeCfgSafe(b []byte) *XfrmLifetimeCfg {
var msg = XfrmLifetimeCfg{}
binary.Read(bytes.NewReader(b[0:SizeofXfrmLifetimeCfg]), NativeEndian(), &msg)
return &msg
}
func TestXfrmLifetimeCfgDeserializeSerialize(t *testing.T) {
var orig = make([]byte, SizeofXfrmLifetimeCfg)
rand.Read(orig)
safemsg := deserializeXfrmLifetimeCfgSafe(orig)
msg := DeserializeXfrmLifetimeCfg(orig)
testDeserializeSerialize(t, orig, safemsg, msg)
}
func (msg *XfrmLifetimeCur) write(b []byte) {
native := NativeEndian()
native.PutUint64(b[0:8], msg.Bytes)
native.PutUint64(b[8:16], msg.Packets)
native.PutUint64(b[16:24], msg.AddTime)
native.PutUint64(b[24:32], msg.UseTime)
}
func (msg *XfrmLifetimeCur) serializeSafe() []byte {
length := SizeofXfrmLifetimeCur
b := make([]byte, length)
msg.write(b)
return b
}
func deserializeXfrmLifetimeCurSafe(b []byte) *XfrmLifetimeCur {
var msg = XfrmLifetimeCur{}
binary.Read(bytes.NewReader(b[0:SizeofXfrmLifetimeCur]), NativeEndian(), &msg)
return &msg
}
func TestXfrmLifetimeCurDeserializeSerialize(t *testing.T) {
var orig = make([]byte, SizeofXfrmLifetimeCur)
rand.Read(orig)
safemsg := deserializeXfrmLifetimeCurSafe(orig)
msg := DeserializeXfrmLifetimeCur(orig)
testDeserializeSerialize(t, orig, safemsg, msg)
}
func (msg *XfrmId) write(b []byte) {
native := NativeEndian()
msg.Daddr.write(b[0:SizeofXfrmAddress])
native.PutUint32(b[SizeofXfrmAddress:SizeofXfrmAddress+4], msg.Spi)
b[SizeofXfrmAddress+4] = msg.Proto
copy(b[SizeofXfrmAddress+5:SizeofXfrmAddress+8], msg.Pad[:])
}
func (msg *XfrmId) serializeSafe() []byte {
b := make([]byte, SizeofXfrmId)
msg.write(b)
return b
}
func deserializeXfrmIdSafe(b []byte) *XfrmId {
var msg = XfrmId{}
binary.Read(bytes.NewReader(b[0:SizeofXfrmId]), NativeEndian(), &msg)
return &msg
}
func TestXfrmIdDeserializeSerialize(t *testing.T) {
var orig = make([]byte, SizeofXfrmId)
rand.Read(orig)
safemsg := deserializeXfrmIdSafe(orig)
msg := DeserializeXfrmId(orig)
testDeserializeSerialize(t, orig, safemsg, msg)
}

View File

@@ -1,109 +0,0 @@
package nl
import (
"bytes"
"crypto/rand"
"encoding/binary"
"testing"
)
func (msg *XfrmUserpolicyId) write(b []byte) {
native := NativeEndian()
msg.Sel.write(b[0:SizeofXfrmSelector])
native.PutUint32(b[SizeofXfrmSelector:SizeofXfrmSelector+4], msg.Index)
b[SizeofXfrmSelector+4] = msg.Dir
copy(b[SizeofXfrmSelector+5:SizeofXfrmSelector+8], msg.Pad[:])
}
func (msg *XfrmUserpolicyId) serializeSafe() []byte {
b := make([]byte, SizeofXfrmUserpolicyId)
msg.write(b)
return b
}
func deserializeXfrmUserpolicyIdSafe(b []byte) *XfrmUserpolicyId {
var msg = XfrmUserpolicyId{}
binary.Read(bytes.NewReader(b[0:SizeofXfrmUserpolicyId]), NativeEndian(), &msg)
return &msg
}
func TestXfrmUserpolicyIdDeserializeSerialize(t *testing.T) {
var orig = make([]byte, SizeofXfrmUserpolicyId)
rand.Read(orig)
safemsg := deserializeXfrmUserpolicyIdSafe(orig)
msg := DeserializeXfrmUserpolicyId(orig)
testDeserializeSerialize(t, orig, safemsg, msg)
}
func (msg *XfrmUserpolicyInfo) write(b []byte) {
const CfgEnd = SizeofXfrmSelector + SizeofXfrmLifetimeCfg
const CurEnd = CfgEnd + SizeofXfrmLifetimeCur
native := NativeEndian()
msg.Sel.write(b[0:SizeofXfrmSelector])
msg.Lft.write(b[SizeofXfrmSelector:CfgEnd])
msg.Curlft.write(b[CfgEnd:CurEnd])
native.PutUint32(b[CurEnd:CurEnd+4], msg.Priority)
native.PutUint32(b[CurEnd+4:CurEnd+8], msg.Index)
b[CurEnd+8] = msg.Dir
b[CurEnd+9] = msg.Action
b[CurEnd+10] = msg.Flags
b[CurEnd+11] = msg.Share
copy(b[CurEnd+12:CurEnd+16], msg.Pad[:])
}
func (msg *XfrmUserpolicyInfo) serializeSafe() []byte {
b := make([]byte, SizeofXfrmUserpolicyInfo)
msg.write(b)
return b
}
func deserializeXfrmUserpolicyInfoSafe(b []byte) *XfrmUserpolicyInfo {
var msg = XfrmUserpolicyInfo{}
binary.Read(bytes.NewReader(b[0:SizeofXfrmUserpolicyInfo]), NativeEndian(), &msg)
return &msg
}
func TestXfrmUserpolicyInfoDeserializeSerialize(t *testing.T) {
var orig = make([]byte, SizeofXfrmUserpolicyInfo)
rand.Read(orig)
safemsg := deserializeXfrmUserpolicyInfoSafe(orig)
msg := DeserializeXfrmUserpolicyInfo(orig)
testDeserializeSerialize(t, orig, safemsg, msg)
}
func (msg *XfrmUserTmpl) write(b []byte) {
const AddrEnd = SizeofXfrmId + 4 + SizeofXfrmAddress
native := NativeEndian()
msg.XfrmId.write(b[0:SizeofXfrmId])
native.PutUint16(b[SizeofXfrmId:SizeofXfrmId+2], msg.Family)
copy(b[SizeofXfrmId+2:SizeofXfrmId+4], msg.Pad1[:])
msg.Saddr.write(b[SizeofXfrmId+4 : AddrEnd])
native.PutUint32(b[AddrEnd:AddrEnd+4], msg.Reqid)
b[AddrEnd+4] = msg.Mode
b[AddrEnd+5] = msg.Share
b[AddrEnd+6] = msg.Optional
b[AddrEnd+7] = msg.Pad2
native.PutUint32(b[AddrEnd+8:AddrEnd+12], msg.Aalgos)
native.PutUint32(b[AddrEnd+12:AddrEnd+16], msg.Ealgos)
native.PutUint32(b[AddrEnd+16:AddrEnd+20], msg.Calgos)
}
func (msg *XfrmUserTmpl) serializeSafe() []byte {
b := make([]byte, SizeofXfrmUserTmpl)
msg.write(b)
return b
}
func deserializeXfrmUserTmplSafe(b []byte) *XfrmUserTmpl {
var msg = XfrmUserTmpl{}
binary.Read(bytes.NewReader(b[0:SizeofXfrmUserTmpl]), NativeEndian(), &msg)
return &msg
}
func TestXfrmUserTmplDeserializeSerialize(t *testing.T) {
var orig = make([]byte, SizeofXfrmUserTmpl)
rand.Read(orig)
safemsg := deserializeXfrmUserTmplSafe(orig)
msg := DeserializeXfrmUserTmpl(orig)
testDeserializeSerialize(t, orig, safemsg, msg)
}

View File

@@ -1,277 +0,0 @@
package nl
import (
"bytes"
"crypto/rand"
"encoding/binary"
"testing"
)
func (msg *XfrmUsersaId) write(b []byte) {
native := NativeEndian()
msg.Daddr.write(b[0:SizeofXfrmAddress])
native.PutUint32(b[SizeofXfrmAddress:SizeofXfrmAddress+4], msg.Spi)
native.PutUint16(b[SizeofXfrmAddress+4:SizeofXfrmAddress+6], msg.Family)
b[SizeofXfrmAddress+6] = msg.Proto
b[SizeofXfrmAddress+7] = msg.Pad
}
func (msg *XfrmUsersaId) serializeSafe() []byte {
b := make([]byte, SizeofXfrmUsersaId)
msg.write(b)
return b
}
func deserializeXfrmUsersaIdSafe(b []byte) *XfrmUsersaId {
var msg = XfrmUsersaId{}
binary.Read(bytes.NewReader(b[0:SizeofXfrmUsersaId]), NativeEndian(), &msg)
return &msg
}
func TestXfrmUsersaIdDeserializeSerialize(t *testing.T) {
var orig = make([]byte, SizeofXfrmUsersaId)
rand.Read(orig)
safemsg := deserializeXfrmUsersaIdSafe(orig)
msg := DeserializeXfrmUsersaId(orig)
testDeserializeSerialize(t, orig, safemsg, msg)
}
func (msg *XfrmStats) write(b []byte) {
native := NativeEndian()
native.PutUint32(b[0:4], msg.ReplayWindow)
native.PutUint32(b[4:8], msg.Replay)
native.PutUint32(b[8:12], msg.IntegrityFailed)
}
func (msg *XfrmStats) serializeSafe() []byte {
b := make([]byte, SizeofXfrmStats)
msg.write(b)
return b
}
func deserializeXfrmStatsSafe(b []byte) *XfrmStats {
var msg = XfrmStats{}
binary.Read(bytes.NewReader(b[0:SizeofXfrmStats]), NativeEndian(), &msg)
return &msg
}
func TestXfrmStatsDeserializeSerialize(t *testing.T) {
var orig = make([]byte, SizeofXfrmStats)
rand.Read(orig)
safemsg := deserializeXfrmStatsSafe(orig)
msg := DeserializeXfrmStats(orig)
testDeserializeSerialize(t, orig, safemsg, msg)
}
func (msg *XfrmUsersaInfo) write(b []byte) {
const IdEnd = SizeofXfrmSelector + SizeofXfrmId
const AddressEnd = IdEnd + SizeofXfrmAddress
const CfgEnd = AddressEnd + SizeofXfrmLifetimeCfg
const CurEnd = CfgEnd + SizeofXfrmLifetimeCur
const StatsEnd = CurEnd + SizeofXfrmStats
native := NativeEndian()
msg.Sel.write(b[0:SizeofXfrmSelector])
msg.Id.write(b[SizeofXfrmSelector:IdEnd])
msg.Saddr.write(b[IdEnd:AddressEnd])
msg.Lft.write(b[AddressEnd:CfgEnd])
msg.Curlft.write(b[CfgEnd:CurEnd])
msg.Stats.write(b[CurEnd:StatsEnd])
native.PutUint32(b[StatsEnd:StatsEnd+4], msg.Seq)
native.PutUint32(b[StatsEnd+4:StatsEnd+8], msg.Reqid)
native.PutUint16(b[StatsEnd+8:StatsEnd+10], msg.Family)
b[StatsEnd+10] = msg.Mode
b[StatsEnd+11] = msg.ReplayWindow
b[StatsEnd+12] = msg.Flags
copy(b[StatsEnd+13:StatsEnd+20], msg.Pad[:])
}
func (msg *XfrmUsersaInfo) serializeSafe() []byte {
b := make([]byte, SizeofXfrmUsersaInfo)
msg.write(b)
return b
}
func deserializeXfrmUsersaInfoSafe(b []byte) *XfrmUsersaInfo {
var msg = XfrmUsersaInfo{}
binary.Read(bytes.NewReader(b[0:SizeofXfrmUsersaInfo]), NativeEndian(), &msg)
return &msg
}
func TestXfrmUsersaInfoDeserializeSerialize(t *testing.T) {
var orig = make([]byte, SizeofXfrmUsersaInfo)
rand.Read(orig)
safemsg := deserializeXfrmUsersaInfoSafe(orig)
msg := DeserializeXfrmUsersaInfo(orig)
testDeserializeSerialize(t, orig, safemsg, msg)
}
func (msg *XfrmAlgo) write(b []byte) {
native := NativeEndian()
copy(b[0:64], msg.AlgName[:])
native.PutUint32(b[64:68], msg.AlgKeyLen)
copy(b[68:msg.Len()], msg.AlgKey[:])
}
func (msg *XfrmAlgo) serializeSafe() []byte {
b := make([]byte, msg.Len())
msg.write(b)
return b
}
func deserializeXfrmAlgoSafe(b []byte) *XfrmAlgo {
var msg = XfrmAlgo{}
copy(msg.AlgName[:], b[0:64])
binary.Read(bytes.NewReader(b[64:68]), NativeEndian(), &msg.AlgKeyLen)
msg.AlgKey = b[68:msg.Len()]
return &msg
}
func TestXfrmAlgoDeserializeSerialize(t *testing.T) {
native := NativeEndian()
// use a 32 byte key len
var orig = make([]byte, SizeofXfrmAlgo+32)
rand.Read(orig)
// set the key len to 256 bits
var KeyLen uint32 = 0x00000100
// Little Endian Big Endian
// orig[64] = 0 orig[64] = 0
// orig[65] = 1 orig[65] = 0
// orig[66] = 0 orig[66] = 1
// orig[67] = 0 orig[67] = 0
native.PutUint32(orig[64:68], KeyLen)
safemsg := deserializeXfrmAlgoSafe(orig)
msg := DeserializeXfrmAlgo(orig)
testDeserializeSerialize(t, orig, safemsg, msg)
}
func (msg *XfrmAlgoAuth) write(b []byte) {
native := NativeEndian()
copy(b[0:64], msg.AlgName[:])
native.PutUint32(b[64:68], msg.AlgKeyLen)
native.PutUint32(b[68:72], msg.AlgTruncLen)
copy(b[72:msg.Len()], msg.AlgKey[:])
}
func (msg *XfrmAlgoAuth) serializeSafe() []byte {
b := make([]byte, msg.Len())
msg.write(b)
return b
}
func deserializeXfrmAlgoAuthSafe(b []byte) *XfrmAlgoAuth {
var msg = XfrmAlgoAuth{}
copy(msg.AlgName[:], b[0:64])
binary.Read(bytes.NewReader(b[64:68]), NativeEndian(), &msg.AlgKeyLen)
binary.Read(bytes.NewReader(b[68:72]), NativeEndian(), &msg.AlgTruncLen)
msg.AlgKey = b[72:msg.Len()]
return &msg
}
func TestXfrmAlgoAuthDeserializeSerialize(t *testing.T) {
native := NativeEndian()
// use a 32 byte key len
var orig = make([]byte, SizeofXfrmAlgoAuth+32)
rand.Read(orig)
// set the key len to 256 bits
var KeyLen uint32 = 0x00000100
// Little Endian Big Endian
// orig[64] = 0 orig[64] = 0
// orig[65] = 1 orig[65] = 0
// orig[66] = 0 orig[66] = 1
// orig[67] = 0 orig[67] = 0
native.PutUint32(orig[64:68], KeyLen)
safemsg := deserializeXfrmAlgoAuthSafe(orig)
msg := DeserializeXfrmAlgoAuth(orig)
testDeserializeSerialize(t, orig, safemsg, msg)
}
func (msg *XfrmEncapTmpl) write(b []byte) {
native := NativeEndian()
native.PutUint16(b[0:2], msg.EncapType)
native.PutUint16(b[2:4], msg.EncapSport)
native.PutUint16(b[4:6], msg.EncapDport)
copy(b[6:8], msg.Pad[:])
msg.EncapOa.write(b[8:SizeofXfrmAddress])
}
func (msg *XfrmEncapTmpl) serializeSafe() []byte {
b := make([]byte, SizeofXfrmEncapTmpl)
msg.write(b)
return b
}
func deserializeXfrmEncapTmplSafe(b []byte) *XfrmEncapTmpl {
var msg = XfrmEncapTmpl{}
binary.Read(bytes.NewReader(b[0:SizeofXfrmEncapTmpl]), NativeEndian(), &msg)
return &msg
}
func TestXfrmEncapTmplDeserializeSerialize(t *testing.T) {
var orig = make([]byte, SizeofXfrmEncapTmpl)
rand.Read(orig)
safemsg := deserializeXfrmEncapTmplSafe(orig)
msg := DeserializeXfrmEncapTmpl(orig)
testDeserializeSerialize(t, orig, safemsg, msg)
}
func (msg *XfrmMark) write(b []byte) {
native := NativeEndian()
native.PutUint32(b[0:4], msg.Value)
native.PutUint32(b[4:8], msg.Mask)
}
func (msg *XfrmMark) serializeSafe() []byte {
b := make([]byte, SizeofXfrmMark)
msg.write(b)
return b
}
func deserializeXfrmMarkSafe(b []byte) *XfrmMark {
var msg = XfrmMark{}
binary.Read(bytes.NewReader(b[0:SizeofXfrmMark]), NativeEndian(), &msg)
return &msg
}
func TestXfrmMarkDeserializeSerialize(t *testing.T) {
var orig = make([]byte, SizeofXfrmMark)
rand.Read(orig)
safemsg := deserializeXfrmMarkSafe(orig)
msg := DeserializeXfrmMark(orig)
testDeserializeSerialize(t, orig, safemsg, msg)
}
func (msg *XfrmAlgoAEAD) write(b []byte) {
native := NativeEndian()
copy(b[0:64], msg.AlgName[:])
native.PutUint32(b[64:68], msg.AlgKeyLen)
native.PutUint32(b[68:72], msg.AlgICVLen)
copy(b[72:msg.Len()], msg.AlgKey[:])
}
func (msg *XfrmAlgoAEAD) serializeSafe() []byte {
b := make([]byte, msg.Len())
msg.write(b)
return b
}
func deserializeXfrmAlgoAEADSafe(b []byte) *XfrmAlgoAEAD {
var msg = XfrmAlgoAEAD{}
copy(msg.AlgName[:], b[0:64])
binary.Read(bytes.NewReader(b[64:68]), NativeEndian(), &msg.AlgKeyLen)
binary.Read(bytes.NewReader(b[68:72]), NativeEndian(), &msg.AlgICVLen)
msg.AlgKey = b[72:msg.Len()]
return &msg
}
func TestXfrmXfrmAlgoAeadDeserializeSerialize(t *testing.T) {
native := NativeEndian()
// use a 32 byte key len
var orig = make([]byte, SizeofXfrmAlgoAEAD+36)
rand.Read(orig)
// set the key len to (256 + 32) bits
var KeyLen uint32 = 0x00000120
native.PutUint32(orig[64:68], KeyLen)
safemsg := deserializeXfrmAlgoAEADSafe(orig)
msg := DeserializeXfrmAlgoAEAD(orig)
testDeserializeSerialize(t, orig, safemsg, msg)
}

View File

@@ -1,98 +0,0 @@
package netlink
import "testing"
func TestProtinfo(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
master := &Bridge{LinkAttrs{Name: "foo"}}
if err := LinkAdd(master); err != nil {
t.Fatal(err)
}
iface1 := &Dummy{LinkAttrs{Name: "bar1", MasterIndex: master.Index}}
iface2 := &Dummy{LinkAttrs{Name: "bar2", MasterIndex: master.Index}}
iface3 := &Dummy{LinkAttrs{Name: "bar3"}}
if err := LinkAdd(iface1); err != nil {
t.Fatal(err)
}
if err := LinkAdd(iface2); err != nil {
t.Fatal(err)
}
if err := LinkAdd(iface3); err != nil {
t.Fatal(err)
}
oldpi1, err := LinkGetProtinfo(iface1)
if err != nil {
t.Fatal(err)
}
oldpi2, err := LinkGetProtinfo(iface2)
if err != nil {
t.Fatal(err)
}
if err := LinkSetHairpin(iface1, true); err != nil {
t.Fatal(err)
}
if err := LinkSetRootBlock(iface1, true); err != nil {
t.Fatal(err)
}
pi1, err := LinkGetProtinfo(iface1)
if err != nil {
t.Fatal(err)
}
if !pi1.Hairpin {
t.Fatalf("Hairpin mode is not enabled for %s, but should", iface1.Name)
}
if !pi1.RootBlock {
t.Fatalf("RootBlock is not enabled for %s, but should", iface1.Name)
}
if pi1.Guard != oldpi1.Guard {
t.Fatalf("Guard field was changed for %s but shouldn't", iface1.Name)
}
if pi1.FastLeave != oldpi1.FastLeave {
t.Fatalf("FastLeave field was changed for %s but shouldn't", iface1.Name)
}
if pi1.Learning != oldpi1.Learning {
t.Fatalf("Learning field was changed for %s but shouldn't", iface1.Name)
}
if pi1.Flood != oldpi1.Flood {
t.Fatalf("Flood field was changed for %s but shouldn't", iface1.Name)
}
if err := LinkSetGuard(iface2, true); err != nil {
t.Fatal(err)
}
if err := LinkSetLearning(iface2, false); err != nil {
t.Fatal(err)
}
pi2, err := LinkGetProtinfo(iface2)
if err != nil {
t.Fatal(err)
}
if pi2.Hairpin {
t.Fatalf("Hairpin mode is enabled for %s, but shouldn't", iface2.Name)
}
if !pi2.Guard {
t.Fatalf("Guard is not enabled for %s, but should", iface2.Name)
}
if pi2.Learning {
t.Fatalf("Learning is enabled for %s, but shouldn't", iface2.Name)
}
if pi2.RootBlock != oldpi2.RootBlock {
t.Fatalf("RootBlock field was changed for %s but shouldn't", iface2.Name)
}
if pi2.FastLeave != oldpi2.FastLeave {
t.Fatalf("FastLeave field was changed for %s but shouldn't", iface2.Name)
}
if pi2.Flood != oldpi2.Flood {
t.Fatalf("Flood field was changed for %s but shouldn't", iface2.Name)
}
if err := LinkSetHairpin(iface3, true); err == nil || err.Error() != "operation not supported" {
t.Fatalf("Set protinfo attrs for link without master is not supported, but err: %s", err)
}
}

View File

@@ -1,345 +0,0 @@
package netlink
import (
"testing"
)
func TestTbfAddDel(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
t.Fatal(err)
}
link, err := LinkByName("foo")
if err != nil {
t.Fatal(err)
}
if err := LinkSetUp(link); err != nil {
t.Fatal(err)
}
qdisc := &Tbf{
QdiscAttrs: QdiscAttrs{
LinkIndex: link.Attrs().Index,
Handle: MakeHandle(1, 0),
Parent: HANDLE_ROOT,
},
Rate: 131072,
Limit: 1220703,
Buffer: 16793,
}
if err := QdiscAdd(qdisc); err != nil {
t.Fatal(err)
}
qdiscs, err := QdiscList(link)
if err != nil {
t.Fatal(err)
}
if len(qdiscs) != 1 {
t.Fatal("Failed to add qdisc")
}
tbf, ok := qdiscs[0].(*Tbf)
if !ok {
t.Fatal("Qdisc is the wrong type")
}
if tbf.Rate != qdisc.Rate {
t.Fatal("Rate doesn't match")
}
if tbf.Limit != qdisc.Limit {
t.Fatal("Limit doesn't match")
}
if tbf.Buffer != qdisc.Buffer {
t.Fatal("Buffer doesn't match")
}
if err := QdiscDel(qdisc); err != nil {
t.Fatal(err)
}
qdiscs, err = QdiscList(link)
if err != nil {
t.Fatal(err)
}
if len(qdiscs) != 0 {
t.Fatal("Failed to remove qdisc")
}
}
func TestHtbAddDel(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
t.Fatal(err)
}
link, err := LinkByName("foo")
if err != nil {
t.Fatal(err)
}
if err := LinkSetUp(link); err != nil {
t.Fatal(err)
}
attrs := QdiscAttrs{
LinkIndex: link.Attrs().Index,
Handle: MakeHandle(1, 0),
Parent: HANDLE_ROOT,
}
qdisc := NewHtb(attrs)
qdisc.Rate2Quantum = 5
if err := QdiscAdd(qdisc); err != nil {
t.Fatal(err)
}
qdiscs, err := QdiscList(link)
if err != nil {
t.Fatal(err)
}
if len(qdiscs) != 1 {
t.Fatal("Failed to add qdisc")
}
htb, ok := qdiscs[0].(*Htb)
if !ok {
t.Fatal("Qdisc is the wrong type")
}
if htb.Defcls != qdisc.Defcls {
t.Fatal("Defcls doesn't match")
}
if htb.Rate2Quantum != qdisc.Rate2Quantum {
t.Fatal("Rate2Quantum doesn't match")
}
if htb.Debug != qdisc.Debug {
t.Fatal("Debug doesn't match")
}
if err := QdiscDel(qdisc); err != nil {
t.Fatal(err)
}
qdiscs, err = QdiscList(link)
if err != nil {
t.Fatal(err)
}
if len(qdiscs) != 0 {
t.Fatal("Failed to remove qdisc")
}
}
func TestPrioAddDel(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
t.Fatal(err)
}
link, err := LinkByName("foo")
if err != nil {
t.Fatal(err)
}
if err := LinkSetUp(link); err != nil {
t.Fatal(err)
}
qdisc := NewPrio(QdiscAttrs{
LinkIndex: link.Attrs().Index,
Handle: MakeHandle(1, 0),
Parent: HANDLE_ROOT,
})
if err := QdiscAdd(qdisc); err != nil {
t.Fatal(err)
}
qdiscs, err := QdiscList(link)
if err != nil {
t.Fatal(err)
}
if len(qdiscs) != 1 {
t.Fatal("Failed to add qdisc")
}
_, ok := qdiscs[0].(*Prio)
if !ok {
t.Fatal("Qdisc is the wrong type")
}
if err := QdiscDel(qdisc); err != nil {
t.Fatal(err)
}
qdiscs, err = QdiscList(link)
if err != nil {
t.Fatal(err)
}
if len(qdiscs) != 0 {
t.Fatal("Failed to remove qdisc")
}
}
func TestTbfAddHtbReplaceDel(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
t.Fatal(err)
}
link, err := LinkByName("foo")
if err != nil {
t.Fatal(err)
}
if err := LinkSetUp(link); err != nil {
t.Fatal(err)
}
// Add
attrs := QdiscAttrs{
LinkIndex: link.Attrs().Index,
Handle: MakeHandle(1, 0),
Parent: HANDLE_ROOT,
}
qdisc := &Tbf{
QdiscAttrs: attrs,
Rate: 131072,
Limit: 1220703,
Buffer: 16793,
}
if err := QdiscAdd(qdisc); err != nil {
t.Fatal(err)
}
qdiscs, err := QdiscList(link)
if err != nil {
t.Fatal(err)
}
if len(qdiscs) != 1 {
t.Fatal("Failed to add qdisc")
}
tbf, ok := qdiscs[0].(*Tbf)
if !ok {
t.Fatal("Qdisc is the wrong type")
}
if tbf.Rate != qdisc.Rate {
t.Fatal("Rate doesn't match")
}
if tbf.Limit != qdisc.Limit {
t.Fatal("Limit doesn't match")
}
if tbf.Buffer != qdisc.Buffer {
t.Fatal("Buffer doesn't match")
}
// Replace
// For replace to work, the handle MUST be different that the running one
attrs.Handle = MakeHandle(2, 0)
qdisc2 := NewHtb(attrs)
qdisc2.Rate2Quantum = 5
if err := QdiscReplace(qdisc2); err != nil {
t.Fatal(err)
}
qdiscs, err = QdiscList(link)
if err != nil {
t.Fatal(err)
}
if len(qdiscs) != 1 {
t.Fatal("Failed to add qdisc")
}
htb, ok := qdiscs[0].(*Htb)
if !ok {
t.Fatal("Qdisc is the wrong type")
}
if htb.Defcls != qdisc2.Defcls {
t.Fatal("Defcls doesn't match")
}
if htb.Rate2Quantum != qdisc2.Rate2Quantum {
t.Fatal("Rate2Quantum doesn't match")
}
if htb.Debug != qdisc2.Debug {
t.Fatal("Debug doesn't match")
}
if err := QdiscDel(qdisc2); err != nil {
t.Fatal(err)
}
qdiscs, err = QdiscList(link)
if err != nil {
t.Fatal(err)
}
if len(qdiscs) != 0 {
t.Fatal("Failed to remove qdisc")
}
}
func TestTbfAddTbfChangeDel(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
t.Fatal(err)
}
link, err := LinkByName("foo")
if err != nil {
t.Fatal(err)
}
if err := LinkSetUp(link); err != nil {
t.Fatal(err)
}
// Add
attrs := QdiscAttrs{
LinkIndex: link.Attrs().Index,
Handle: MakeHandle(1, 0),
Parent: HANDLE_ROOT,
}
qdisc := &Tbf{
QdiscAttrs: attrs,
Rate: 131072,
Limit: 1220703,
Buffer: 16793,
}
if err := QdiscAdd(qdisc); err != nil {
t.Fatal(err)
}
qdiscs, err := QdiscList(link)
if err != nil {
t.Fatal(err)
}
if len(qdiscs) != 1 {
t.Fatal("Failed to add qdisc")
}
tbf, ok := qdiscs[0].(*Tbf)
if !ok {
t.Fatal("Qdisc is the wrong type")
}
if tbf.Rate != qdisc.Rate {
t.Fatal("Rate doesn't match")
}
if tbf.Limit != qdisc.Limit {
t.Fatal("Limit doesn't match")
}
if tbf.Buffer != qdisc.Buffer {
t.Fatal("Buffer doesn't match")
}
// Change
// For change to work, the handle MUST not change
qdisc.Rate = 23456
if err := QdiscChange(qdisc); err != nil {
t.Fatal(err)
}
qdiscs, err = QdiscList(link)
if err != nil {
t.Fatal(err)
}
if len(qdiscs) != 1 {
t.Fatal("Failed to add qdisc")
}
tbf, ok = qdiscs[0].(*Tbf)
if !ok {
t.Fatal("Qdisc is the wrong type")
}
if tbf.Rate != qdisc.Rate {
t.Fatal("Rate doesn't match")
}
if tbf.Limit != qdisc.Limit {
t.Fatal("Limit doesn't match")
}
if tbf.Buffer != qdisc.Buffer {
t.Fatal("Buffer doesn't match")
}
if err := QdiscDel(qdisc); err != nil {
t.Fatal(err)
}
qdiscs, err = QdiscList(link)
if err != nil {
t.Fatal(err)
}
if len(qdiscs) != 0 {
t.Fatal("Failed to remove qdisc")
}
}

View File

@@ -1,305 +0,0 @@
package netlink
import (
"net"
"syscall"
"testing"
"time"
"github.com/vishvananda/netns"
)
func TestRouteAddDel(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
// get loopback interface
link, err := LinkByName("lo")
if err != nil {
t.Fatal(err)
}
// bring the interface up
if err := LinkSetUp(link); err != nil {
t.Fatal(err)
}
// add a gateway route
dst := &net.IPNet{
IP: net.IPv4(192, 168, 0, 0),
Mask: net.CIDRMask(24, 32),
}
ip := net.IPv4(127, 1, 1, 1)
route := Route{LinkIndex: link.Attrs().Index, Dst: dst, Src: ip}
if err := RouteAdd(&route); err != nil {
t.Fatal(err)
}
routes, err := RouteList(link, FAMILY_V4)
if err != nil {
t.Fatal(err)
}
if len(routes) != 1 {
t.Fatal("Route not added properly")
}
dstIP := net.IPv4(192, 168, 0, 42)
routeToDstIP, err := RouteGet(dstIP)
if err != nil {
t.Fatal(err)
}
if len(routeToDstIP) == 0 {
t.Fatal("Default route not present")
}
if err := RouteDel(&route); err != nil {
t.Fatal(err)
}
routes, err = RouteList(link, FAMILY_V4)
if err != nil {
t.Fatal(err)
}
if len(routes) != 0 {
t.Fatal("Route not removed properly")
}
}
func TestRouteAddIncomplete(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
// get loopback interface
link, err := LinkByName("lo")
if err != nil {
t.Fatal(err)
}
// bring the interface up
if err = LinkSetUp(link); err != nil {
t.Fatal(err)
}
route := Route{LinkIndex: link.Attrs().Index}
if err := RouteAdd(&route); err == nil {
t.Fatal("Adding incomplete route should fail")
}
}
func expectRouteUpdate(ch <-chan RouteUpdate, t uint16, dst net.IP) bool {
for {
timeout := time.After(time.Minute)
select {
case update := <-ch:
if update.Type == t && update.Route.Dst.IP.Equal(dst) {
return true
}
case <-timeout:
return false
}
}
}
func TestRouteSubscribe(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
ch := make(chan RouteUpdate)
done := make(chan struct{})
defer close(done)
if err := RouteSubscribe(ch, done); err != nil {
t.Fatal(err)
}
// get loopback interface
link, err := LinkByName("lo")
if err != nil {
t.Fatal(err)
}
// bring the interface up
if err = LinkSetUp(link); err != nil {
t.Fatal(err)
}
// add a gateway route
dst := &net.IPNet{
IP: net.IPv4(192, 168, 0, 0),
Mask: net.CIDRMask(24, 32),
}
ip := net.IPv4(127, 1, 1, 1)
route := Route{LinkIndex: link.Attrs().Index, Dst: dst, Src: ip}
if err := RouteAdd(&route); err != nil {
t.Fatal(err)
}
if !expectRouteUpdate(ch, syscall.RTM_NEWROUTE, dst.IP) {
t.Fatal("Add update not received as expected")
}
if err := RouteDel(&route); err != nil {
t.Fatal(err)
}
if !expectRouteUpdate(ch, syscall.RTM_DELROUTE, dst.IP) {
t.Fatal("Del update not received as expected")
}
}
func TestRouteSubscribeAt(t *testing.T) {
// Create an handle on a custom netns
newNs, err := netns.New()
if err != nil {
t.Fatal(err)
}
defer newNs.Close()
nh, err := NewHandleAt(newNs)
if err != nil {
t.Fatal(err)
}
defer nh.Delete()
// Subscribe for Route events on the custom netns
ch := make(chan RouteUpdate)
done := make(chan struct{})
defer close(done)
if err := RouteSubscribeAt(newNs, ch, done); err != nil {
t.Fatal(err)
}
// get loopback interface
link, err := nh.LinkByName("lo")
if err != nil {
t.Fatal(err)
}
// bring the interface up
if err = nh.LinkSetUp(link); err != nil {
t.Fatal(err)
}
// add a gateway route
dst := &net.IPNet{
IP: net.IPv4(192, 169, 0, 0),
Mask: net.CIDRMask(24, 32),
}
ip := net.IPv4(127, 100, 1, 1)
route := Route{LinkIndex: link.Attrs().Index, Dst: dst, Src: ip}
if err := nh.RouteAdd(&route); err != nil {
t.Fatal(err)
}
if !expectRouteUpdate(ch, syscall.RTM_NEWROUTE, dst.IP) {
t.Fatal("Add update not received as expected")
}
if err := nh.RouteDel(&route); err != nil {
t.Fatal(err)
}
if !expectRouteUpdate(ch, syscall.RTM_DELROUTE, dst.IP) {
t.Fatal("Del update not received as expected")
}
}
func TestRouteExtraFields(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
// get loopback interface
link, err := LinkByName("lo")
if err != nil {
t.Fatal(err)
}
// bring the interface up
if err = LinkSetUp(link); err != nil {
t.Fatal(err)
}
// add a gateway route
dst := &net.IPNet{
IP: net.IPv4(1, 1, 1, 1),
Mask: net.CIDRMask(32, 32),
}
src := net.IPv4(127, 3, 3, 3)
route := Route{
LinkIndex: link.Attrs().Index,
Dst: dst,
Src: src,
Scope: syscall.RT_SCOPE_LINK,
Priority: 13,
Table: syscall.RT_TABLE_MAIN,
Type: syscall.RTN_UNICAST,
Tos: 14,
}
if err := RouteAdd(&route); err != nil {
t.Fatal(err)
}
routes, err := RouteListFiltered(FAMILY_V4, &Route{
Dst: dst,
Src: src,
Scope: syscall.RT_SCOPE_LINK,
Table: syscall.RT_TABLE_MAIN,
Type: syscall.RTN_UNICAST,
Tos: 14,
}, RT_FILTER_DST|RT_FILTER_SRC|RT_FILTER_SCOPE|RT_FILTER_TABLE|RT_FILTER_TYPE|RT_FILTER_TOS)
if err != nil {
t.Fatal(err)
}
if len(routes) != 1 {
t.Fatal("Route not added properly")
}
if routes[0].Scope != syscall.RT_SCOPE_LINK {
t.Fatal("Invalid Scope. Route not added properly")
}
if routes[0].Priority != 13 {
t.Fatal("Invalid Priority. Route not added properly")
}
if routes[0].Table != syscall.RT_TABLE_MAIN {
t.Fatal("Invalid Scope. Route not added properly")
}
if routes[0].Type != syscall.RTN_UNICAST {
t.Fatal("Invalid Type. Route not added properly")
}
if routes[0].Tos != 14 {
t.Fatal("Invalid Tos. Route not added properly")
}
}
func TestRouteMultiPath(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
// get loopback interface
link, err := LinkByName("lo")
if err != nil {
t.Fatal(err)
}
// bring the interface up
if err = LinkSetUp(link); err != nil {
t.Fatal(err)
}
// add a gateway route
dst := &net.IPNet{
IP: net.IPv4(192, 168, 0, 0),
Mask: net.CIDRMask(24, 32),
}
idx := link.Attrs().Index
route := Route{Dst: dst, MultiPath: []*NexthopInfo{&NexthopInfo{LinkIndex: idx}, &NexthopInfo{LinkIndex: idx}}}
if err := RouteAdd(&route); err != nil {
t.Fatal(err)
}
routes, err := RouteList(nil, FAMILY_V4)
if err != nil {
t.Fatal(err)
}
if len(routes) != 1 {
t.Fatal("MultiPath Route not added properly")
}
if len(routes[0].MultiPath) != 2 {
t.Fatal("MultiPath Route not added properly")
}
}

View File

@@ -1,66 +0,0 @@
package netlink
import (
"net"
"syscall"
"testing"
)
func TestRuleAddDel(t *testing.T) {
srcNet := &net.IPNet{IP: net.IPv4(172, 16, 0, 1), Mask: net.CIDRMask(16, 32)}
dstNet := &net.IPNet{IP: net.IPv4(172, 16, 1, 1), Mask: net.CIDRMask(24, 32)}
rulesBegin, err := RuleList(syscall.AF_INET)
if err != nil {
t.Fatal(err)
}
rule := NewRule()
rule.Table = syscall.RT_TABLE_MAIN
rule.Src = srcNet
rule.Dst = dstNet
rule.Priority = 5
rule.OifName = "lo"
rule.IifName = "lo"
if err := RuleAdd(rule); err != nil {
t.Fatal(err)
}
rules, err := RuleList(syscall.AF_INET)
if err != nil {
t.Fatal(err)
}
if len(rules) != len(rulesBegin)+1 {
t.Fatal("Rule not added properly")
}
// find this rule
var found bool
for i := range rules {
if rules[i].Table == rule.Table &&
rules[i].Src != nil && rules[i].Src.String() == srcNet.String() &&
rules[i].Dst != nil && rules[i].Dst.String() == dstNet.String() &&
rules[i].OifName == rule.OifName &&
rules[i].Priority == rule.Priority &&
rules[i].IifName == rule.IifName {
found = true
}
}
if !found {
t.Fatal("Rule has diffrent options than one added")
}
if err := RuleDel(rule); err != nil {
t.Fatal(err)
}
rulesEnd, err := RuleList(syscall.AF_INET)
if err != nil {
t.Fatal(err)
}
if len(rulesEnd) != len(rulesBegin) {
t.Fatal("Rule not removed properly")
}
}

View File

@@ -1,197 +0,0 @@
package netlink
import (
"bytes"
"net"
"testing"
)
const zeroCIDR = "0.0.0.0/0"
func TestXfrmPolicyAddUpdateDel(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
policy := getPolicy()
if err := XfrmPolicyAdd(policy); err != nil {
t.Fatal(err)
}
policies, err := XfrmPolicyList(FAMILY_ALL)
if err != nil {
t.Fatal(err)
}
if len(policies) != 1 {
t.Fatal("Policy not added properly")
}
if !comparePolicies(policy, &policies[0]) {
t.Fatalf("unexpected policy returned.\nExpected: %v.\nGot %v", policy, policies[0])
}
// Look for a specific policy
sp, err := XfrmPolicyGet(policy)
if err != nil {
t.Fatal(err)
}
if !comparePolicies(policy, sp) {
t.Fatalf("unexpected policy returned")
}
// Modify the policy
policy.Priority = 100
if err := XfrmPolicyUpdate(policy); err != nil {
t.Fatal(err)
}
sp, err = XfrmPolicyGet(policy)
if err != nil {
t.Fatal(err)
}
if sp.Priority != 100 {
t.Fatalf("failed to modify the policy")
}
if err = XfrmPolicyDel(policy); err != nil {
t.Fatal(err)
}
policies, err = XfrmPolicyList(FAMILY_ALL)
if err != nil {
t.Fatal(err)
}
if len(policies) != 0 {
t.Fatal("Policy not removed properly")
}
// Src and dst are not mandatory field. Creation should succeed
policy.Src = nil
policy.Dst = nil
if err = XfrmPolicyAdd(policy); err != nil {
t.Fatal(err)
}
sp, err = XfrmPolicyGet(policy)
if err != nil {
t.Fatal(err)
}
if !comparePolicies(policy, sp) {
t.Fatalf("unexpected policy returned")
}
if err = XfrmPolicyDel(policy); err != nil {
t.Fatal(err)
}
if _, err := XfrmPolicyGet(policy); err == nil {
t.Fatalf("Unexpected success")
}
}
func TestXfrmPolicyFlush(t *testing.T) {
setUpNetlinkTest(t)()
p1 := getPolicy()
if err := XfrmPolicyAdd(p1); err != nil {
t.Fatal(err)
}
p1.Dir = XFRM_DIR_IN
s := p1.Src
p1.Src = p1.Dst
p1.Dst = s
if err := XfrmPolicyAdd(p1); err != nil {
t.Fatal(err)
}
policies, err := XfrmPolicyList(FAMILY_ALL)
if err != nil {
t.Fatal(err)
}
if len(policies) != 2 {
t.Fatalf("unexpected number of policies: %d", len(policies))
}
if err := XfrmPolicyFlush(); err != nil {
t.Fatal(err)
}
policies, err = XfrmPolicyList(FAMILY_ALL)
if err != nil {
t.Fatal(err)
}
if len(policies) != 0 {
t.Fatalf("unexpected number of policies: %d", len(policies))
}
}
func comparePolicies(a, b *XfrmPolicy) bool {
if a == b {
return true
}
if a == nil || b == nil {
return false
}
// Do not check Index which is assigned by kernel
return a.Dir == b.Dir && a.Priority == b.Priority &&
compareIPNet(a.Src, b.Src) && compareIPNet(a.Dst, b.Dst) &&
a.Mark.Value == b.Mark.Value && a.Mark.Mask == b.Mark.Mask &&
compareTemplates(a.Tmpls, b.Tmpls)
}
func compareTemplates(a, b []XfrmPolicyTmpl) bool {
if len(a) != len(b) {
return false
}
for i, ta := range a {
tb := b[i]
if !ta.Dst.Equal(tb.Dst) || !ta.Src.Equal(tb.Src) || ta.Spi != tb.Spi ||
ta.Mode != tb.Mode || ta.Reqid != tb.Reqid || ta.Proto != tb.Proto {
return false
}
}
return true
}
func compareIPNet(a, b *net.IPNet) bool {
if a == b {
return true
}
// For unspecified src/dst parseXfrmPolicy would set the zero address cidr
if (a == nil && b.String() == zeroCIDR) || (b == nil && a.String() == zeroCIDR) {
return true
}
if a == nil || b == nil {
return false
}
return a.IP.Equal(b.IP) && bytes.Equal(a.Mask, b.Mask)
}
func getPolicy() *XfrmPolicy {
src, _ := ParseIPNet("127.1.1.1/32")
dst, _ := ParseIPNet("127.1.1.2/32")
policy := &XfrmPolicy{
Src: src,
Dst: dst,
Proto: 17,
DstPort: 1234,
SrcPort: 5678,
Dir: XFRM_DIR_OUT,
Mark: &XfrmMark{
Value: 0xabff22,
Mask: 0xffffffff,
},
Priority: 10,
}
tmpl := XfrmPolicyTmpl{
Src: net.ParseIP("127.0.0.1"),
Dst: net.ParseIP("127.0.0.2"),
Proto: XFRM_PROTO_ESP,
Mode: XFRM_MODE_TUNNEL,
Spi: 0xabcdef99,
}
policy.Tmpls = append(policy.Tmpls, tmpl)
return policy
}

View File

@@ -1,248 +0,0 @@
package netlink
import (
"bytes"
"encoding/hex"
"net"
"testing"
)
func TestXfrmStateAddGetDel(t *testing.T) {
for _, s := range []*XfrmState{getBaseState(), getAeadState()} {
testXfrmStateAddGetDel(t, s)
}
}
func testXfrmStateAddGetDel(t *testing.T, state *XfrmState) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
if err := XfrmStateAdd(state); err != nil {
t.Fatal(err)
}
states, err := XfrmStateList(FAMILY_ALL)
if err != nil {
t.Fatal(err)
}
if len(states) != 1 {
t.Fatal("State not added properly")
}
if !compareStates(state, &states[0]) {
t.Fatalf("unexpected states returned")
}
// Get specific state
sa, err := XfrmStateGet(state)
if err != nil {
t.Fatal(err)
}
if !compareStates(state, sa) {
t.Fatalf("unexpected state returned")
}
if err = XfrmStateDel(state); err != nil {
t.Fatal(err)
}
states, err = XfrmStateList(FAMILY_ALL)
if err != nil {
t.Fatal(err)
}
if len(states) != 0 {
t.Fatal("State not removed properly")
}
if _, err := XfrmStateGet(state); err == nil {
t.Fatalf("Unexpected success")
}
}
func TestXfrmStateFlush(t *testing.T) {
setUpNetlinkTest(t)()
state1 := getBaseState()
state2 := getBaseState()
state2.Src = net.ParseIP("127.1.0.1")
state2.Dst = net.ParseIP("127.1.0.2")
state2.Proto = XFRM_PROTO_AH
state2.Mode = XFRM_MODE_TUNNEL
state2.Spi = 20
state2.Mark = nil
state2.Crypt = nil
if err := XfrmStateAdd(state1); err != nil {
t.Fatal(err)
}
if err := XfrmStateAdd(state2); err != nil {
t.Fatal(err)
}
// flushing proto for which no state is present should return silently
if err := XfrmStateFlush(XFRM_PROTO_COMP); err != nil {
t.Fatal(err)
}
if err := XfrmStateFlush(XFRM_PROTO_AH); err != nil {
t.Fatal(err)
}
if _, err := XfrmStateGet(state2); err == nil {
t.Fatalf("Unexpected success")
}
if err := XfrmStateAdd(state2); err != nil {
t.Fatal(err)
}
if err := XfrmStateFlush(0); err != nil {
t.Fatal(err)
}
states, err := XfrmStateList(FAMILY_ALL)
if err != nil {
t.Fatal(err)
}
if len(states) != 0 {
t.Fatal("State not flushed properly")
}
}
func TestXfrmStateUpdateLimits(t *testing.T) {
setUpNetlinkTest(t)()
// Program state with limits
state := getBaseState()
state.Limits.TimeHard = 3600
state.Limits.TimeSoft = 60
state.Limits.PacketHard = 1000
state.Limits.PacketSoft = 50
state.Limits.ByteHard = 1000000
state.Limits.ByteSoft = 50000
state.Limits.TimeUseHard = 3000
state.Limits.TimeUseSoft = 1500
if err := XfrmStateAdd(state); err != nil {
t.Fatal(err)
}
// Verify limits
s, err := XfrmStateGet(state)
if err != nil {
t.Fatal(err)
}
if !compareLimits(state, s) {
t.Fatalf("Incorrect time hard/soft retrieved: %s", s.Print(true))
}
// Update limits
state.Limits.TimeHard = 1800
state.Limits.TimeSoft = 30
state.Limits.PacketHard = 500
state.Limits.PacketSoft = 25
state.Limits.ByteHard = 500000
state.Limits.ByteSoft = 25000
state.Limits.TimeUseHard = 2000
state.Limits.TimeUseSoft = 1000
if err := XfrmStateUpdate(state); err != nil {
t.Fatal(err)
}
// Verify new limits
s, err = XfrmStateGet(state)
if err != nil {
t.Fatal(err)
}
if s.Limits.TimeHard != 1800 || s.Limits.TimeSoft != 30 {
t.Fatalf("Incorrect time hard retrieved: (%d, %d)", s.Limits.TimeHard, s.Limits.TimeSoft)
}
}
func getBaseState() *XfrmState {
return &XfrmState{
// Force 4 byte notation for the IPv4 addresses
Src: net.ParseIP("127.0.0.1").To4(),
Dst: net.ParseIP("127.0.0.2").To4(),
Proto: XFRM_PROTO_ESP,
Mode: XFRM_MODE_TUNNEL,
Spi: 1,
Auth: &XfrmStateAlgo{
Name: "hmac(sha256)",
Key: []byte("abcdefghijklmnopqrstuvwzyzABCDEF"),
},
Crypt: &XfrmStateAlgo{
Name: "cbc(aes)",
Key: []byte("abcdefghijklmnopqrstuvwzyzABCDEF"),
},
Mark: &XfrmMark{
Value: 0x12340000,
Mask: 0xffff0000,
},
}
}
func getAeadState() *XfrmState {
// 128 key bits + 32 salt bits
k, _ := hex.DecodeString("d0562776bf0e75830ba3f7f8eb6c09b555aa1177")
return &XfrmState{
// Leave IPv4 addresses in Ipv4 in IPv6 notation
Src: net.ParseIP("192.168.1.1"),
Dst: net.ParseIP("192.168.2.2"),
Proto: XFRM_PROTO_ESP,
Mode: XFRM_MODE_TUNNEL,
Spi: 2,
Aead: &XfrmStateAlgo{
Name: "rfc4106(gcm(aes))",
Key: k,
ICVLen: 64,
},
}
}
func compareStates(a, b *XfrmState) bool {
if a == b {
return true
}
if a == nil || b == nil {
return false
}
return a.Src.Equal(b.Src) && a.Dst.Equal(b.Dst) &&
a.Mode == b.Mode && a.Spi == b.Spi && a.Proto == b.Proto &&
compareAlgo(a.Auth, b.Auth) &&
compareAlgo(a.Crypt, b.Crypt) &&
compareAlgo(a.Aead, b.Aead) &&
compareMarks(a.Mark, b.Mark)
}
func compareLimits(a, b *XfrmState) bool {
return a.Limits.TimeHard == b.Limits.TimeHard &&
a.Limits.TimeSoft == b.Limits.TimeSoft &&
a.Limits.PacketHard == b.Limits.PacketHard &&
a.Limits.PacketSoft == b.Limits.PacketSoft &&
a.Limits.ByteHard == b.Limits.ByteHard &&
a.Limits.ByteSoft == b.Limits.ByteSoft &&
a.Limits.TimeUseHard == b.Limits.TimeUseHard &&
a.Limits.TimeUseSoft == b.Limits.TimeUseSoft
}
func compareAlgo(a, b *XfrmStateAlgo) bool {
if a == b {
return true
}
if a == nil || b == nil {
return false
}
return a.Name == b.Name && bytes.Equal(a.Key, b.Key) &&
(a.TruncateLen == 0 || a.TruncateLen == b.TruncateLen) &&
(a.ICVLen == 0 || a.ICVLen == b.ICVLen)
}
func compareMarks(a, b *XfrmMark) bool {
if a == b {
return true
}
if a == nil || b == nil {
return false
}
return a.Value == b.Value && a.Mask == b.Mask
}

View File

@@ -1,51 +0,0 @@
# netns - network namespaces in go #
The netns package provides an ultra-simple interface for handling
network namespaces in go. Changing namespaces requires elevated
privileges, so in most cases this code needs to be run as root.
## Local Build and Test ##
You can use go get command:
go get github.com/vishvananda/netns
Testing (requires root):
sudo -E go test github.com/vishvananda/netns
## Example ##
```go
package main
import (
"fmt"
"net"
"runtime"
"github.com/vishvananda/netns"
)
func main() {
// Lock the OS Thread so we don't accidentally switch namespaces
runtime.LockOSThread()
defer runtime.UnlockOSThread()
// Save the current network namespace
origns, _ := netns.Get()
defer origns.Close()
// Create a new network namespace
newns, _ := netns.New()
netns.Set(newns)
defer newns.Close()
// Do something with the network namespace
ifaces, _ := net.Interfaces()
fmt.Printf("Interfaces: %v\n", ifaces)
// Switch back to the original namespace
netns.Set(origns)
}
```

View File

@@ -1,66 +0,0 @@
package netns
import (
"runtime"
"sync"
"testing"
)
func TestGetNewSetDelete(t *testing.T) {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
origns, err := Get()
if err != nil {
t.Fatal(err)
}
newns, err := New()
if err != nil {
t.Fatal(err)
}
if origns.Equal(newns) {
t.Fatal("New ns failed")
}
if err := Set(origns); err != nil {
t.Fatal(err)
}
newns.Close()
if newns.IsOpen() {
t.Fatal("newns still open after close", newns)
}
ns, err := Get()
if err != nil {
t.Fatal(err)
}
if !ns.Equal(origns) {
t.Fatal("Reset ns failed", origns, newns, ns)
}
}
func TestNone(t *testing.T) {
ns := None()
if ns.IsOpen() {
t.Fatal("None ns is open", ns)
}
}
func TestThreaded(t *testing.T) {
ncpu := runtime.GOMAXPROCS(-1)
if ncpu < 2 {
t.Skip("-cpu=2 or larger required")
}
// Lock this thread simply to ensure other threads get used.
runtime.LockOSThread()
defer runtime.UnlockOSThread()
wg := &sync.WaitGroup{}
for i := 0; i < ncpu; i++ {
wg.Add(1)
go func() {
defer wg.Done()
TestGetNewSetDelete(t)
}()
}
wg.Wait()
}