diff --git a/link_linux.go b/link_linux.go index dae9f16..781e664 100644 --- a/link_linux.go +++ b/link_linux.go @@ -2476,7 +2476,7 @@ func addGeneveAttrs(geneve *Geneve, linkInfo *nl.RtAttr) { } if geneve.ID != 0 { - data.AddRtAttr(nl.IFLA_GENEVE_ID, htonl(geneve.ID)) + data.AddRtAttr(nl.IFLA_GENEVE_ID, nl.Uint32Attr(geneve.ID)) } if geneve.Dport != 0 { @@ -2497,7 +2497,9 @@ func parseGeneveData(link Link, data []syscall.NetlinkRouteAttr) { for _, datum := range data { switch datum.Attr.Type { case nl.IFLA_GENEVE_ID: - geneve.ID = ntohl(datum.Value[0:4]) + geneve.ID = native.Uint32(datum.Value[0:4]) + case nl.IFLA_GENEVE_REMOTE, nl.IFLA_GENEVE_REMOTE6: + geneve.Remote = datum.Value case nl.IFLA_GENEVE_PORT: geneve.Dport = ntohs(datum.Value[0:2]) case nl.IFLA_GENEVE_TTL: diff --git a/link_test.go b/link_test.go index ae1c9c0..b68dbb0 100644 --- a/link_test.go +++ b/link_test.go @@ -4,8 +4,10 @@ package netlink import ( "bytes" + "fmt" "net" "os" + "os/exec" "syscall" "testing" "time" @@ -323,6 +325,10 @@ func compareGeneve(t *testing.T, expected, actual *Geneve) { t.Fatal("Geneve.Tos doesn't match") } + if !actual.Remote.Equal(expected.Remote) { + t.Fatalf("Geneve.Remote is not equal: %s!=%s", actual.Remote, expected.Remote) + } + // TODO: we should implement the rest of the geneve methods } @@ -623,6 +629,45 @@ func TestLinkAddDelGeneve(t *testing.T) { Remote: net.ParseIP("2001:db8:ef33::2")}) } +func TestGeneveCompareToIP(t *testing.T) { + ns, tearDown := setUpNamedNetlinkTest(t) + defer tearDown() + + expected := &Geneve{ + ID: 0x764332, // 23 bits + Remote: net.ParseIP("1.2.3.4"), + Dport: 6081, + } + + // Create interface + cmd := exec.Command("ip", "netns", "exec", ns, + "ip", "link", "add", "gen0", + "type", "geneve", + "vni", fmt.Sprint(expected.ID), + "remote", expected.Remote.String(), + // TODO: unit tests are currently done on ubuntu 16, and the version of iproute2 there doesn't support dstport + // We can still do most of the testing by verifying that we do read the default port + // "dstport", fmt.Sprint(expected.Dport), + ) + out := &bytes.Buffer{} + cmd.Stdout = out + cmd.Stderr = out + + if rc := cmd.Run(); rc != nil { + t.Fatal("failed creating link:", rc, out.String()) + } + + link, err := LinkByName("gen0") + if err != nil { + t.Fatal("Failed getting link: ", err) + } + actual, ok := link.(*Geneve) + if !ok { + t.Fatalf("resulted interface is not geneve: %T", link) + } + compareGeneve(t, expected, actual) +} + func TestLinkAddDelGretap(t *testing.T) { tearDown := setUpNetlinkTest(t) defer tearDown() diff --git a/netlink_test.go b/netlink_test.go index f64c84e..aed1167 100644 --- a/netlink_test.go +++ b/netlink_test.go @@ -4,6 +4,8 @@ package netlink import ( "bytes" + "crypto/rand" + "encoding/hex" "fmt" "io/ioutil" "log" @@ -43,6 +45,43 @@ func setUpNetlinkTest(t *testing.T) tearDownNetlinkTest { } } +// setUpNamedNetlinkTest create a temporary named names space with a random name +func setUpNamedNetlinkTest(t *testing.T) (string, tearDownNetlinkTest) { + skipUnlessRoot(t) + + origNS, err := netns.Get() + if err != nil { + t.Fatal("Failed saving orig namespace") + } + + // create a random name + rnd := make([]byte, 4) + if _, err := rand.Read(rnd); err != nil { + t.Fatal("failed creating random ns name") + } + name := "netlinktest-" + hex.EncodeToString(rnd) + + ns, err := netns.NewNamed(name) + if err != nil { + t.Fatal("Failed to create new ns", err) + } + + runtime.LockOSThread() + cleanup := func() { + ns.Close() + netns.DeleteNamed(name) + netns.Set(origNS) + runtime.UnlockOSThread() + } + + if err := netns.Set(ns); err != nil { + cleanup() + t.Fatal("Failed entering new namespace", err) + } + + return name, cleanup +} + func setUpNetlinkTestWithLoopback(t *testing.T) tearDownNetlinkTest { skipUnlessRoot(t)