diff --git a/go.mod b/go.mod index 9d8455ee7..703322719 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,6 @@ module github.com/vishvananda/netlink go 1.12 require ( - github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae - golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1 + github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df + golang.org/x/sys v0.0.0-20200121082415-34d275377bf9 ) diff --git a/go.sum b/go.sum index ed5d30891..28cda557e 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,4 @@ -github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae h1:4hwBBUfQCFe3Cym0ZtKyq7L16eZUtYKs+BaHDN6mAns= -github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= -golang.org/x/sys v0.0.0-20200217220822-9197077df867 h1:JoRuNIf+rpHl+VhScRQQvzbHed86tKkqwPMV34T8myw= -golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1 h1:sIky/MyNRSHTrdxfsiUSS4WIAMvInbeXljJz+jDjeYE= -golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df h1:OviZH7qLw/7ZovXvuNyL3XQl8UFofeikI1NW1Gypu7k= +github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= +golang.org/x/sys v0.0.0-20200121082415-34d275377bf9 h1:N19i1HjUnR7TF7rMt8O4p3dLvqvmYyzB6ifMFmrbY50= +golang.org/x/sys v0.0.0-20200121082415-34d275377bf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/link.go b/link.go index c9d960db7..fb7f45d87 100644 --- a/link.go +++ b/link.go @@ -834,6 +834,30 @@ func (b *BondSlave) SlaveType() string { return "bond" } +// Geneve devices must specify RemoteIP and ID (VNI) on create +// https://github.com/torvalds/linux/blob/47ec5303d73ea344e84f46660fff693c57641386/drivers/net/geneve.c#L1209-L1223 +type Geneve struct { + LinkAttrs + ID uint32 // vni + Remote net.IP + Ttl uint8 + Tos uint8 + Dport uint16 + UdpCsum uint8 + UdpZeroCsum6_Tx uint8 + UdpZeroCsum6_Rx uint8 + Link uint32 + FlowBased bool +} + +func (geneve *Geneve) Attrs() *LinkAttrs { + return &geneve.LinkAttrs +} + +func (geneve *Geneve) Type() string { + return "geneve" +} + // Gretap devices must specify LocalIP and RemoteIP on create type Gretap struct { LinkAttrs diff --git a/link_linux.go b/link_linux.go index 53cc08ef9..8cd72e092 100644 --- a/link_linux.go +++ b/link_linux.go @@ -1373,6 +1373,8 @@ func (h *Handle) linkModify(link Link, flags int) error { data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) data.AddRtAttr(nl.IFLA_MACVLAN_MODE, nl.Uint32Attr(macvlanModes[link.Mode])) } + case *Geneve: + addGeneveAttrs(link, linkInfo) case *Gretap: addGretapAttrs(link, linkInfo) case *Iptun: @@ -1636,6 +1638,8 @@ func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) { link = &Macvlan{} case "macvtap": link = &Macvtap{} + case "geneve": + link = &Geneve{} case "gretap": link = &Gretap{} case "ip6gretap": @@ -1683,6 +1687,8 @@ func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) { parseMacvlanData(link, data) case "macvtap": parseMacvtapData(link, data) + case "geneve": + parseGeneveData(link, data) case "gretap": parseGretapData(link, data) case "ip6gretap": @@ -2417,6 +2423,45 @@ func linkFlags(rawFlags uint32) net.Flags { return f } +func addGeneveAttrs(geneve *Geneve, linkInfo *nl.RtAttr) { + data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) + + if geneve.FlowBased { + // In flow based mode, no other attributes need to be configured + linkInfo.AddRtAttr(nl.IFLA_GENEVE_COLLECT_METADATA, boolAttr(geneve.FlowBased)) + return + } + + if ip := geneve.Remote; ip != nil { + if ip4 := ip.To4(); ip4 != nil { + data.AddRtAttr(nl.IFLA_GENEVE_REMOTE, []byte(ip)) + } else { + data.AddRtAttr(nl.IFLA_GENEVE_REMOTE6, []byte(ip)) + } + } + + data.AddRtAttr(nl.IFLA_GENEVE_ID, nl.Uint32Attr(geneve.ID)) + data.AddRtAttr(nl.IFLA_GENEVE_PORT, htons(geneve.Dport)) + data.AddRtAttr(nl.IFLA_GENEVE_TTL, nl.Uint8Attr(geneve.Ttl)) + data.AddRtAttr(nl.IFLA_GENEVE_TOS, nl.Uint8Attr(geneve.Tos)) +} + +func parseGeneveData(link Link, data []syscall.NetlinkRouteAttr) { + geneve := link.(*Geneve) + for _, datum := range data { + switch datum.Attr.Type { + case nl.IFLA_GENEVE_ID: + native.Uint32(datum.Value[0:4]) + case nl.IFLA_GENEVE_PORT: + geneve.Dport = ntohs(datum.Value[0:2]) + case nl.IFLA_GENEVE_TTL: + geneve.Ttl = uint8(datum.Value[0]) + case nl.IFLA_GENEVE_TOS: + geneve.Tos = uint8(datum.Value[0]) + } + } +} + func addGretapAttrs(gretap *Gretap, linkInfo *nl.RtAttr) { data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) diff --git a/link_test.go b/link_test.go index 8911af89c..63c28bbd3 100644 --- a/link_test.go +++ b/link_test.go @@ -245,6 +245,14 @@ func testLinkAddDel(t *testing.T, link Link) { } } + if geneve, ok := link.(*Geneve); ok { + other, ok := result.(*Geneve) + if !ok { + t.Fatal("Result of create is not a Geneve") + } + compareGeneve(t, geneve, other) + } + if gretap, ok := link.(*Gretap); ok { other, ok := result.(*Gretap) if !ok { @@ -293,6 +301,26 @@ func testLinkAddDel(t *testing.T, link Link) { } } +func compareGeneve(t *testing.T, expected, actual *Geneve) { + if actual.ID != expected.ID { + t.Fatalf("Geneve.ID doesn't match: %d %d", actual.ID, expected.ID) + } + + if actual.Dport != expected.Dport { + t.Fatal("Geneve.Dport doesn't match") + } + + if actual.Ttl != expected.Ttl { + t.Fatal("Geneve.Ttl doesn't match") + } + + if actual.Tos != expected.Tos { + t.Fatal("Geneve.Tos doesn't match") + } + + // TODO: we should implement the rest of the geneve methods +} + func compareGretap(t *testing.T, expected, actual *Gretap) { if actual.IKey != expected.IKey { t.Fatal("Gretap.IKey doesn't match") @@ -575,6 +603,21 @@ func TestLinkAddDelBridge(t *testing.T) { testLinkAddDel(t, &Bridge{LinkAttrs: LinkAttrs{Name: "foo", MTU: 1400}}) } +func TestLinkAddDelGeneve(t *testing.T) { + tearDown := setUpNetlinkTest(t) + defer tearDown() + + testLinkAddDel(t, &Geneve{ + LinkAttrs: LinkAttrs{Name: "foo4"}, + ID: 0x01, + Remote: net.IPv4(127, 0, 0, 1)}) + + testLinkAddDel(t, &Geneve{ + LinkAttrs: LinkAttrs{Name: "foo6"}, + ID: 0x01, + Remote: net.ParseIP("2001:db8:ef33::2")}) +} + func TestLinkAddDelGretap(t *testing.T) { tearDown := setUpNetlinkTest(t) defer tearDown() diff --git a/nl/link_linux.go b/nl/link_linux.go index 5cb166c13..a7992559d 100644 --- a/nl/link_linux.go +++ b/nl/link_linux.go @@ -171,6 +171,22 @@ const ( IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE ) +const ( + IFLA_GENEVE_UNSPEC = iota + IFLA_GENEVE_ID // vni + IFLA_GENEVE_REMOTE + IFLA_GENEVE_TTL + IFLA_GENEVE_TOS + IFLA_GENEVE_PORT // destination port + IFLA_GENEVE_COLLECT_METADATA + IFLA_GENEVE_REMOTE6 + IFLA_GENEVE_UDP_CSUM + IFLA_GENEVE_UDP_ZERO_CSUM6_TX + IFLA_GENEVE_UDP_ZERO_CSUM6_RX + IFLA_GENEVE_LABEL + IFLA_GENEVE_MAX = IFLA_GENEVE_LABEL +) + const ( IFLA_GRE_UNSPEC = iota IFLA_GRE_LINK