Matteo Scandolo | a6a3aee | 2019-11-26 13:30:14 -0700 | [diff] [blame] | 1 | // Copyright 2016 Google, Inc. All rights reserved. |
| 2 | // |
| 3 | // Use of this source code is governed by a BSD-style license |
| 4 | // that can be found in the LICENSE file in the root of the source |
| 5 | // tree. |
| 6 | |
| 7 | package layers |
| 8 | |
| 9 | import ( |
| 10 | "encoding/binary" |
| 11 | "errors" |
| 12 | |
| 13 | "github.com/google/gopacket" |
| 14 | ) |
| 15 | |
| 16 | // Geneve is specifed here https://tools.ietf.org/html/draft-ietf-nvo3-geneve-03 |
| 17 | // Geneve Header: |
| 18 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 19 | // |Ver| Opt Len |O|C| Rsvd. | Protocol Type | |
| 20 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 21 | // | Virtual Network Identifier (VNI) | Reserved | |
| 22 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 23 | // | Variable Length Options | |
| 24 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 25 | type Geneve struct { |
| 26 | BaseLayer |
| 27 | Version uint8 // 2 bits |
| 28 | OptionsLength uint8 // 6 bits |
| 29 | OAMPacket bool // 1 bits |
| 30 | CriticalOption bool // 1 bits |
| 31 | Protocol EthernetType // 16 bits |
| 32 | VNI uint32 // 24bits |
| 33 | Options []*GeneveOption |
| 34 | } |
| 35 | |
| 36 | // Geneve Tunnel Options |
| 37 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 38 | // | Option Class | Type |R|R|R| Length | |
| 39 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 40 | // | Variable Option Data | |
| 41 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 42 | type GeneveOption struct { |
| 43 | Class uint16 // 16 bits |
| 44 | Type uint8 // 8 bits |
| 45 | Flags uint8 // 3 bits |
| 46 | Length uint8 // 5 bits |
| 47 | Data []byte |
| 48 | } |
| 49 | |
| 50 | // LayerType returns LayerTypeGeneve |
| 51 | func (gn *Geneve) LayerType() gopacket.LayerType { return LayerTypeGeneve } |
| 52 | |
| 53 | func decodeGeneveOption(data []byte, gn *Geneve) (*GeneveOption, uint8) { |
| 54 | opt := &GeneveOption{} |
| 55 | |
| 56 | opt.Class = binary.BigEndian.Uint16(data[0:2]) |
| 57 | opt.Type = data[2] |
| 58 | opt.Flags = data[3] >> 4 |
| 59 | opt.Length = (data[3]&0xf)*4 + 4 |
| 60 | |
| 61 | opt.Data = make([]byte, opt.Length-4) |
| 62 | copy(opt.Data, data[4:opt.Length]) |
| 63 | |
| 64 | return opt, opt.Length |
| 65 | } |
| 66 | |
| 67 | func (gn *Geneve) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { |
| 68 | if len(data) < 7 { |
| 69 | df.SetTruncated() |
| 70 | return errors.New("geneve packet too short") |
| 71 | } |
| 72 | |
| 73 | gn.Version = data[0] >> 7 |
| 74 | gn.OptionsLength = (data[0] & 0x3f) * 4 |
| 75 | |
| 76 | gn.OAMPacket = data[1]&0x80 > 0 |
| 77 | gn.CriticalOption = data[1]&0x40 > 0 |
| 78 | gn.Protocol = EthernetType(binary.BigEndian.Uint16(data[2:4])) |
| 79 | |
| 80 | var buf [4]byte |
| 81 | copy(buf[1:], data[4:7]) |
| 82 | gn.VNI = binary.BigEndian.Uint32(buf[:]) |
| 83 | |
| 84 | offset, length := uint8(8), int32(gn.OptionsLength) |
| 85 | if len(data) < int(length+7) { |
| 86 | df.SetTruncated() |
| 87 | return errors.New("geneve packet too short") |
| 88 | } |
| 89 | |
| 90 | for length > 0 { |
| 91 | opt, len := decodeGeneveOption(data[offset:], gn) |
| 92 | gn.Options = append(gn.Options, opt) |
| 93 | |
| 94 | length -= int32(len) |
| 95 | offset += len |
| 96 | } |
| 97 | |
| 98 | gn.BaseLayer = BaseLayer{data[:offset], data[offset:]} |
| 99 | |
| 100 | return nil |
| 101 | } |
| 102 | |
| 103 | func (gn *Geneve) NextLayerType() gopacket.LayerType { |
| 104 | return gn.Protocol.LayerType() |
| 105 | } |
| 106 | |
| 107 | func decodeGeneve(data []byte, p gopacket.PacketBuilder) error { |
| 108 | gn := &Geneve{} |
| 109 | return decodingLayerDecoder(gn, data, p) |
| 110 | } |