Skip to content

Commit 4e29164

Browse files
retr0hgconnell
authored andcommitted
Add Geneve SerializeTo support
Added missing SerializeTo functionality to Geneve. Fixes: #1043
1 parent 3eaba08 commit 4e29164

File tree

2 files changed

+94
-1
lines changed

2 files changed

+94
-1
lines changed

layers/geneve.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ package layers
99
import (
1010
"encoding/binary"
1111
"errors"
12+
"fmt"
1213

1314
"github.com/google/gopacket"
1415
)
@@ -119,3 +120,59 @@ func decodeGeneve(data []byte, p gopacket.PacketBuilder) error {
119120
gn := &Geneve{}
120121
return decodingLayerDecoder(gn, data, p)
121122
}
123+
124+
// SerializeTo writes the serialized form of this layer into the
125+
// SerializationBuffer, implementing gopacket.SerializableLayer.
126+
// See the docs for gopacket.SerializableLayer for more info.
127+
func (gn *Geneve) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
128+
plen := int(gn.OptionsLength + 8)
129+
bytes, err := b.PrependBytes(plen)
130+
if err != nil {
131+
return err
132+
}
133+
134+
// PrependBytes does not guarantee that bytes are zeroed. Setting flags via OR requires that they start off at zero
135+
bytes[0] = 0
136+
bytes[1] = 0
137+
138+
// Construct Geneve
139+
140+
bytes[0] |= gn.Version << 6
141+
bytes[0] |= ((gn.OptionsLength >> 2) & 0x3f)
142+
143+
if gn.OAMPacket {
144+
bytes[1] |= 0x80
145+
}
146+
147+
if gn.CriticalOption {
148+
bytes[1] |= 0x40
149+
}
150+
151+
binary.BigEndian.PutUint16(bytes[2:4], uint16(gn.Protocol))
152+
153+
if gn.VNI >= 1<<24 {
154+
return fmt.Errorf("Virtual Network Identifier = %x exceeds max for 24-bit uint", gn.VNI)
155+
}
156+
binary.BigEndian.PutUint32(bytes[4:8], gn.VNI<<8)
157+
158+
// Construct Options
159+
160+
offset, _ := uint8(8), int32(gn.OptionsLength)
161+
for _, o := range gn.Options {
162+
binary.BigEndian.PutUint16(bytes[offset:(offset+2)], uint16(o.Class))
163+
164+
offset += 2
165+
bytes[offset] = o.Type
166+
167+
offset += 1
168+
bytes[offset] |= o.Flags << 5
169+
bytes[offset] |= ((o.Length - 4) >> 2) & 0x1f
170+
171+
offset += 1
172+
copy(bytes[offset:(offset+o.Length-4)], o.Data)
173+
174+
offset += o.Length - 4
175+
}
176+
177+
return nil
178+
}

layers/geneve_test.go

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ func TestDecodeGeneve3(t *testing.T) {
136136
Protocol: EthernetTypeTransparentEthernetBridging,
137137
VNI: 0xa,
138138
Options: []*GeneveOption{
139-
&GeneveOption{
139+
{
140140
Class: 0x0,
141141
Type: 0x80,
142142
Length: 8,
@@ -155,3 +155,39 @@ func BenchmarkDecodeGeneve1(b *testing.B) {
155155
gopacket.NewPacket(testPacketGeneve1, LinkTypeEthernet, gopacket.NoCopy)
156156
}
157157
}
158+
159+
func TestIsomorphicPacketGeneve(t *testing.T) {
160+
gn := &Geneve{
161+
Version: 0x0,
162+
OptionsLength: 0x14,
163+
OAMPacket: false,
164+
CriticalOption: true,
165+
Protocol: EthernetTypeTransparentEthernetBridging,
166+
VNI: 0xa,
167+
Options: []*GeneveOption{
168+
{
169+
Class: 0x0,
170+
Type: 0x80,
171+
Length: 12,
172+
Data: []byte{0, 0, 0, 0, 0, 0, 0, 0xc},
173+
},
174+
{
175+
Class: 0x0,
176+
Type: 0x80,
177+
Length: 8,
178+
Data: []byte{0, 0, 0, 0xc},
179+
},
180+
},
181+
}
182+
183+
b := gopacket.NewSerializeBuffer()
184+
gn.SerializeTo(b, gopacket.SerializeOptions{})
185+
186+
p := gopacket.NewPacket(b.Bytes(), gopacket.DecodeFunc(decodeGeneve), gopacket.Default)
187+
gnTranslated := p.Layer(LayerTypeGeneve).(*Geneve)
188+
gnTranslated.BaseLayer = BaseLayer{}
189+
190+
if !reflect.DeepEqual(gn, gnTranslated) {
191+
t.Errorf("VXLAN isomorph mismatch, \nwant %#v\ngot %#v\n", gn, gnTranslated)
192+
}
193+
}

0 commit comments

Comments
 (0)