| // Copyright 2016 Google, Inc. All rights reserved. |
| // |
| // Use of this source code is governed by a BSD-style license |
| // that can be found in the LICENSE file in the root of the source |
| // tree. |
| |
| package layers |
| |
| import ( |
| "encoding/binary" |
| "errors" |
| |
| "github.com/google/gopacket" |
| ) |
| |
| // Geneve is specifed here https://tools.ietf.org/html/draft-ietf-nvo3-geneve-03 |
| // Geneve Header: |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| // |Ver| Opt Len |O|C| Rsvd. | Protocol Type | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| // | Virtual Network Identifier (VNI) | Reserved | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| // | Variable Length Options | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| type Geneve struct { |
| BaseLayer |
| Version uint8 // 2 bits |
| OptionsLength uint8 // 6 bits |
| OAMPacket bool // 1 bits |
| CriticalOption bool // 1 bits |
| Protocol EthernetType // 16 bits |
| VNI uint32 // 24bits |
| Options []*GeneveOption |
| } |
| |
| // Geneve Tunnel Options |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| // | Option Class | Type |R|R|R| Length | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| // | Variable Option Data | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| type GeneveOption struct { |
| Class uint16 // 16 bits |
| Type uint8 // 8 bits |
| Flags uint8 // 3 bits |
| Length uint8 // 5 bits |
| Data []byte |
| } |
| |
| // LayerType returns LayerTypeGeneve |
| func (gn *Geneve) LayerType() gopacket.LayerType { return LayerTypeGeneve } |
| |
| func decodeGeneveOption(data []byte, gn *Geneve, df gopacket.DecodeFeedback) (*GeneveOption, uint8, error) { |
| if len(data) < 3 { |
| df.SetTruncated() |
| return nil, 0, errors.New("geneve option too small") |
| } |
| opt := &GeneveOption{} |
| |
| opt.Class = binary.BigEndian.Uint16(data[0:2]) |
| opt.Type = data[2] |
| opt.Flags = data[3] >> 4 |
| opt.Length = (data[3]&0xf)*4 + 4 |
| |
| if len(data) < int(opt.Length) { |
| df.SetTruncated() |
| return nil, 0, errors.New("geneve option too small") |
| } |
| opt.Data = make([]byte, opt.Length-4) |
| copy(opt.Data, data[4:opt.Length]) |
| |
| return opt, opt.Length, nil |
| } |
| |
| func (gn *Geneve) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { |
| if len(data) < 7 { |
| df.SetTruncated() |
| return errors.New("geneve packet too short") |
| } |
| |
| gn.Version = data[0] >> 7 |
| gn.OptionsLength = (data[0] & 0x3f) * 4 |
| |
| gn.OAMPacket = data[1]&0x80 > 0 |
| gn.CriticalOption = data[1]&0x40 > 0 |
| gn.Protocol = EthernetType(binary.BigEndian.Uint16(data[2:4])) |
| |
| var buf [4]byte |
| copy(buf[1:], data[4:7]) |
| gn.VNI = binary.BigEndian.Uint32(buf[:]) |
| |
| offset, length := uint8(8), int32(gn.OptionsLength) |
| if len(data) < int(length+7) { |
| df.SetTruncated() |
| return errors.New("geneve packet too short") |
| } |
| |
| for length > 0 { |
| opt, len, err := decodeGeneveOption(data[offset:], gn, df) |
| if err != nil { |
| return err |
| } |
| gn.Options = append(gn.Options, opt) |
| |
| length -= int32(len) |
| offset += len |
| } |
| |
| gn.BaseLayer = BaseLayer{data[:offset], data[offset:]} |
| |
| return nil |
| } |
| |
| func (gn *Geneve) NextLayerType() gopacket.LayerType { |
| return gn.Protocol.LayerType() |
| } |
| |
| func decodeGeneve(data []byte, p gopacket.PacketBuilder) error { |
| gn := &Geneve{} |
| return decodingLayerDecoder(gn, data, p) |
| } |