Skip to content

Commit

Permalink
Add Geneve link support
Browse files Browse the repository at this point in the history
Heavily based on the existing Gretap support
  • Loading branch information
shassard authored and aboch committed Nov 22, 2020
1 parent e440572 commit d185ffd
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 0 deletions.
24 changes: 24 additions & 0 deletions link.go
Original file line number Diff line number Diff line change
Expand Up @@ -851,6 +851,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
UdpZeroCsum6Tx uint8
UdpZeroCsum6Rx 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
Expand Down
56 changes: 56 additions & 0 deletions link_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -1404,6 +1404,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:
Expand Down Expand Up @@ -1667,6 +1669,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":
Expand Down Expand Up @@ -1716,6 +1720,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":
Expand Down Expand Up @@ -2452,6 +2458,56 @@ 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))
}
}

if geneve.ID != 0 {
data.AddRtAttr(nl.IFLA_GENEVE_ID, htonl(geneve.ID))
}

if geneve.Dport != 0 {
data.AddRtAttr(nl.IFLA_GENEVE_PORT, htons(geneve.Dport))
}

if geneve.Ttl != 0 {
data.AddRtAttr(nl.IFLA_GENEVE_TTL, nl.Uint8Attr(geneve.Ttl))
}

if geneve.Tos != 0 {
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:
geneve.ID = ntohl(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)

Expand Down
48 changes: 48 additions & 0 deletions link_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -293,6 +301,31 @@ 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)
}

// set the Dport to 6081 (the linux default) if it wasn't specified at creation
if expected.Dport == 0 {
expected.Dport = 6081
}

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")
Expand Down Expand Up @@ -575,6 +608,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", EncapType: "geneve"},
ID: 0x1000,
Remote: net.IPv4(127, 0, 0, 1)})

testLinkAddDel(t, &Geneve{
LinkAttrs: LinkAttrs{Name: "foo6", EncapType: "geneve"},
ID: 0x1000,
Remote: net.ParseIP("2001:db8:ef33::2")})
}

func TestLinkAddDelGretap(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
Expand Down
16 changes: 16 additions & 0 deletions nl/link_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,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
Expand Down

0 comments on commit d185ffd

Please sign in to comment.