github.com/gopacket/gopacket@v1.1.0/layers/geneve.go (about)

     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  	"fmt"
    13  
    14  	"github.com/gopacket/gopacket"
    15  )
    16  
    17  // Geneve is specifed here https://tools.ietf.org/html/draft-ietf-nvo3-geneve-03
    18  // Geneve Header:
    19  //
    20  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    21  //	|Ver|  Opt Len  |O|C|    Rsvd.  |          Protocol Type        |
    22  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    23  //	|        Virtual Network Identifier (VNI)       |    Reserved   |
    24  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    25  //	|                    Variable Length Options                    |
    26  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    27  type Geneve struct {
    28  	BaseLayer
    29  	Version        uint8        // 2 bits
    30  	OptionsLength  uint8        // 6 bits
    31  	OAMPacket      bool         // 1 bits
    32  	CriticalOption bool         // 1 bits
    33  	Protocol       EthernetType // 16 bits
    34  	VNI            uint32       // 24bits
    35  	Options        []*GeneveOption
    36  }
    37  
    38  // Geneve Tunnel Options
    39  //
    40  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    41  //	|          Option Class         |      Type     |R|R|R| Length  |
    42  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    43  //	|                      Variable Option Data                     |
    44  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    45  type GeneveOption struct {
    46  	Class  uint16 // 16 bits
    47  	Type   uint8  // 8 bits
    48  	Flags  uint8  // 3 bits
    49  	Length uint8  // 5 bits
    50  	Data   []byte
    51  }
    52  
    53  // LayerType returns LayerTypeGeneve
    54  func (gn *Geneve) LayerType() gopacket.LayerType { return LayerTypeGeneve }
    55  
    56  func decodeGeneveOption(data []byte, gn *Geneve, df gopacket.DecodeFeedback) (*GeneveOption, uint8, error) {
    57  	if len(data) < 3 {
    58  		df.SetTruncated()
    59  		return nil, 0, errors.New("geneve option too small")
    60  	}
    61  	opt := &GeneveOption{}
    62  
    63  	opt.Class = binary.BigEndian.Uint16(data[0:2])
    64  	opt.Type = data[2]
    65  	opt.Flags = data[3] >> 4
    66  	opt.Length = (data[3]&0xf)*4 + 4
    67  
    68  	if len(data) < int(opt.Length) {
    69  		df.SetTruncated()
    70  		return nil, 0, errors.New("geneve option too small")
    71  	}
    72  	opt.Data = make([]byte, opt.Length-4)
    73  	copy(opt.Data, data[4:opt.Length])
    74  
    75  	return opt, opt.Length, nil
    76  }
    77  
    78  func (gn *Geneve) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
    79  	if len(data) < 7 {
    80  		df.SetTruncated()
    81  		return errors.New("geneve packet too short")
    82  	}
    83  
    84  	gn.Version = data[0] >> 7
    85  	gn.OptionsLength = (data[0] & 0x3f) * 4
    86  
    87  	gn.OAMPacket = data[1]&0x80 > 0
    88  	gn.CriticalOption = data[1]&0x40 > 0
    89  	gn.Protocol = EthernetType(binary.BigEndian.Uint16(data[2:4]))
    90  
    91  	var buf [4]byte
    92  	copy(buf[1:], data[4:7])
    93  	gn.VNI = binary.BigEndian.Uint32(buf[:])
    94  
    95  	offset, length := uint8(8), int32(gn.OptionsLength)
    96  	if len(data) < int(length+7) {
    97  		df.SetTruncated()
    98  		return errors.New("geneve packet too short")
    99  	}
   100  
   101  	for length > 0 {
   102  		opt, len, err := decodeGeneveOption(data[offset:], gn, df)
   103  		if err != nil {
   104  			return err
   105  		}
   106  		gn.Options = append(gn.Options, opt)
   107  
   108  		length -= int32(len)
   109  		offset += len
   110  	}
   111  
   112  	gn.BaseLayer = BaseLayer{data[:offset], data[offset:]}
   113  
   114  	return nil
   115  }
   116  
   117  func (gn *Geneve) NextLayerType() gopacket.LayerType {
   118  	return gn.Protocol.LayerType()
   119  }
   120  
   121  func decodeGeneve(data []byte, p gopacket.PacketBuilder) error {
   122  	gn := &Geneve{}
   123  	return decodingLayerDecoder(gn, data, p)
   124  }
   125  
   126  // SerializeTo writes the serialized form of this layer into the
   127  // SerializationBuffer, implementing gopacket.SerializableLayer.
   128  // See the docs for gopacket.SerializableLayer for more info.
   129  func (gn *Geneve) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
   130  	var optionsLength int
   131  	for _, o := range gn.Options {
   132  		dataLen := len(o.Data) & ^3
   133  		optionsLength += 4 + dataLen
   134  	}
   135  	if opts.FixLengths {
   136  		gn.OptionsLength = uint8(optionsLength)
   137  	}
   138  
   139  	plen := int(8 + optionsLength)
   140  	bytes, err := b.PrependBytes(plen)
   141  	if err != nil {
   142  		return err
   143  	}
   144  
   145  	// PrependBytes does not guarantee that bytes are zeroed.  Setting flags via OR requires that they start off at zero
   146  	bytes[0] = 0
   147  	bytes[1] = 0
   148  
   149  	// Construct Geneve
   150  
   151  	bytes[0] |= gn.Version << 6
   152  	bytes[0] |= ((gn.OptionsLength >> 2) & 0x3f)
   153  
   154  	if gn.OAMPacket {
   155  		bytes[1] |= 0x80
   156  	}
   157  
   158  	if gn.CriticalOption {
   159  		bytes[1] |= 0x40
   160  	}
   161  
   162  	binary.BigEndian.PutUint16(bytes[2:4], uint16(gn.Protocol))
   163  
   164  	if gn.VNI >= 1<<24 {
   165  		return fmt.Errorf("Virtual Network Identifier = %x exceeds max for 24-bit uint", gn.VNI)
   166  	}
   167  	binary.BigEndian.PutUint32(bytes[4:8], gn.VNI<<8)
   168  
   169  	// Construct Options
   170  
   171  	offset := 8
   172  	for _, o := range gn.Options {
   173  		dataLen := len(o.Data) & ^3
   174  		if opts.FixLengths {
   175  			o.Length = uint8(4 + dataLen)
   176  		}
   177  
   178  		binary.BigEndian.PutUint16(bytes[offset:(offset+2)], uint16(o.Class))
   179  
   180  		offset += 2
   181  		bytes[offset] = o.Type
   182  
   183  		offset += 1
   184  		bytes[offset] |= o.Flags << 5
   185  		bytes[offset] |= ((o.Length - 4) >> 2) & 0x1f
   186  
   187  		offset += 1
   188  		copy(bytes[offset:(offset+dataLen)], o.Data)
   189  
   190  		offset += dataLen
   191  	}
   192  
   193  	return nil
   194  }