Add Geneve link support

Heavily based on the existing Gretap support
This commit is contained in:
Stephen Hassard 2020-09-23 18:53:16 -07:00 committed by Alessandro Boch
parent e440572571
commit d185ffdb62
4 changed files with 144 additions and 0 deletions

24
link.go
View File

@ -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

View File

@ -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:
@ -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":
@ -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":
@ -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)

View File

@ -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,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")
@ -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()

View File

@ -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