[VOL-1349] EPON OLT adapter (package B)

Change-Id: I634ef62c53813dcf4456f54948f13e06358e263c
diff --git a/vendor/github.com/google/gopacket/layers/sflow.go b/vendor/github.com/google/gopacket/layers/sflow.go
new file mode 100644
index 0000000..c56fe89
--- /dev/null
+++ b/vendor/github.com/google/gopacket/layers/sflow.go
@@ -0,0 +1,2480 @@
+// Copyright 2014 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.
+
+/*
+This layer decodes SFlow version 5 datagrams.
+
+The specification can be found here: http://sflow.org/sflow_version_5.txt
+
+Additional developer information about sflow can be found at:
+http://sflow.org/developers/specifications.php
+
+And SFlow in general:
+http://sflow.org/index.php
+
+Two forms of sample data are defined: compact and expanded. The
+Specification has this to say:
+
+    Compact and expand forms of counter and flow samples are defined.
+    An agent must not mix compact/expanded encodings.  If an agent
+    will never use ifIndex numbers >= 2^24 then it must use compact
+    encodings for all interfaces.  Otherwise the expanded formats must
+    be used for all interfaces.
+
+This decoder only supports the compact form, because that is the only
+one for which data was avaialble.
+
+The datagram is composed of one or more samples of type flow or counter,
+and each sample is composed of one or more records describing the sample.
+A sample is a single instance of sampled inforamtion, and each record in
+the sample gives additional / supplimentary information about the sample.
+
+The following sample record types are supported:
+
+	Raw Packet Header
+	opaque = flow_data; enterprise = 0; format = 1
+
+	Extended Switch Data
+	opaque = flow_data; enterprise = 0; format = 1001
+
+	Extended Router Data
+	opaque = flow_data; enterprise = 0; format = 1002
+
+	Extended Gateway Data
+	opaque = flow_data; enterprise = 0; format = 1003
+
+	Extended User Data
+	opaque = flow_data; enterprise = 0; format = 1004
+
+	Extended URL Data
+	opaque = flow_data; enterprise = 0; format = 1005
+
+The following types of counter records are supported:
+
+	Generic Interface Counters - see RFC 2233
+	opaque = counter_data; enterprise = 0; format = 1
+
+	Ethernet Interface Counters - see RFC 2358
+	opaque = counter_data; enterprise = 0; format = 2
+
+SFlow is encoded using XDR (RFC4506). There are a few places
+where the standard 4-byte fields are partitioned into two
+bitfields of different lengths. I'm not sure why the designers
+chose to pack together two values like this in some places, and
+in others they use the entire 4-byte value to store a number that
+will never be more than a few bits. In any case, there are a couple
+of types defined to handle the decoding of these bitfields, and
+that's why they're there. */
+
+package layers
+
+import (
+	"encoding/binary"
+	"errors"
+	"fmt"
+	"net"
+
+	"github.com/google/gopacket"
+)
+
+// SFlowRecord holds both flow sample records and counter sample records.
+// A Record is the structure that actually holds the sampled data
+// and / or counters.
+type SFlowRecord interface {
+}
+
+// SFlowDataSource encodes a 2-bit SFlowSourceFormat in its most significant
+// 2 bits, and an SFlowSourceValue in its least significant 30 bits.
+// These types and values define the meaning of the inteface information
+// presented in the sample metadata.
+type SFlowDataSource int32
+
+func (sdc SFlowDataSource) decode() (SFlowSourceFormat, SFlowSourceValue) {
+	leftField := sdc >> 30
+	rightField := uint32(0x3FFFFFFF) & uint32(sdc)
+	return SFlowSourceFormat(leftField), SFlowSourceValue(rightField)
+}
+
+type SFlowDataSourceExpanded struct {
+	SourceIDClass SFlowSourceFormat
+	SourceIDIndex SFlowSourceValue
+}
+
+func (sdce SFlowDataSourceExpanded) decode() (SFlowSourceFormat, SFlowSourceValue) {
+	leftField := sdce.SourceIDClass >> 30
+	rightField := uint32(0x3FFFFFFF) & uint32(sdce.SourceIDIndex)
+	return SFlowSourceFormat(leftField), SFlowSourceValue(rightField)
+}
+
+type SFlowSourceFormat uint32
+
+type SFlowSourceValue uint32
+
+const (
+	SFlowTypeSingleInterface      SFlowSourceFormat = 0
+	SFlowTypePacketDiscarded      SFlowSourceFormat = 1
+	SFlowTypeMultipleDestinations SFlowSourceFormat = 2
+)
+
+func (sdf SFlowSourceFormat) String() string {
+	switch sdf {
+	case SFlowTypeSingleInterface:
+		return "Single Interface"
+	case SFlowTypePacketDiscarded:
+		return "Packet Discarded"
+	case SFlowTypeMultipleDestinations:
+		return "Multiple Destinations"
+	default:
+		return "UNKNOWN"
+	}
+}
+
+func decodeSFlow(data []byte, p gopacket.PacketBuilder) error {
+	s := &SFlowDatagram{}
+	err := s.DecodeFromBytes(data, p)
+	if err != nil {
+		return err
+	}
+	p.AddLayer(s)
+	p.SetApplicationLayer(s)
+	return nil
+}
+
+// SFlowDatagram is the outermost container which holds some basic information
+// about the reporting agent, and holds at least one sample record
+type SFlowDatagram struct {
+	BaseLayer
+
+	DatagramVersion uint32
+	AgentAddress    net.IP
+	SubAgentID      uint32
+	SequenceNumber  uint32
+	AgentUptime     uint32
+	SampleCount     uint32
+	FlowSamples     []SFlowFlowSample
+	CounterSamples  []SFlowCounterSample
+}
+
+// An SFlow  datagram's outer container has the following
+// structure:
+
+//  0                      15                      31
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |           int sFlow version (2|4|5)           |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |   int IP version of the Agent (1=v4|2=v6)     |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  /    Agent IP address (v4=4byte|v6=16byte)      /
+//  /                                               /
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |               int sub agent id                |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |         int datagram sequence number          |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |            int switch uptime in ms            |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |          int n samples in datagram            |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  /                  n samples                    /
+//  /                                               /
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+// SFlowDataFormat encodes the EnterpriseID in the most
+// significant 12 bits, and the SampleType in the least significant
+// 20 bits.
+type SFlowDataFormat uint32
+
+func (sdf SFlowDataFormat) decode() (SFlowEnterpriseID, SFlowSampleType) {
+	leftField := sdf >> 12
+	rightField := uint32(0xFFF) & uint32(sdf)
+	return SFlowEnterpriseID(leftField), SFlowSampleType(rightField)
+}
+
+// SFlowEnterpriseID is used to differentiate between the
+// official SFlow standard, and other, vendor-specific
+// types of flow data. (Similiar to SNMP's enterprise MIB
+// OIDs) Only the office SFlow Enterprise ID is decoded
+// here.
+type SFlowEnterpriseID uint32
+
+const (
+	SFlowStandard SFlowEnterpriseID = 0
+)
+
+func (eid SFlowEnterpriseID) String() string {
+	switch eid {
+	case SFlowStandard:
+		return "Standard SFlow"
+	default:
+		return ""
+	}
+}
+
+func (eid SFlowEnterpriseID) GetType() SFlowEnterpriseID {
+	return SFlowStandard
+}
+
+// SFlowSampleType specifies the type of sample. Only flow samples
+// and counter samples are supported
+type SFlowSampleType uint32
+
+const (
+	SFlowTypeFlowSample            SFlowSampleType = 1
+	SFlowTypeCounterSample         SFlowSampleType = 2
+	SFlowTypeExpandedFlowSample    SFlowSampleType = 3
+	SFlowTypeExpandedCounterSample SFlowSampleType = 4
+)
+
+func (st SFlowSampleType) GetType() SFlowSampleType {
+	switch st {
+	case SFlowTypeFlowSample:
+		return SFlowTypeFlowSample
+	case SFlowTypeCounterSample:
+		return SFlowTypeCounterSample
+	case SFlowTypeExpandedFlowSample:
+		return SFlowTypeExpandedFlowSample
+	case SFlowTypeExpandedCounterSample:
+		return SFlowTypeExpandedCounterSample
+	default:
+		panic("Invalid Sample Type")
+	}
+}
+
+func (st SFlowSampleType) String() string {
+	switch st {
+	case SFlowTypeFlowSample:
+		return "Flow Sample"
+	case SFlowTypeCounterSample:
+		return "Counter Sample"
+	case SFlowTypeExpandedFlowSample:
+		return "Expanded Flow Sample"
+	case SFlowTypeExpandedCounterSample:
+		return "Expanded Counter Sample"
+	default:
+		return ""
+	}
+}
+
+func (s *SFlowDatagram) LayerType() gopacket.LayerType { return LayerTypeSFlow }
+
+func (d *SFlowDatagram) Payload() []byte { return nil }
+
+func (d *SFlowDatagram) CanDecode() gopacket.LayerClass { return LayerTypeSFlow }
+
+func (d *SFlowDatagram) NextLayerType() gopacket.LayerType { return gopacket.LayerTypePayload }
+
+// SFlowIPType determines what form the IP address being decoded will
+// take. This is an XDR union type allowing for both IPv4 and IPv6
+type SFlowIPType uint32
+
+const (
+	SFlowIPv4 SFlowIPType = 1
+	SFlowIPv6 SFlowIPType = 2
+)
+
+func (s SFlowIPType) String() string {
+	switch s {
+	case SFlowIPv4:
+		return "IPv4"
+	case SFlowIPv6:
+		return "IPv6"
+	default:
+		return ""
+	}
+}
+
+func (s SFlowIPType) Length() int {
+	switch s {
+	case SFlowIPv4:
+		return 4
+	case SFlowIPv6:
+		return 16
+	default:
+		return 0
+	}
+}
+
+func (s *SFlowDatagram) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
+	var agentAddressType SFlowIPType
+
+	data, s.DatagramVersion = data[4:], binary.BigEndian.Uint32(data[:4])
+	data, agentAddressType = data[4:], SFlowIPType(binary.BigEndian.Uint32(data[:4]))
+	data, s.AgentAddress = data[agentAddressType.Length():], data[:agentAddressType.Length()]
+	data, s.SubAgentID = data[4:], binary.BigEndian.Uint32(data[:4])
+	data, s.SequenceNumber = data[4:], binary.BigEndian.Uint32(data[:4])
+	data, s.AgentUptime = data[4:], binary.BigEndian.Uint32(data[:4])
+	data, s.SampleCount = data[4:], binary.BigEndian.Uint32(data[:4])
+
+	if s.SampleCount < 1 {
+		return fmt.Errorf("SFlow Datagram has invalid sample length: %d", s.SampleCount)
+	}
+	for i := uint32(0); i < s.SampleCount; i++ {
+		sdf := SFlowDataFormat(binary.BigEndian.Uint32(data[:4]))
+		_, sampleType := sdf.decode()
+		switch sampleType {
+		case SFlowTypeFlowSample:
+			if flowSample, err := decodeFlowSample(&data, false); err == nil {
+				s.FlowSamples = append(s.FlowSamples, flowSample)
+			} else {
+				return err
+			}
+		case SFlowTypeCounterSample:
+			if counterSample, err := decodeCounterSample(&data, false); err == nil {
+				s.CounterSamples = append(s.CounterSamples, counterSample)
+			} else {
+				return err
+			}
+		case SFlowTypeExpandedFlowSample:
+			if flowSample, err := decodeFlowSample(&data, true); err == nil {
+				s.FlowSamples = append(s.FlowSamples, flowSample)
+			} else {
+				return err
+			}
+		case SFlowTypeExpandedCounterSample:
+			if counterSample, err := decodeCounterSample(&data, true); err == nil {
+				s.CounterSamples = append(s.CounterSamples, counterSample)
+			} else {
+				return err
+			}
+
+		default:
+			return fmt.Errorf("Unsupported SFlow sample type %d", sampleType)
+		}
+	}
+	return nil
+}
+
+// SFlowFlowSample represents a sampled packet and contains
+// one or more records describing the packet
+type SFlowFlowSample struct {
+	EnterpriseID          SFlowEnterpriseID
+	Format                SFlowSampleType
+	SampleLength          uint32
+	SequenceNumber        uint32
+	SourceIDClass         SFlowSourceFormat
+	SourceIDIndex         SFlowSourceValue
+	SamplingRate          uint32
+	SamplePool            uint32
+	Dropped               uint32
+	InputInterfaceFormat  uint32
+	InputInterface        uint32
+	OutputInterfaceFormat uint32
+	OutputInterface       uint32
+	RecordCount           uint32
+	Records               []SFlowRecord
+}
+
+// Flow samples have the following structure. Note
+// the bit fields to encode the Enterprise ID and the
+// Flow record format: type 1
+
+//  0                      15                      31
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |      20 bit Interprise (0)     |12 bit format |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                  sample length                |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |          int sample sequence number           |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |id type |       src id index value             |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |               int sampling rate               |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                int sample pool                |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                    int drops                  |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                 int input ifIndex             |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                int output ifIndex             |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |               int number of records           |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  /                   flow records                /
+//  /                                               /
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+// Flow samples have the following structure.
+// Flow record format: type 3
+
+//  0                      15                      31
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |      20 bit Interprise (0)     |12 bit format |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                  sample length                |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |          int sample sequence number           |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |               int src id type                 |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |             int src id index value            |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |               int sampling rate               |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                int sample pool                |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                    int drops                  |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |           int input interface format          |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |           int input interface value           |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |           int output interface format         |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |           int output interface value          |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |               int number of records           |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  /                   flow records                /
+//  /                                               /
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+type SFlowFlowDataFormat uint32
+
+func (fdf SFlowFlowDataFormat) decode() (SFlowEnterpriseID, SFlowFlowRecordType) {
+	leftField := fdf >> 12
+	rightField := uint32(0xFFF) & uint32(fdf)
+	return SFlowEnterpriseID(leftField), SFlowFlowRecordType(rightField)
+}
+
+func (fs SFlowFlowSample) GetRecords() []SFlowRecord {
+	return fs.Records
+}
+
+func (fs SFlowFlowSample) GetType() SFlowSampleType {
+	return SFlowTypeFlowSample
+}
+
+func skipRecord(data *[]byte) {
+	recordLength := int(binary.BigEndian.Uint32((*data)[4:]))
+	*data = (*data)[(recordLength+((4-recordLength)%4))+8:]
+}
+
+func decodeFlowSample(data *[]byte, expanded bool) (SFlowFlowSample, error) {
+	s := SFlowFlowSample{}
+	var sdf SFlowDataFormat
+	*data, sdf = (*data)[4:], SFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
+	var sdc SFlowDataSource
+
+	s.EnterpriseID, s.Format = sdf.decode()
+	*data, s.SampleLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, s.SequenceNumber = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	if expanded {
+		*data, s.SourceIDClass = (*data)[4:], SFlowSourceFormat(binary.BigEndian.Uint32((*data)[:4]))
+		*data, s.SourceIDIndex = (*data)[4:], SFlowSourceValue(binary.BigEndian.Uint32((*data)[:4]))
+	} else {
+		*data, sdc = (*data)[4:], SFlowDataSource(binary.BigEndian.Uint32((*data)[:4]))
+		s.SourceIDClass, s.SourceIDIndex = sdc.decode()
+	}
+	*data, s.SamplingRate = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, s.SamplePool = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, s.Dropped = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+
+	if expanded {
+		*data, s.InputInterfaceFormat = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+		*data, s.InputInterface = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+		*data, s.OutputInterfaceFormat = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+		*data, s.OutputInterface = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	} else {
+		*data, s.InputInterface = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+		*data, s.OutputInterface = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	}
+	*data, s.RecordCount = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+
+	for i := uint32(0); i < s.RecordCount; i++ {
+		rdf := SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
+		enterpriseID, flowRecordType := rdf.decode()
+
+		// Try to decode when EnterpriseID is 0 signaling
+		// default sflow structs are used according specification
+		// Unexpected behavior detected for e.g. with pmacct
+		if enterpriseID == 0 {
+			switch flowRecordType {
+			case SFlowTypeRawPacketFlow:
+				if record, err := decodeRawPacketFlowRecord(data); err == nil {
+					s.Records = append(s.Records, record)
+				} else {
+					return s, err
+				}
+			case SFlowTypeExtendedUserFlow:
+				if record, err := decodeExtendedUserFlow(data); err == nil {
+					s.Records = append(s.Records, record)
+				} else {
+					return s, err
+				}
+			case SFlowTypeExtendedUrlFlow:
+				if record, err := decodeExtendedURLRecord(data); err == nil {
+					s.Records = append(s.Records, record)
+				} else {
+					return s, err
+				}
+			case SFlowTypeExtendedSwitchFlow:
+				if record, err := decodeExtendedSwitchFlowRecord(data); err == nil {
+					s.Records = append(s.Records, record)
+				} else {
+					return s, err
+				}
+			case SFlowTypeExtendedRouterFlow:
+				if record, err := decodeExtendedRouterFlowRecord(data); err == nil {
+					s.Records = append(s.Records, record)
+				} else {
+					return s, err
+				}
+			case SFlowTypeExtendedGatewayFlow:
+				if record, err := decodeExtendedGatewayFlowRecord(data); err == nil {
+					s.Records = append(s.Records, record)
+				} else {
+					return s, err
+				}
+			case SFlowTypeEthernetFrameFlow:
+				if record, err := decodeEthernetFrameFlowRecord(data); err == nil {
+					s.Records = append(s.Records, record)
+				} else {
+					return s, err
+				}
+			case SFlowTypeIpv4Flow:
+				if record, err := decodeSFlowIpv4Record(data); err == nil {
+					s.Records = append(s.Records, record)
+				} else {
+					return s, err
+				}
+			case SFlowTypeIpv6Flow:
+				if record, err := decodeSFlowIpv6Record(data); err == nil {
+					s.Records = append(s.Records, record)
+				} else {
+					return s, err
+				}
+			case SFlowTypeExtendedMlpsFlow:
+				// TODO
+				skipRecord(data)
+				return s, errors.New("skipping TypeExtendedMlpsFlow")
+			case SFlowTypeExtendedNatFlow:
+				// TODO
+				skipRecord(data)
+				return s, errors.New("skipping TypeExtendedNatFlow")
+			case SFlowTypeExtendedMlpsTunnelFlow:
+				// TODO
+				skipRecord(data)
+				return s, errors.New("skipping TypeExtendedMlpsTunnelFlow")
+			case SFlowTypeExtendedMlpsVcFlow:
+				// TODO
+				skipRecord(data)
+				return s, errors.New("skipping TypeExtendedMlpsVcFlow")
+			case SFlowTypeExtendedMlpsFecFlow:
+				// TODO
+				skipRecord(data)
+				return s, errors.New("skipping TypeExtendedMlpsFecFlow")
+			case SFlowTypeExtendedMlpsLvpFecFlow:
+				// TODO
+				skipRecord(data)
+				return s, errors.New("skipping TypeExtendedMlpsLvpFecFlow")
+			case SFlowTypeExtendedVlanFlow:
+				// TODO
+				skipRecord(data)
+				return s, errors.New("skipping TypeExtendedVlanFlow")
+			case SFlowTypeExtendedIpv4TunnelEgressFlow:
+				if record, err := decodeExtendedIpv4TunnelEgress(data); err == nil {
+					s.Records = append(s.Records, record)
+				} else {
+					return s, err
+				}
+			case SFlowTypeExtendedIpv4TunnelIngressFlow:
+				if record, err := decodeExtendedIpv4TunnelIngress(data); err == nil {
+					s.Records = append(s.Records, record)
+				} else {
+					return s, err
+				}
+			case SFlowTypeExtendedIpv6TunnelEgressFlow:
+				if record, err := decodeExtendedIpv6TunnelEgress(data); err == nil {
+					s.Records = append(s.Records, record)
+				} else {
+					return s, err
+				}
+			case SFlowTypeExtendedIpv6TunnelIngressFlow:
+				if record, err := decodeExtendedIpv6TunnelIngress(data); err == nil {
+					s.Records = append(s.Records, record)
+				} else {
+					return s, err
+				}
+			case SFlowTypeExtendedDecapsulateEgressFlow:
+				if record, err := decodeExtendedDecapsulateEgress(data); err == nil {
+					s.Records = append(s.Records, record)
+				} else {
+					return s, err
+				}
+			case SFlowTypeExtendedDecapsulateIngressFlow:
+				if record, err := decodeExtendedDecapsulateIngress(data); err == nil {
+					s.Records = append(s.Records, record)
+				} else {
+					return s, err
+				}
+			case SFlowTypeExtendedVniEgressFlow:
+				if record, err := decodeExtendedVniEgress(data); err == nil {
+					s.Records = append(s.Records, record)
+				} else {
+					return s, err
+				}
+			case SFlowTypeExtendedVniIngressFlow:
+				if record, err := decodeExtendedVniIngress(data); err == nil {
+					s.Records = append(s.Records, record)
+				} else {
+					return s, err
+				}
+			default:
+				return s, fmt.Errorf("Unsupported flow record type: %d", flowRecordType)
+			}
+		} else {
+			skipRecord(data)
+		}
+	}
+	return s, nil
+}
+
+// Counter samples report information about various counter
+// objects. Typically these are items like IfInOctets, or
+// CPU / Memory stats, etc. SFlow will report these at regular
+// intervals as configured on the agent. If one were sufficiently
+// industrious, this could be used to replace the typical
+// SNMP polling used for such things.
+type SFlowCounterSample struct {
+	EnterpriseID   SFlowEnterpriseID
+	Format         SFlowSampleType
+	SampleLength   uint32
+	SequenceNumber uint32
+	SourceIDClass  SFlowSourceFormat
+	SourceIDIndex  SFlowSourceValue
+	RecordCount    uint32
+	Records        []SFlowRecord
+}
+
+// Counter samples have the following structure:
+
+//  0                      15                      31
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |          int sample sequence number           |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |id type |       src id index value             |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |               int number of records           |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  /                counter records                /
+//  /                                               /
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+type SFlowCounterDataFormat uint32
+
+func (cdf SFlowCounterDataFormat) decode() (SFlowEnterpriseID, SFlowCounterRecordType) {
+	leftField := cdf >> 12
+	rightField := uint32(0xFFF) & uint32(cdf)
+	return SFlowEnterpriseID(leftField), SFlowCounterRecordType(rightField)
+}
+
+// GetRecords will return a slice of interface types
+// representing records. A type switch can be used to
+// get at the underlying SFlowCounterRecordType.
+func (cs SFlowCounterSample) GetRecords() []SFlowRecord {
+	return cs.Records
+}
+
+// GetType will report the type of sample. Only the
+// compact form of counter samples is supported
+func (cs SFlowCounterSample) GetType() SFlowSampleType {
+	return SFlowTypeCounterSample
+}
+
+type SFlowCounterRecordType uint32
+
+const (
+	SFlowTypeGenericInterfaceCounters   SFlowCounterRecordType = 1
+	SFlowTypeEthernetInterfaceCounters  SFlowCounterRecordType = 2
+	SFlowTypeTokenRingInterfaceCounters SFlowCounterRecordType = 3
+	SFlowType100BaseVGInterfaceCounters SFlowCounterRecordType = 4
+	SFlowTypeVLANCounters               SFlowCounterRecordType = 5
+	SFlowTypeLACPCounters               SFlowCounterRecordType = 7
+	SFlowTypeProcessorCounters          SFlowCounterRecordType = 1001
+	SFlowTypeOpenflowPortCounters       SFlowCounterRecordType = 1004
+	SFlowTypePORTNAMECounters           SFlowCounterRecordType = 1005
+	SFLowTypeAPPRESOURCESCounters       SFlowCounterRecordType = 2203
+	SFlowTypeOVSDPCounters              SFlowCounterRecordType = 2207
+)
+
+func (cr SFlowCounterRecordType) String() string {
+	switch cr {
+	case SFlowTypeGenericInterfaceCounters:
+		return "Generic Interface Counters"
+	case SFlowTypeEthernetInterfaceCounters:
+		return "Ethernet Interface Counters"
+	case SFlowTypeTokenRingInterfaceCounters:
+		return "Token Ring Interface Counters"
+	case SFlowType100BaseVGInterfaceCounters:
+		return "100BaseVG Interface Counters"
+	case SFlowTypeVLANCounters:
+		return "VLAN Counters"
+	case SFlowTypeLACPCounters:
+		return "LACP Counters"
+	case SFlowTypeProcessorCounters:
+		return "Processor Counters"
+	case SFlowTypeOpenflowPortCounters:
+		return "Openflow Port Counters"
+	case SFlowTypePORTNAMECounters:
+		return "PORT NAME Counters"
+	case SFLowTypeAPPRESOURCESCounters:
+		return "App Resources Counters"
+	case SFlowTypeOVSDPCounters:
+		return "OVSDP Counters"
+	default:
+		return ""
+
+	}
+}
+
+func decodeCounterSample(data *[]byte, expanded bool) (SFlowCounterSample, error) {
+	s := SFlowCounterSample{}
+	var sdc SFlowDataSource
+	var sdce SFlowDataSourceExpanded
+	var sdf SFlowDataFormat
+
+	*data, sdf = (*data)[4:], SFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
+	s.EnterpriseID, s.Format = sdf.decode()
+	*data, s.SampleLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, s.SequenceNumber = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	if expanded {
+		*data, sdce = (*data)[8:], SFlowDataSourceExpanded{SFlowSourceFormat(binary.BigEndian.Uint32((*data)[:4])), SFlowSourceValue(binary.BigEndian.Uint32((*data)[4:8]))}
+		s.SourceIDClass, s.SourceIDIndex = sdce.decode()
+	} else {
+		*data, sdc = (*data)[4:], SFlowDataSource(binary.BigEndian.Uint32((*data)[:4]))
+		s.SourceIDClass, s.SourceIDIndex = sdc.decode()
+	}
+	*data, s.RecordCount = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+
+	for i := uint32(0); i < s.RecordCount; i++ {
+		cdf := SFlowCounterDataFormat(binary.BigEndian.Uint32((*data)[:4]))
+		_, counterRecordType := cdf.decode()
+		switch counterRecordType {
+		case SFlowTypeGenericInterfaceCounters:
+			if record, err := decodeGenericInterfaceCounters(data); err == nil {
+				s.Records = append(s.Records, record)
+			} else {
+				return s, err
+			}
+		case SFlowTypeEthernetInterfaceCounters:
+			if record, err := decodeEthernetCounters(data); err == nil {
+				s.Records = append(s.Records, record)
+			} else {
+				return s, err
+			}
+		case SFlowTypeTokenRingInterfaceCounters:
+			skipRecord(data)
+			return s, errors.New("skipping TypeTokenRingInterfaceCounters")
+		case SFlowType100BaseVGInterfaceCounters:
+			skipRecord(data)
+			return s, errors.New("skipping Type100BaseVGInterfaceCounters")
+		case SFlowTypeVLANCounters:
+			if record, err := decodeVLANCounters(data); err == nil {
+				s.Records = append(s.Records, record)
+			} else {
+				return s, err
+			}
+		case SFlowTypeLACPCounters:
+			if record, err := decodeLACPCounters(data); err == nil {
+				s.Records = append(s.Records, record)
+			} else {
+				return s, err
+			}
+		case SFlowTypeProcessorCounters:
+			if record, err := decodeProcessorCounters(data); err == nil {
+				s.Records = append(s.Records, record)
+			} else {
+				return s, err
+			}
+		case SFlowTypeOpenflowPortCounters:
+			if record, err := decodeOpenflowportCounters(data); err == nil {
+				s.Records = append(s.Records, record)
+			} else {
+				return s, err
+			}
+		case SFlowTypePORTNAMECounters:
+			if record, err := decodePortnameCounters(data); err == nil {
+				s.Records = append(s.Records, record)
+			} else {
+				return s, err
+			}
+		case SFLowTypeAPPRESOURCESCounters:
+			if record, err := decodeAppresourcesCounters(data); err == nil {
+				s.Records = append(s.Records, record)
+			} else {
+				return s, err
+			}
+		case SFlowTypeOVSDPCounters:
+			if record, err := decodeOVSDPCounters(data); err == nil {
+				s.Records = append(s.Records, record)
+			} else {
+				return s, err
+			}
+		default:
+			return s, fmt.Errorf("Invalid counter record type: %d", counterRecordType)
+		}
+	}
+	return s, nil
+}
+
+// SFlowBaseFlowRecord holds the fields common to all records
+// of type SFlowFlowRecordType
+type SFlowBaseFlowRecord struct {
+	EnterpriseID   SFlowEnterpriseID
+	Format         SFlowFlowRecordType
+	FlowDataLength uint32
+}
+
+func (bfr SFlowBaseFlowRecord) GetType() SFlowFlowRecordType {
+	return bfr.Format
+}
+
+// SFlowFlowRecordType denotes what kind of Flow Record is
+// represented. See RFC 3176
+type SFlowFlowRecordType uint32
+
+const (
+	SFlowTypeRawPacketFlow                  SFlowFlowRecordType = 1
+	SFlowTypeEthernetFrameFlow              SFlowFlowRecordType = 2
+	SFlowTypeIpv4Flow                       SFlowFlowRecordType = 3
+	SFlowTypeIpv6Flow                       SFlowFlowRecordType = 4
+	SFlowTypeExtendedSwitchFlow             SFlowFlowRecordType = 1001
+	SFlowTypeExtendedRouterFlow             SFlowFlowRecordType = 1002
+	SFlowTypeExtendedGatewayFlow            SFlowFlowRecordType = 1003
+	SFlowTypeExtendedUserFlow               SFlowFlowRecordType = 1004
+	SFlowTypeExtendedUrlFlow                SFlowFlowRecordType = 1005
+	SFlowTypeExtendedMlpsFlow               SFlowFlowRecordType = 1006
+	SFlowTypeExtendedNatFlow                SFlowFlowRecordType = 1007
+	SFlowTypeExtendedMlpsTunnelFlow         SFlowFlowRecordType = 1008
+	SFlowTypeExtendedMlpsVcFlow             SFlowFlowRecordType = 1009
+	SFlowTypeExtendedMlpsFecFlow            SFlowFlowRecordType = 1010
+	SFlowTypeExtendedMlpsLvpFecFlow         SFlowFlowRecordType = 1011
+	SFlowTypeExtendedVlanFlow               SFlowFlowRecordType = 1012
+	SFlowTypeExtendedIpv4TunnelEgressFlow   SFlowFlowRecordType = 1023
+	SFlowTypeExtendedIpv4TunnelIngressFlow  SFlowFlowRecordType = 1024
+	SFlowTypeExtendedIpv6TunnelEgressFlow   SFlowFlowRecordType = 1025
+	SFlowTypeExtendedIpv6TunnelIngressFlow  SFlowFlowRecordType = 1026
+	SFlowTypeExtendedDecapsulateEgressFlow  SFlowFlowRecordType = 1027
+	SFlowTypeExtendedDecapsulateIngressFlow SFlowFlowRecordType = 1028
+	SFlowTypeExtendedVniEgressFlow          SFlowFlowRecordType = 1029
+	SFlowTypeExtendedVniIngressFlow         SFlowFlowRecordType = 1030
+)
+
+func (rt SFlowFlowRecordType) String() string {
+	switch rt {
+	case SFlowTypeRawPacketFlow:
+		return "Raw Packet Flow Record"
+	case SFlowTypeEthernetFrameFlow:
+		return "Ethernet Frame Flow Record"
+	case SFlowTypeIpv4Flow:
+		return "IPv4 Flow Record"
+	case SFlowTypeIpv6Flow:
+		return "IPv6 Flow Record"
+	case SFlowTypeExtendedSwitchFlow:
+		return "Extended Switch Flow Record"
+	case SFlowTypeExtendedRouterFlow:
+		return "Extended Router Flow Record"
+	case SFlowTypeExtendedGatewayFlow:
+		return "Extended Gateway Flow Record"
+	case SFlowTypeExtendedUserFlow:
+		return "Extended User Flow Record"
+	case SFlowTypeExtendedUrlFlow:
+		return "Extended URL Flow Record"
+	case SFlowTypeExtendedMlpsFlow:
+		return "Extended MPLS Flow Record"
+	case SFlowTypeExtendedNatFlow:
+		return "Extended NAT Flow Record"
+	case SFlowTypeExtendedMlpsTunnelFlow:
+		return "Extended MPLS Tunnel Flow Record"
+	case SFlowTypeExtendedMlpsVcFlow:
+		return "Extended MPLS VC Flow Record"
+	case SFlowTypeExtendedMlpsFecFlow:
+		return "Extended MPLS FEC Flow Record"
+	case SFlowTypeExtendedMlpsLvpFecFlow:
+		return "Extended MPLS LVP FEC Flow Record"
+	case SFlowTypeExtendedVlanFlow:
+		return "Extended VLAN Flow Record"
+	case SFlowTypeExtendedIpv4TunnelEgressFlow:
+		return "Extended IPv4 Tunnel Egress Record"
+	case SFlowTypeExtendedIpv4TunnelIngressFlow:
+		return "Extended IPv4 Tunnel Ingress Record"
+	case SFlowTypeExtendedIpv6TunnelEgressFlow:
+		return "Extended IPv6 Tunnel Egress Record"
+	case SFlowTypeExtendedIpv6TunnelIngressFlow:
+		return "Extended IPv6 Tunnel Ingress Record"
+	case SFlowTypeExtendedDecapsulateEgressFlow:
+		return "Extended Decapsulate Egress Record"
+	case SFlowTypeExtendedDecapsulateIngressFlow:
+		return "Extended Decapsulate Ingress Record"
+	case SFlowTypeExtendedVniEgressFlow:
+		return "Extended VNI Ingress Record"
+	case SFlowTypeExtendedVniIngressFlow:
+		return "Extended VNI Ingress Record"
+	default:
+		return ""
+	}
+}
+
+// SFlowRawPacketFlowRecords hold information about a sampled
+// packet grabbed as it transited the agent. This is
+// perhaps the most useful and interesting record type,
+// as it holds the headers of the sampled packet and
+// can be used to build up a complete picture of the
+// traffic patterns on a network.
+//
+// The raw packet header is sent back into gopacket for
+// decoding, and the resulting gopackt.Packet is stored
+// in the Header member
+type SFlowRawPacketFlowRecord struct {
+	SFlowBaseFlowRecord
+	HeaderProtocol SFlowRawHeaderProtocol
+	FrameLength    uint32
+	PayloadRemoved uint32
+	HeaderLength   uint32
+	Header         gopacket.Packet
+}
+
+// Raw packet record types have the following structure:
+
+//  0                      15                      31
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |      20 bit Interprise (0)     |12 bit format |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                  record length                |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                 Header Protocol               |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                 Frame Length                  |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                 Payload Removed               |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                 Header Length                 |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  \                     Header                    \
+//  \                                               \
+//  \                                               \
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+type SFlowRawHeaderProtocol uint32
+
+const (
+	SFlowProtoEthernet   SFlowRawHeaderProtocol = 1
+	SFlowProtoISO88024   SFlowRawHeaderProtocol = 2
+	SFlowProtoISO88025   SFlowRawHeaderProtocol = 3
+	SFlowProtoFDDI       SFlowRawHeaderProtocol = 4
+	SFlowProtoFrameRelay SFlowRawHeaderProtocol = 5
+	SFlowProtoX25        SFlowRawHeaderProtocol = 6
+	SFlowProtoPPP        SFlowRawHeaderProtocol = 7
+	SFlowProtoSMDS       SFlowRawHeaderProtocol = 8
+	SFlowProtoAAL5       SFlowRawHeaderProtocol = 9
+	SFlowProtoAAL5_IP    SFlowRawHeaderProtocol = 10 /* e.g. Cisco AAL5 mux */
+	SFlowProtoIPv4       SFlowRawHeaderProtocol = 11
+	SFlowProtoIPv6       SFlowRawHeaderProtocol = 12
+	SFlowProtoMPLS       SFlowRawHeaderProtocol = 13
+	SFlowProtoPOS        SFlowRawHeaderProtocol = 14 /* RFC 1662, 2615 */
+)
+
+func (sfhp SFlowRawHeaderProtocol) String() string {
+	switch sfhp {
+	case SFlowProtoEthernet:
+		return "ETHERNET-ISO88023"
+	case SFlowProtoISO88024:
+		return "ISO88024-TOKENBUS"
+	case SFlowProtoISO88025:
+		return "ISO88025-TOKENRING"
+	case SFlowProtoFDDI:
+		return "FDDI"
+	case SFlowProtoFrameRelay:
+		return "FRAME-RELAY"
+	case SFlowProtoX25:
+		return "X25"
+	case SFlowProtoPPP:
+		return "PPP"
+	case SFlowProtoSMDS:
+		return "SMDS"
+	case SFlowProtoAAL5:
+		return "AAL5"
+	case SFlowProtoAAL5_IP:
+		return "AAL5-IP"
+	case SFlowProtoIPv4:
+		return "IPv4"
+	case SFlowProtoIPv6:
+		return "IPv6"
+	case SFlowProtoMPLS:
+		return "MPLS"
+	case SFlowProtoPOS:
+		return "POS"
+	}
+	return "UNKNOWN"
+}
+
+func decodeRawPacketFlowRecord(data *[]byte) (SFlowRawPacketFlowRecord, error) {
+	rec := SFlowRawPacketFlowRecord{}
+	header := []byte{}
+	var fdf SFlowFlowDataFormat
+
+	*data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
+	rec.EnterpriseID, rec.Format = fdf.decode()
+	*data, rec.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, rec.HeaderProtocol = (*data)[4:], SFlowRawHeaderProtocol(binary.BigEndian.Uint32((*data)[:4]))
+	*data, rec.FrameLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, rec.PayloadRemoved = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, rec.HeaderLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	headerLenWithPadding := int(rec.HeaderLength + ((4 - rec.HeaderLength) % 4))
+	*data, header = (*data)[headerLenWithPadding:], (*data)[:headerLenWithPadding]
+	rec.Header = gopacket.NewPacket(header, LayerTypeEthernet, gopacket.Default)
+	return rec, nil
+}
+
+// SFlowExtendedSwitchFlowRecord give additional information
+// about the sampled packet if it's available. It's mainly
+// useful for getting at the incoming and outgoing VLANs
+// An agent may or may not provide this information.
+type SFlowExtendedSwitchFlowRecord struct {
+	SFlowBaseFlowRecord
+	IncomingVLAN         uint32
+	IncomingVLANPriority uint32
+	OutgoingVLAN         uint32
+	OutgoingVLANPriority uint32
+}
+
+// Extended switch records have the following structure:
+
+//  0                      15                      31
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |      20 bit Interprise (0)     |12 bit format |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                  record length                |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                   Incoming VLAN               |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                Incoming VLAN Priority         |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                   Outgoing VLAN               |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                Outgoing VLAN Priority         |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+func decodeExtendedSwitchFlowRecord(data *[]byte) (SFlowExtendedSwitchFlowRecord, error) {
+	es := SFlowExtendedSwitchFlowRecord{}
+	var fdf SFlowFlowDataFormat
+
+	*data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
+	es.EnterpriseID, es.Format = fdf.decode()
+	*data, es.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, es.IncomingVLAN = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, es.IncomingVLANPriority = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, es.OutgoingVLAN = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, es.OutgoingVLANPriority = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	return es, nil
+}
+
+// SFlowExtendedRouterFlowRecord gives additional information
+// about the layer 3 routing information used to forward
+// the packet
+type SFlowExtendedRouterFlowRecord struct {
+	SFlowBaseFlowRecord
+	NextHop                net.IP
+	NextHopSourceMask      uint32
+	NextHopDestinationMask uint32
+}
+
+// Extended router records have the following structure:
+
+//  0                      15                      31
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |      20 bit Interprise (0)     |12 bit format |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                  record length                |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |   IP version of next hop router (1=v4|2=v6)   |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  /     Next Hop address (v4=4byte|v6=16byte)     /
+//  /                                               /
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |              Next Hop Source Mask             |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |              Next Hop Destination Mask        |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+func decodeExtendedRouterFlowRecord(data *[]byte) (SFlowExtendedRouterFlowRecord, error) {
+	er := SFlowExtendedRouterFlowRecord{}
+	var fdf SFlowFlowDataFormat
+	var extendedRouterAddressType SFlowIPType
+
+	*data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
+	er.EnterpriseID, er.Format = fdf.decode()
+	*data, er.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, extendedRouterAddressType = (*data)[4:], SFlowIPType(binary.BigEndian.Uint32((*data)[:4]))
+	*data, er.NextHop = (*data)[extendedRouterAddressType.Length():], (*data)[:extendedRouterAddressType.Length()]
+	*data, er.NextHopSourceMask = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, er.NextHopDestinationMask = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	return er, nil
+}
+
+// SFlowExtendedGatewayFlowRecord describes information treasured by
+// nework engineers everywhere: AS path information listing which
+// BGP peer sent the packet, and various other BGP related info.
+// This information is vital because it gives a picture of how much
+// traffic is being sent from / received by various BGP peers.
+
+// Extended gateway records have the following structure:
+
+//  0                      15                      31
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |      20 bit Interprise (0)     |12 bit format |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                  record length                |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |   IP version of next hop router (1=v4|2=v6)   |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  /     Next Hop address (v4=4byte|v6=16byte)     /
+//  /                                               /
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                       AS                      |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                  Source AS                    |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                    Peer AS                    |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                  AS Path Count                |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  /                AS Path / Sequence             /
+//  /                                               /
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  /                   Communities                 /
+//  /                                               /
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                    Local Pref                 |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+// AS Path / Sequence:
+
+//  0                      15                      31
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |     AS Source Type (Path=1 / Sequence=2)      |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |              Path / Sequence length           |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  /              Path / Sequence Members          /
+//  /                                               /
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+// Communities:
+
+//  0                      15                      31
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                communitiy length              |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  /              communitiy Members               /
+//  /                                               /
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+type SFlowExtendedGatewayFlowRecord struct {
+	SFlowBaseFlowRecord
+	NextHop     net.IP
+	AS          uint32
+	SourceAS    uint32
+	PeerAS      uint32
+	ASPathCount uint32
+	ASPath      []SFlowASDestination
+	Communities []uint32
+	LocalPref   uint32
+}
+
+type SFlowASPathType uint32
+
+const (
+	SFlowASSet      SFlowASPathType = 1
+	SFlowASSequence SFlowASPathType = 2
+)
+
+func (apt SFlowASPathType) String() string {
+	switch apt {
+	case SFlowASSet:
+		return "AS Set"
+	case SFlowASSequence:
+		return "AS Sequence"
+	default:
+		return ""
+	}
+}
+
+type SFlowASDestination struct {
+	Type    SFlowASPathType
+	Count   uint32
+	Members []uint32
+}
+
+func (asd SFlowASDestination) String() string {
+	switch asd.Type {
+	case SFlowASSet:
+		return fmt.Sprint("AS Set:", asd.Members)
+	case SFlowASSequence:
+		return fmt.Sprint("AS Sequence:", asd.Members)
+	default:
+		return ""
+	}
+}
+
+func (ad *SFlowASDestination) decodePath(data *[]byte) {
+	*data, ad.Type = (*data)[4:], SFlowASPathType(binary.BigEndian.Uint32((*data)[:4]))
+	*data, ad.Count = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	ad.Members = make([]uint32, ad.Count)
+	for i := uint32(0); i < ad.Count; i++ {
+		var member uint32
+		*data, member = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+		ad.Members[i] = member
+	}
+}
+
+func decodeExtendedGatewayFlowRecord(data *[]byte) (SFlowExtendedGatewayFlowRecord, error) {
+	eg := SFlowExtendedGatewayFlowRecord{}
+	var fdf SFlowFlowDataFormat
+	var extendedGatewayAddressType SFlowIPType
+	var communitiesLength uint32
+	var community uint32
+
+	*data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
+	eg.EnterpriseID, eg.Format = fdf.decode()
+	*data, eg.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, extendedGatewayAddressType = (*data)[4:], SFlowIPType(binary.BigEndian.Uint32((*data)[:4]))
+	*data, eg.NextHop = (*data)[extendedGatewayAddressType.Length():], (*data)[:extendedGatewayAddressType.Length()]
+	*data, eg.AS = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, eg.SourceAS = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, eg.PeerAS = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, eg.ASPathCount = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	for i := uint32(0); i < eg.ASPathCount; i++ {
+		asPath := SFlowASDestination{}
+		asPath.decodePath(data)
+		eg.ASPath = append(eg.ASPath, asPath)
+	}
+	*data, communitiesLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	eg.Communities = make([]uint32, communitiesLength)
+	for j := uint32(0); j < communitiesLength; j++ {
+		*data, community = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+		eg.Communities[j] = community
+	}
+	*data, eg.LocalPref = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	return eg, nil
+}
+
+// **************************************************
+//  Extended URL Flow Record
+// **************************************************
+
+//  0                      15                      31
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |      20 bit Interprise (0)     |12 bit format |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                  record length                |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                   direction                   |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                      URL                      |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                      Host                     |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+type SFlowURLDirection uint32
+
+const (
+	SFlowURLsrc SFlowURLDirection = 1
+	SFlowURLdst SFlowURLDirection = 2
+)
+
+func (urld SFlowURLDirection) String() string {
+	switch urld {
+	case SFlowURLsrc:
+		return "Source address is the server"
+	case SFlowURLdst:
+		return "Destination address is the server"
+	default:
+		return ""
+	}
+}
+
+type SFlowExtendedURLRecord struct {
+	SFlowBaseFlowRecord
+	Direction SFlowURLDirection
+	URL       string
+	Host      string
+}
+
+func decodeExtendedURLRecord(data *[]byte) (SFlowExtendedURLRecord, error) {
+	eur := SFlowExtendedURLRecord{}
+	var fdf SFlowFlowDataFormat
+	var urlLen uint32
+	var urlLenWithPad int
+	var hostLen uint32
+	var hostLenWithPad int
+	var urlBytes []byte
+	var hostBytes []byte
+
+	*data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
+	eur.EnterpriseID, eur.Format = fdf.decode()
+	*data, eur.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, eur.Direction = (*data)[4:], SFlowURLDirection(binary.BigEndian.Uint32((*data)[:4]))
+	*data, urlLen = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	urlLenWithPad = int(urlLen + ((4 - urlLen) % 4))
+	*data, urlBytes = (*data)[urlLenWithPad:], (*data)[:urlLenWithPad]
+	eur.URL = string(urlBytes[:urlLen])
+	*data, hostLen = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	hostLenWithPad = int(hostLen + ((4 - hostLen) % 4))
+	*data, hostBytes = (*data)[hostLenWithPad:], (*data)[:hostLenWithPad]
+	eur.Host = string(hostBytes[:hostLen])
+	return eur, nil
+}
+
+// **************************************************
+//  Extended User Flow Record
+// **************************************************
+
+//  0                      15                      31
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |      20 bit Interprise (0)     |12 bit format |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                  record length                |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                Source Character Set           |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                 Source User Id                |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |              Destination Character Set        |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |               Destination User ID             |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+type SFlowExtendedUserFlow struct {
+	SFlowBaseFlowRecord
+	SourceCharSet      SFlowCharSet
+	SourceUserID       string
+	DestinationCharSet SFlowCharSet
+	DestinationUserID  string
+}
+
+type SFlowCharSet uint32
+
+const (
+	SFlowCSunknown                 SFlowCharSet = 2
+	SFlowCSASCII                   SFlowCharSet = 3
+	SFlowCSISOLatin1               SFlowCharSet = 4
+	SFlowCSISOLatin2               SFlowCharSet = 5
+	SFlowCSISOLatin3               SFlowCharSet = 6
+	SFlowCSISOLatin4               SFlowCharSet = 7
+	SFlowCSISOLatinCyrillic        SFlowCharSet = 8
+	SFlowCSISOLatinArabic          SFlowCharSet = 9
+	SFlowCSISOLatinGreek           SFlowCharSet = 10
+	SFlowCSISOLatinHebrew          SFlowCharSet = 11
+	SFlowCSISOLatin5               SFlowCharSet = 12
+	SFlowCSISOLatin6               SFlowCharSet = 13
+	SFlowCSISOTextComm             SFlowCharSet = 14
+	SFlowCSHalfWidthKatakana       SFlowCharSet = 15
+	SFlowCSJISEncoding             SFlowCharSet = 16
+	SFlowCSShiftJIS                SFlowCharSet = 17
+	SFlowCSEUCPkdFmtJapanese       SFlowCharSet = 18
+	SFlowCSEUCFixWidJapanese       SFlowCharSet = 19
+	SFlowCSISO4UnitedKingdom       SFlowCharSet = 20
+	SFlowCSISO11SwedishForNames    SFlowCharSet = 21
+	SFlowCSISO15Italian            SFlowCharSet = 22
+	SFlowCSISO17Spanish            SFlowCharSet = 23
+	SFlowCSISO21German             SFlowCharSet = 24
+	SFlowCSISO60DanishNorwegian    SFlowCharSet = 25
+	SFlowCSISO69French             SFlowCharSet = 26
+	SFlowCSISO10646UTF1            SFlowCharSet = 27
+	SFlowCSISO646basic1983         SFlowCharSet = 28
+	SFlowCSINVARIANT               SFlowCharSet = 29
+	SFlowCSISO2IntlRefVersion      SFlowCharSet = 30
+	SFlowCSNATSSEFI                SFlowCharSet = 31
+	SFlowCSNATSSEFIADD             SFlowCharSet = 32
+	SFlowCSNATSDANO                SFlowCharSet = 33
+	SFlowCSNATSDANOADD             SFlowCharSet = 34
+	SFlowCSISO10Swedish            SFlowCharSet = 35
+	SFlowCSKSC56011987             SFlowCharSet = 36
+	SFlowCSISO2022KR               SFlowCharSet = 37
+	SFlowCSEUCKR                   SFlowCharSet = 38
+	SFlowCSISO2022JP               SFlowCharSet = 39
+	SFlowCSISO2022JP2              SFlowCharSet = 40
+	SFlowCSISO13JISC6220jp         SFlowCharSet = 41
+	SFlowCSISO14JISC6220ro         SFlowCharSet = 42
+	SFlowCSISO16Portuguese         SFlowCharSet = 43
+	SFlowCSISO18Greek7Old          SFlowCharSet = 44
+	SFlowCSISO19LatinGreek         SFlowCharSet = 45
+	SFlowCSISO25French             SFlowCharSet = 46
+	SFlowCSISO27LatinGreek1        SFlowCharSet = 47
+	SFlowCSISO5427Cyrillic         SFlowCharSet = 48
+	SFlowCSISO42JISC62261978       SFlowCharSet = 49
+	SFlowCSISO47BSViewdata         SFlowCharSet = 50
+	SFlowCSISO49INIS               SFlowCharSet = 51
+	SFlowCSISO50INIS8              SFlowCharSet = 52
+	SFlowCSISO51INISCyrillic       SFlowCharSet = 53
+	SFlowCSISO54271981             SFlowCharSet = 54
+	SFlowCSISO5428Greek            SFlowCharSet = 55
+	SFlowCSISO57GB1988             SFlowCharSet = 56
+	SFlowCSISO58GB231280           SFlowCharSet = 57
+	SFlowCSISO61Norwegian2         SFlowCharSet = 58
+	SFlowCSISO70VideotexSupp1      SFlowCharSet = 59
+	SFlowCSISO84Portuguese2        SFlowCharSet = 60
+	SFlowCSISO85Spanish2           SFlowCharSet = 61
+	SFlowCSISO86Hungarian          SFlowCharSet = 62
+	SFlowCSISO87JISX0208           SFlowCharSet = 63
+	SFlowCSISO88Greek7             SFlowCharSet = 64
+	SFlowCSISO89ASMO449            SFlowCharSet = 65
+	SFlowCSISO90                   SFlowCharSet = 66
+	SFlowCSISO91JISC62291984a      SFlowCharSet = 67
+	SFlowCSISO92JISC62991984b      SFlowCharSet = 68
+	SFlowCSISO93JIS62291984badd    SFlowCharSet = 69
+	SFlowCSISO94JIS62291984hand    SFlowCharSet = 70
+	SFlowCSISO95JIS62291984handadd SFlowCharSet = 71
+	SFlowCSISO96JISC62291984kana   SFlowCharSet = 72
+	SFlowCSISO2033                 SFlowCharSet = 73
+	SFlowCSISO99NAPLPS             SFlowCharSet = 74
+	SFlowCSISO102T617bit           SFlowCharSet = 75
+	SFlowCSISO103T618bit           SFlowCharSet = 76
+	SFlowCSISO111ECMACyrillic      SFlowCharSet = 77
+	SFlowCSa71                     SFlowCharSet = 78
+	SFlowCSa72                     SFlowCharSet = 79
+	SFlowCSISO123CSAZ24341985gr    SFlowCharSet = 80
+	SFlowCSISO88596E               SFlowCharSet = 81
+	SFlowCSISO88596I               SFlowCharSet = 82
+	SFlowCSISO128T101G2            SFlowCharSet = 83
+	SFlowCSISO88598E               SFlowCharSet = 84
+	SFlowCSISO88598I               SFlowCharSet = 85
+	SFlowCSISO139CSN369103         SFlowCharSet = 86
+	SFlowCSISO141JUSIB1002         SFlowCharSet = 87
+	SFlowCSISO143IECP271           SFlowCharSet = 88
+	SFlowCSISO146Serbian           SFlowCharSet = 89
+	SFlowCSISO147Macedonian        SFlowCharSet = 90
+	SFlowCSISO150                  SFlowCharSet = 91
+	SFlowCSISO151Cuba              SFlowCharSet = 92
+	SFlowCSISO6937Add              SFlowCharSet = 93
+	SFlowCSISO153GOST1976874       SFlowCharSet = 94
+	SFlowCSISO8859Supp             SFlowCharSet = 95
+	SFlowCSISO10367Box             SFlowCharSet = 96
+	SFlowCSISO158Lap               SFlowCharSet = 97
+	SFlowCSISO159JISX02121990      SFlowCharSet = 98
+	SFlowCSISO646Danish            SFlowCharSet = 99
+	SFlowCSUSDK                    SFlowCharSet = 100
+	SFlowCSDKUS                    SFlowCharSet = 101
+	SFlowCSKSC5636                 SFlowCharSet = 102
+	SFlowCSUnicode11UTF7           SFlowCharSet = 103
+	SFlowCSISO2022CN               SFlowCharSet = 104
+	SFlowCSISO2022CNEXT            SFlowCharSet = 105
+	SFlowCSUTF8                    SFlowCharSet = 106
+	SFlowCSISO885913               SFlowCharSet = 109
+	SFlowCSISO885914               SFlowCharSet = 110
+	SFlowCSISO885915               SFlowCharSet = 111
+	SFlowCSISO885916               SFlowCharSet = 112
+	SFlowCSGBK                     SFlowCharSet = 113
+	SFlowCSGB18030                 SFlowCharSet = 114
+	SFlowCSOSDEBCDICDF0415         SFlowCharSet = 115
+	SFlowCSOSDEBCDICDF03IRV        SFlowCharSet = 116
+	SFlowCSOSDEBCDICDF041          SFlowCharSet = 117
+	SFlowCSISO115481               SFlowCharSet = 118
+	SFlowCSKZ1048                  SFlowCharSet = 119
+	SFlowCSUnicode                 SFlowCharSet = 1000
+	SFlowCSUCS4                    SFlowCharSet = 1001
+	SFlowCSUnicodeASCII            SFlowCharSet = 1002
+	SFlowCSUnicodeLatin1           SFlowCharSet = 1003
+	SFlowCSUnicodeJapanese         SFlowCharSet = 1004
+	SFlowCSUnicodeIBM1261          SFlowCharSet = 1005
+	SFlowCSUnicodeIBM1268          SFlowCharSet = 1006
+	SFlowCSUnicodeIBM1276          SFlowCharSet = 1007
+	SFlowCSUnicodeIBM1264          SFlowCharSet = 1008
+	SFlowCSUnicodeIBM1265          SFlowCharSet = 1009
+	SFlowCSUnicode11               SFlowCharSet = 1010
+	SFlowCSSCSU                    SFlowCharSet = 1011
+	SFlowCSUTF7                    SFlowCharSet = 1012
+	SFlowCSUTF16BE                 SFlowCharSet = 1013
+	SFlowCSUTF16LE                 SFlowCharSet = 1014
+	SFlowCSUTF16                   SFlowCharSet = 1015
+	SFlowCSCESU8                   SFlowCharSet = 1016
+	SFlowCSUTF32                   SFlowCharSet = 1017
+	SFlowCSUTF32BE                 SFlowCharSet = 1018
+	SFlowCSUTF32LE                 SFlowCharSet = 1019
+	SFlowCSBOCU1                   SFlowCharSet = 1020
+	SFlowCSWindows30Latin1         SFlowCharSet = 2000
+	SFlowCSWindows31Latin1         SFlowCharSet = 2001
+	SFlowCSWindows31Latin2         SFlowCharSet = 2002
+	SFlowCSWindows31Latin5         SFlowCharSet = 2003
+	SFlowCSHPRoman8                SFlowCharSet = 2004
+	SFlowCSAdobeStandardEncoding   SFlowCharSet = 2005
+	SFlowCSVenturaUS               SFlowCharSet = 2006
+	SFlowCSVenturaInternational    SFlowCharSet = 2007
+	SFlowCSDECMCS                  SFlowCharSet = 2008
+	SFlowCSPC850Multilingual       SFlowCharSet = 2009
+	SFlowCSPCp852                  SFlowCharSet = 2010
+	SFlowCSPC8CodePage437          SFlowCharSet = 2011
+	SFlowCSPC8DanishNorwegian      SFlowCharSet = 2012
+	SFlowCSPC862LatinHebrew        SFlowCharSet = 2013
+	SFlowCSPC8Turkish              SFlowCharSet = 2014
+	SFlowCSIBMSymbols              SFlowCharSet = 2015
+	SFlowCSIBMThai                 SFlowCharSet = 2016
+	SFlowCSHPLegal                 SFlowCharSet = 2017
+	SFlowCSHPPiFont                SFlowCharSet = 2018
+	SFlowCSHPMath8                 SFlowCharSet = 2019
+	SFlowCSHPPSMath                SFlowCharSet = 2020
+	SFlowCSHPDesktop               SFlowCharSet = 2021
+	SFlowCSVenturaMath             SFlowCharSet = 2022
+	SFlowCSMicrosoftPublishing     SFlowCharSet = 2023
+	SFlowCSWindows31J              SFlowCharSet = 2024
+	SFlowCSGB2312                  SFlowCharSet = 2025
+	SFlowCSBig5                    SFlowCharSet = 2026
+	SFlowCSMacintosh               SFlowCharSet = 2027
+	SFlowCSIBM037                  SFlowCharSet = 2028
+	SFlowCSIBM038                  SFlowCharSet = 2029
+	SFlowCSIBM273                  SFlowCharSet = 2030
+	SFlowCSIBM274                  SFlowCharSet = 2031
+	SFlowCSIBM275                  SFlowCharSet = 2032
+	SFlowCSIBM277                  SFlowCharSet = 2033
+	SFlowCSIBM278                  SFlowCharSet = 2034
+	SFlowCSIBM280                  SFlowCharSet = 2035
+	SFlowCSIBM281                  SFlowCharSet = 2036
+	SFlowCSIBM284                  SFlowCharSet = 2037
+	SFlowCSIBM285                  SFlowCharSet = 2038
+	SFlowCSIBM290                  SFlowCharSet = 2039
+	SFlowCSIBM297                  SFlowCharSet = 2040
+	SFlowCSIBM420                  SFlowCharSet = 2041
+	SFlowCSIBM423                  SFlowCharSet = 2042
+	SFlowCSIBM424                  SFlowCharSet = 2043
+	SFlowCSIBM500                  SFlowCharSet = 2044
+	SFlowCSIBM851                  SFlowCharSet = 2045
+	SFlowCSIBM855                  SFlowCharSet = 2046
+	SFlowCSIBM857                  SFlowCharSet = 2047
+	SFlowCSIBM860                  SFlowCharSet = 2048
+	SFlowCSIBM861                  SFlowCharSet = 2049
+	SFlowCSIBM863                  SFlowCharSet = 2050
+	SFlowCSIBM864                  SFlowCharSet = 2051
+	SFlowCSIBM865                  SFlowCharSet = 2052
+	SFlowCSIBM868                  SFlowCharSet = 2053
+	SFlowCSIBM869                  SFlowCharSet = 2054
+	SFlowCSIBM870                  SFlowCharSet = 2055
+	SFlowCSIBM871                  SFlowCharSet = 2056
+	SFlowCSIBM880                  SFlowCharSet = 2057
+	SFlowCSIBM891                  SFlowCharSet = 2058
+	SFlowCSIBM903                  SFlowCharSet = 2059
+	SFlowCSIBBM904                 SFlowCharSet = 2060
+	SFlowCSIBM905                  SFlowCharSet = 2061
+	SFlowCSIBM918                  SFlowCharSet = 2062
+	SFlowCSIBM1026                 SFlowCharSet = 2063
+	SFlowCSIBMEBCDICATDE           SFlowCharSet = 2064
+	SFlowCSEBCDICATDEA             SFlowCharSet = 2065
+	SFlowCSEBCDICCAFR              SFlowCharSet = 2066
+	SFlowCSEBCDICDKNO              SFlowCharSet = 2067
+	SFlowCSEBCDICDKNOA             SFlowCharSet = 2068
+	SFlowCSEBCDICFISE              SFlowCharSet = 2069
+	SFlowCSEBCDICFISEA             SFlowCharSet = 2070
+	SFlowCSEBCDICFR                SFlowCharSet = 2071
+	SFlowCSEBCDICIT                SFlowCharSet = 2072
+	SFlowCSEBCDICPT                SFlowCharSet = 2073
+	SFlowCSEBCDICES                SFlowCharSet = 2074
+	SFlowCSEBCDICESA               SFlowCharSet = 2075
+	SFlowCSEBCDICESS               SFlowCharSet = 2076
+	SFlowCSEBCDICUK                SFlowCharSet = 2077
+	SFlowCSEBCDICUS                SFlowCharSet = 2078
+	SFlowCSUnknown8BiT             SFlowCharSet = 2079
+	SFlowCSMnemonic                SFlowCharSet = 2080
+	SFlowCSMnem                    SFlowCharSet = 2081
+	SFlowCSVISCII                  SFlowCharSet = 2082
+	SFlowCSVIQR                    SFlowCharSet = 2083
+	SFlowCSKOI8R                   SFlowCharSet = 2084
+	SFlowCSHZGB2312                SFlowCharSet = 2085
+	SFlowCSIBM866                  SFlowCharSet = 2086
+	SFlowCSPC775Baltic             SFlowCharSet = 2087
+	SFlowCSKOI8U                   SFlowCharSet = 2088
+	SFlowCSIBM00858                SFlowCharSet = 2089
+	SFlowCSIBM00924                SFlowCharSet = 2090
+	SFlowCSIBM01140                SFlowCharSet = 2091
+	SFlowCSIBM01141                SFlowCharSet = 2092
+	SFlowCSIBM01142                SFlowCharSet = 2093
+	SFlowCSIBM01143                SFlowCharSet = 2094
+	SFlowCSIBM01144                SFlowCharSet = 2095
+	SFlowCSIBM01145                SFlowCharSet = 2096
+	SFlowCSIBM01146                SFlowCharSet = 2097
+	SFlowCSIBM01147                SFlowCharSet = 2098
+	SFlowCSIBM01148                SFlowCharSet = 2099
+	SFlowCSIBM01149                SFlowCharSet = 2100
+	SFlowCSBig5HKSCS               SFlowCharSet = 2101
+	SFlowCSIBM1047                 SFlowCharSet = 2102
+	SFlowCSPTCP154                 SFlowCharSet = 2103
+	SFlowCSAmiga1251               SFlowCharSet = 2104
+	SFlowCSKOI7switched            SFlowCharSet = 2105
+	SFlowCSBRF                     SFlowCharSet = 2106
+	SFlowCSTSCII                   SFlowCharSet = 2107
+	SFlowCSCP51932                 SFlowCharSet = 2108
+	SFlowCSWindows874              SFlowCharSet = 2109
+	SFlowCSWindows1250             SFlowCharSet = 2250
+	SFlowCSWindows1251             SFlowCharSet = 2251
+	SFlowCSWindows1252             SFlowCharSet = 2252
+	SFlowCSWindows1253             SFlowCharSet = 2253
+	SFlowCSWindows1254             SFlowCharSet = 2254
+	SFlowCSWindows1255             SFlowCharSet = 2255
+	SFlowCSWindows1256             SFlowCharSet = 2256
+	SFlowCSWindows1257             SFlowCharSet = 2257
+	SFlowCSWindows1258             SFlowCharSet = 2258
+	SFlowCSTIS620                  SFlowCharSet = 2259
+	SFlowCS50220                   SFlowCharSet = 2260
+	SFlowCSreserved                SFlowCharSet = 3000
+)
+
+func decodeExtendedUserFlow(data *[]byte) (SFlowExtendedUserFlow, error) {
+	eu := SFlowExtendedUserFlow{}
+	var fdf SFlowFlowDataFormat
+	var srcUserLen uint32
+	var srcUserLenWithPad int
+	var srcUserBytes []byte
+	var dstUserLen uint32
+	var dstUserLenWithPad int
+	var dstUserBytes []byte
+
+	*data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
+	eu.EnterpriseID, eu.Format = fdf.decode()
+	*data, eu.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, eu.SourceCharSet = (*data)[4:], SFlowCharSet(binary.BigEndian.Uint32((*data)[:4]))
+	*data, srcUserLen = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	srcUserLenWithPad = int(srcUserLen + ((4 - srcUserLen) % 4))
+	*data, srcUserBytes = (*data)[srcUserLenWithPad:], (*data)[:srcUserLenWithPad]
+	eu.SourceUserID = string(srcUserBytes[:srcUserLen])
+	*data, eu.DestinationCharSet = (*data)[4:], SFlowCharSet(binary.BigEndian.Uint32((*data)[:4]))
+	*data, dstUserLen = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	dstUserLenWithPad = int(dstUserLen + ((4 - dstUserLen) % 4))
+	*data, dstUserBytes = (*data)[dstUserLenWithPad:], (*data)[:dstUserLenWithPad]
+	eu.DestinationUserID = string(dstUserBytes[:dstUserLen])
+	return eu, nil
+}
+
+// **************************************************
+//  Packet IP version 4 Record
+// **************************************************
+
+//  0                      15                      31
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                     Length                    |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                    Protocol                   |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                  Source IPv4                  |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                Destination IPv4               |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                   Source Port                 |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                Destionation Port              |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                   TCP Flags                   |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                      TOS                      |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+type SFlowIpv4Record struct {
+	// The length of the IP packet excluding ower layer encapsulations
+	Length uint32
+	// IP Protocol type (for example, TCP = 6, UDP = 17)
+	Protocol uint32
+	// Source IP Address
+	IPSrc net.IP
+	// Destination IP Address
+	IPDst net.IP
+	// TCP/UDP source port number or equivalent
+	PortSrc uint32
+	// TCP/UDP destination port number or equivalent
+	PortDst uint32
+	// TCP flags
+	TCPFlags uint32
+	// IP type of service
+	TOS uint32
+}
+
+func decodeSFlowIpv4Record(data *[]byte) (SFlowIpv4Record, error) {
+	si := SFlowIpv4Record{}
+
+	*data, si.Length = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, si.Protocol = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, si.IPSrc = (*data)[4:], net.IP((*data)[:4])
+	*data, si.IPDst = (*data)[4:], net.IP((*data)[:4])
+	*data, si.PortSrc = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, si.PortDst = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, si.TCPFlags = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, si.TOS = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+
+	return si, nil
+}
+
+// **************************************************
+//  Packet IP version 6 Record
+// **************************************************
+
+//  0                      15                      31
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                     Length                    |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                    Protocol                   |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                  Source IPv4                  |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                Destination IPv4               |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                   Source Port                 |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                Destionation Port              |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                   TCP Flags                   |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                    Priority                   |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+type SFlowIpv6Record struct {
+	// The length of the IP packet excluding ower layer encapsulations
+	Length uint32
+	// IP Protocol type (for example, TCP = 6, UDP = 17)
+	Protocol uint32
+	// Source IP Address
+	IPSrc net.IP
+	// Destination IP Address
+	IPDst net.IP
+	// TCP/UDP source port number or equivalent
+	PortSrc uint32
+	// TCP/UDP destination port number or equivalent
+	PortDst uint32
+	// TCP flags
+	TCPFlags uint32
+	// IP priority
+	Priority uint32
+}
+
+func decodeSFlowIpv6Record(data *[]byte) (SFlowIpv6Record, error) {
+	si := SFlowIpv6Record{}
+
+	*data, si.Length = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, si.Protocol = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, si.IPSrc = (*data)[16:], net.IP((*data)[:16])
+	*data, si.IPDst = (*data)[16:], net.IP((*data)[:16])
+	*data, si.PortSrc = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, si.PortDst = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, si.TCPFlags = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, si.Priority = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+
+	return si, nil
+}
+
+// **************************************************
+//  Extended IPv4 Tunnel Egress
+// **************************************************
+
+//  0                      15                      31
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |      20 bit Interprise (0)     |12 bit format |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                  record length                |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  /           Packet IP version 4 Record          /
+//  /                                               /
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+type SFlowExtendedIpv4TunnelEgressRecord struct {
+	SFlowBaseFlowRecord
+	SFlowIpv4Record SFlowIpv4Record
+}
+
+func decodeExtendedIpv4TunnelEgress(data *[]byte) (SFlowExtendedIpv4TunnelEgressRecord, error) {
+	rec := SFlowExtendedIpv4TunnelEgressRecord{}
+	var fdf SFlowFlowDataFormat
+
+	*data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
+	rec.EnterpriseID, rec.Format = fdf.decode()
+	*data, rec.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	rec.SFlowIpv4Record, _ = decodeSFlowIpv4Record(data)
+
+	return rec, nil
+}
+
+// **************************************************
+//  Extended IPv4 Tunnel Ingress
+// **************************************************
+
+//  0                      15                      31
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |      20 bit Interprise (0)     |12 bit format |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                  record length                |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  /           Packet IP version 4 Record          /
+//  /                                               /
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+type SFlowExtendedIpv4TunnelIngressRecord struct {
+	SFlowBaseFlowRecord
+	SFlowIpv4Record SFlowIpv4Record
+}
+
+func decodeExtendedIpv4TunnelIngress(data *[]byte) (SFlowExtendedIpv4TunnelIngressRecord, error) {
+	rec := SFlowExtendedIpv4TunnelIngressRecord{}
+	var fdf SFlowFlowDataFormat
+
+	*data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
+	rec.EnterpriseID, rec.Format = fdf.decode()
+	*data, rec.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	rec.SFlowIpv4Record, _ = decodeSFlowIpv4Record(data)
+
+	return rec, nil
+}
+
+// **************************************************
+//  Extended IPv6 Tunnel Egress
+// **************************************************
+
+//  0                      15                      31
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |      20 bit Interprise (0)     |12 bit format |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                  record length                |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  /           Packet IP version 6 Record          /
+//  /                                               /
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+type SFlowExtendedIpv6TunnelEgressRecord struct {
+	SFlowBaseFlowRecord
+	SFlowIpv6Record
+}
+
+func decodeExtendedIpv6TunnelEgress(data *[]byte) (SFlowExtendedIpv6TunnelEgressRecord, error) {
+	rec := SFlowExtendedIpv6TunnelEgressRecord{}
+	var fdf SFlowFlowDataFormat
+
+	*data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
+	rec.EnterpriseID, rec.Format = fdf.decode()
+	*data, rec.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	rec.SFlowIpv6Record, _ = decodeSFlowIpv6Record(data)
+
+	return rec, nil
+}
+
+// **************************************************
+//  Extended IPv6 Tunnel Ingress
+// **************************************************
+
+//  0                      15                      31
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |      20 bit Interprise (0)     |12 bit format |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                  record length                |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  /           Packet IP version 6 Record          /
+//  /                                               /
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+type SFlowExtendedIpv6TunnelIngressRecord struct {
+	SFlowBaseFlowRecord
+	SFlowIpv6Record
+}
+
+func decodeExtendedIpv6TunnelIngress(data *[]byte) (SFlowExtendedIpv6TunnelIngressRecord, error) {
+	rec := SFlowExtendedIpv6TunnelIngressRecord{}
+	var fdf SFlowFlowDataFormat
+
+	*data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
+	rec.EnterpriseID, rec.Format = fdf.decode()
+	*data, rec.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	rec.SFlowIpv6Record, _ = decodeSFlowIpv6Record(data)
+
+	return rec, nil
+}
+
+// **************************************************
+//  Extended Decapsulate Egress
+// **************************************************
+
+//  0                      15                      31
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |      20 bit Interprise (0)     |12 bit format |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                  record length                |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |               Inner Header Offset             |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+type SFlowExtendedDecapsulateEgressRecord struct {
+	SFlowBaseFlowRecord
+	InnerHeaderOffset uint32
+}
+
+func decodeExtendedDecapsulateEgress(data *[]byte) (SFlowExtendedDecapsulateEgressRecord, error) {
+	rec := SFlowExtendedDecapsulateEgressRecord{}
+	var fdf SFlowFlowDataFormat
+
+	*data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
+	rec.EnterpriseID, rec.Format = fdf.decode()
+	*data, rec.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, rec.InnerHeaderOffset = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+
+	return rec, nil
+}
+
+// **************************************************
+//  Extended Decapsulate Ingress
+// **************************************************
+
+//  0                      15                      31
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |      20 bit Interprise (0)     |12 bit format |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                  record length                |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |               Inner Header Offset             |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+type SFlowExtendedDecapsulateIngressRecord struct {
+	SFlowBaseFlowRecord
+	InnerHeaderOffset uint32
+}
+
+func decodeExtendedDecapsulateIngress(data *[]byte) (SFlowExtendedDecapsulateIngressRecord, error) {
+	rec := SFlowExtendedDecapsulateIngressRecord{}
+	var fdf SFlowFlowDataFormat
+
+	*data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
+	rec.EnterpriseID, rec.Format = fdf.decode()
+	*data, rec.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, rec.InnerHeaderOffset = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+
+	return rec, nil
+}
+
+// **************************************************
+//  Extended VNI Egress
+// **************************************************
+
+//  0                      15                      31
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |      20 bit Interprise (0)     |12 bit format |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                  record length                |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                       VNI                     |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+type SFlowExtendedVniEgressRecord struct {
+	SFlowBaseFlowRecord
+	VNI uint32
+}
+
+func decodeExtendedVniEgress(data *[]byte) (SFlowExtendedVniEgressRecord, error) {
+	rec := SFlowExtendedVniEgressRecord{}
+	var fdf SFlowFlowDataFormat
+
+	*data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
+	rec.EnterpriseID, rec.Format = fdf.decode()
+	*data, rec.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, rec.VNI = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+
+	return rec, nil
+}
+
+// **************************************************
+//  Extended VNI Ingress
+// **************************************************
+
+//  0                      15                      31
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |      20 bit Interprise (0)     |12 bit format |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                  record length                |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                       VNI                     |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+type SFlowExtendedVniIngressRecord struct {
+	SFlowBaseFlowRecord
+	VNI uint32
+}
+
+func decodeExtendedVniIngress(data *[]byte) (SFlowExtendedVniIngressRecord, error) {
+	rec := SFlowExtendedVniIngressRecord{}
+	var fdf SFlowFlowDataFormat
+
+	*data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
+	rec.EnterpriseID, rec.Format = fdf.decode()
+	*data, rec.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, rec.VNI = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+
+	return rec, nil
+}
+
+// **************************************************
+//  Counter Record
+// **************************************************
+
+//  0                      15                      31
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |      20 bit Interprise (0)     |12 bit format |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                  counter length               |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  /                   counter data                /
+//  /                                               /
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+type SFlowBaseCounterRecord struct {
+	EnterpriseID   SFlowEnterpriseID
+	Format         SFlowCounterRecordType
+	FlowDataLength uint32
+}
+
+func (bcr SFlowBaseCounterRecord) GetType() SFlowCounterRecordType {
+	switch bcr.Format {
+	case SFlowTypeGenericInterfaceCounters:
+		return SFlowTypeGenericInterfaceCounters
+	case SFlowTypeEthernetInterfaceCounters:
+		return SFlowTypeEthernetInterfaceCounters
+	case SFlowTypeTokenRingInterfaceCounters:
+		return SFlowTypeTokenRingInterfaceCounters
+	case SFlowType100BaseVGInterfaceCounters:
+		return SFlowType100BaseVGInterfaceCounters
+	case SFlowTypeVLANCounters:
+		return SFlowTypeVLANCounters
+	case SFlowTypeLACPCounters:
+		return SFlowTypeLACPCounters
+	case SFlowTypeProcessorCounters:
+		return SFlowTypeProcessorCounters
+	case SFlowTypeOpenflowPortCounters:
+		return SFlowTypeOpenflowPortCounters
+	case SFlowTypePORTNAMECounters:
+		return SFlowTypePORTNAMECounters
+	case SFLowTypeAPPRESOURCESCounters:
+		return SFLowTypeAPPRESOURCESCounters
+	case SFlowTypeOVSDPCounters:
+		return SFlowTypeOVSDPCounters
+	}
+	unrecognized := fmt.Sprint("Unrecognized counter record type:", bcr.Format)
+	panic(unrecognized)
+}
+
+// **************************************************
+//  Counter Record
+// **************************************************
+
+//  0                      15                      31
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |      20 bit Interprise (0)     |12 bit format |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                  counter length               |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                    IfIndex                    |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                    IfType                     |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                   IfSpeed                     |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                   IfDirection                 |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                    IfStatus                   |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                   IFInOctets                  |
+//  |                                               |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                   IfInUcastPkts               |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                  IfInMulticastPkts            |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                  IfInBroadcastPkts            |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                    IfInDiscards               |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                    InInErrors                 |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                  IfInUnknownProtos            |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                   IfOutOctets                 |
+//  |                                               |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                   IfOutUcastPkts              |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                  IfOutMulticastPkts           |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                  IfOutBroadcastPkts           |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                   IfOutDiscards               |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                    IfOUtErrors                |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                 IfPromiscouousMode            |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+type SFlowGenericInterfaceCounters struct {
+	SFlowBaseCounterRecord
+	IfIndex            uint32
+	IfType             uint32
+	IfSpeed            uint64
+	IfDirection        uint32
+	IfStatus           uint32
+	IfInOctets         uint64
+	IfInUcastPkts      uint32
+	IfInMulticastPkts  uint32
+	IfInBroadcastPkts  uint32
+	IfInDiscards       uint32
+	IfInErrors         uint32
+	IfInUnknownProtos  uint32
+	IfOutOctets        uint64
+	IfOutUcastPkts     uint32
+	IfOutMulticastPkts uint32
+	IfOutBroadcastPkts uint32
+	IfOutDiscards      uint32
+	IfOutErrors        uint32
+	IfPromiscuousMode  uint32
+}
+
+func decodeGenericInterfaceCounters(data *[]byte) (SFlowGenericInterfaceCounters, error) {
+	gic := SFlowGenericInterfaceCounters{}
+	var cdf SFlowCounterDataFormat
+
+	*data, cdf = (*data)[4:], SFlowCounterDataFormat(binary.BigEndian.Uint32((*data)[:4]))
+	gic.EnterpriseID, gic.Format = cdf.decode()
+	*data, gic.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, gic.IfIndex = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, gic.IfType = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, gic.IfSpeed = (*data)[8:], binary.BigEndian.Uint64((*data)[:8])
+	*data, gic.IfDirection = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, gic.IfStatus = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, gic.IfInOctets = (*data)[8:], binary.BigEndian.Uint64((*data)[:8])
+	*data, gic.IfInUcastPkts = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, gic.IfInMulticastPkts = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, gic.IfInBroadcastPkts = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, gic.IfInDiscards = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, gic.IfInErrors = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, gic.IfInUnknownProtos = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, gic.IfOutOctets = (*data)[8:], binary.BigEndian.Uint64((*data)[:8])
+	*data, gic.IfOutUcastPkts = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, gic.IfOutMulticastPkts = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, gic.IfOutBroadcastPkts = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, gic.IfOutDiscards = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, gic.IfOutErrors = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, gic.IfPromiscuousMode = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	return gic, nil
+}
+
+// **************************************************
+//  Counter Record
+// **************************************************
+
+//  0                      15                      31
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |      20 bit Interprise (0)     |12 bit format |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                  counter length               |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  /                   counter data                /
+//  /                                               /
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+type SFlowEthernetCounters struct {
+	SFlowBaseCounterRecord
+	AlignmentErrors           uint32
+	FCSErrors                 uint32
+	SingleCollisionFrames     uint32
+	MultipleCollisionFrames   uint32
+	SQETestErrors             uint32
+	DeferredTransmissions     uint32
+	LateCollisions            uint32
+	ExcessiveCollisions       uint32
+	InternalMacTransmitErrors uint32
+	CarrierSenseErrors        uint32
+	FrameTooLongs             uint32
+	InternalMacReceiveErrors  uint32
+	SymbolErrors              uint32
+}
+
+func decodeEthernetCounters(data *[]byte) (SFlowEthernetCounters, error) {
+	ec := SFlowEthernetCounters{}
+	var cdf SFlowCounterDataFormat
+
+	*data, cdf = (*data)[4:], SFlowCounterDataFormat(binary.BigEndian.Uint32((*data)[:4]))
+	ec.EnterpriseID, ec.Format = cdf.decode()
+	*data, ec.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, ec.AlignmentErrors = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, ec.FCSErrors = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, ec.SingleCollisionFrames = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, ec.MultipleCollisionFrames = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, ec.SQETestErrors = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, ec.DeferredTransmissions = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, ec.LateCollisions = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, ec.ExcessiveCollisions = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, ec.InternalMacTransmitErrors = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, ec.CarrierSenseErrors = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, ec.FrameTooLongs = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, ec.InternalMacReceiveErrors = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, ec.SymbolErrors = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	return ec, nil
+}
+
+// VLAN Counter
+
+type SFlowVLANCounters struct {
+	SFlowBaseCounterRecord
+	VlanID        uint32
+	Octets        uint64
+	UcastPkts     uint32
+	MulticastPkts uint32
+	BroadcastPkts uint32
+	Discards      uint32
+}
+
+func decodeVLANCounters(data *[]byte) (SFlowVLANCounters, error) {
+	vc := SFlowVLANCounters{}
+	var cdf SFlowCounterDataFormat
+
+	*data, cdf = (*data)[4:], SFlowCounterDataFormat(binary.BigEndian.Uint32((*data)[:4]))
+	vc.EnterpriseID, vc.Format = cdf.decode()
+	vc.EnterpriseID, vc.Format = cdf.decode()
+	*data, vc.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, vc.VlanID = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, vc.Octets = (*data)[8:], binary.BigEndian.Uint64((*data)[:8])
+	*data, vc.UcastPkts = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, vc.MulticastPkts = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, vc.BroadcastPkts = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, vc.Discards = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	return vc, nil
+}
+
+//SFLLACPportState  :  SFlow LACP Port State (All(4) - 32 bit)
+type SFLLACPPortState struct {
+	PortStateAll uint32
+}
+
+//LACPcounters  :  LACP SFlow Counters  ( 64 Bytes )
+type SFlowLACPCounters struct {
+	SFlowBaseCounterRecord
+	ActorSystemID        net.HardwareAddr
+	PartnerSystemID      net.HardwareAddr
+	AttachedAggID        uint32
+	LacpPortState        SFLLACPPortState
+	LACPDUsRx            uint32
+	MarkerPDUsRx         uint32
+	MarkerResponsePDUsRx uint32
+	UnknownRx            uint32
+	IllegalRx            uint32
+	LACPDUsTx            uint32
+	MarkerPDUsTx         uint32
+	MarkerResponsePDUsTx uint32
+}
+
+func decodeLACPCounters(data *[]byte) (SFlowLACPCounters, error) {
+	la := SFlowLACPCounters{}
+	var cdf SFlowCounterDataFormat
+
+	*data, cdf = (*data)[4:], SFlowCounterDataFormat(binary.BigEndian.Uint32((*data)[:4]))
+	la.EnterpriseID, la.Format = cdf.decode()
+	*data, la.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, la.ActorSystemID = (*data)[6:], (*data)[:6]
+	*data = (*data)[2:] // remove padding
+	*data, la.PartnerSystemID = (*data)[6:], (*data)[:6]
+	*data = (*data)[2:] //remove padding
+	*data, la.AttachedAggID = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, la.LacpPortState.PortStateAll = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, la.LACPDUsRx = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, la.MarkerPDUsRx = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, la.MarkerResponsePDUsRx = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, la.UnknownRx = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, la.IllegalRx = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, la.LACPDUsTx = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, la.MarkerPDUsTx = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, la.MarkerResponsePDUsTx = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+
+	return la, nil
+
+}
+
+// **************************************************
+//  Processor Counter Record
+// **************************************************
+//  0                      15                      31
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |      20 bit Interprise (0)     |12 bit format |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                  counter length               |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                    FiveSecCpu                 |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                    OneMinCpu                  |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                    GiveMinCpu                 |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                   TotalMemory                 |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                    FreeMemory                 |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+type SFlowProcessorCounters struct {
+	SFlowBaseCounterRecord
+	FiveSecCpu  uint32 // 5 second average CPU utilization
+	OneMinCpu   uint32 // 1 minute average CPU utilization
+	FiveMinCpu  uint32 // 5 minute average CPU utilization
+	TotalMemory uint64 // total memory (in bytes)
+	FreeMemory  uint64 // free memory (in bytes)
+}
+
+func decodeProcessorCounters(data *[]byte) (SFlowProcessorCounters, error) {
+	pc := SFlowProcessorCounters{}
+	var cdf SFlowCounterDataFormat
+	var high32, low32 uint32
+
+	*data, cdf = (*data)[4:], SFlowCounterDataFormat(binary.BigEndian.Uint32((*data)[:4]))
+	pc.EnterpriseID, pc.Format = cdf.decode()
+	*data, pc.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+
+	*data, pc.FiveSecCpu = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, pc.OneMinCpu = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, pc.FiveMinCpu = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, high32 = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, low32 = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	pc.TotalMemory = (uint64(high32) << 32) + uint64(low32)
+	*data, high32 = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, low32 = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	pc.FreeMemory = (uint64(high32)) + uint64(low32)
+
+	return pc, nil
+}
+
+// SFlowEthernetFrameFlowRecord give additional information
+// about the sampled packet if it's available.
+// An agent may or may not provide this information.
+type SFlowEthernetFrameFlowRecord struct {
+	SFlowBaseFlowRecord
+	FrameLength uint32
+	SrcMac      net.HardwareAddr
+	DstMac      net.HardwareAddr
+	Type        uint32
+}
+
+// Ethernet frame flow records have the following structure:
+
+//  0                      15                      31
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |      20 bit Interprise (0)     |12 bit format |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                  record length                |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |                Source Mac Address             |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |             Destination Mac Address           |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+//  |               Ethernet Packet Type            |
+//  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+func decodeEthernetFrameFlowRecord(data *[]byte) (SFlowEthernetFrameFlowRecord, error) {
+	es := SFlowEthernetFrameFlowRecord{}
+	var fdf SFlowFlowDataFormat
+
+	*data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
+	es.EnterpriseID, es.Format = fdf.decode()
+	*data, es.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+
+	*data, es.FrameLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, es.SrcMac = (*data)[8:], net.HardwareAddr((*data)[:6])
+	*data, es.DstMac = (*data)[8:], net.HardwareAddr((*data)[:6])
+	*data, es.Type = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	return es, nil
+}
+
+//SFlowOpenflowPortCounters  :  OVS-Sflow OpenFlow Port Counter  ( 20 Bytes )
+type SFlowOpenflowPortCounters struct {
+	SFlowBaseCounterRecord
+	DatapathID uint64
+	PortNo     uint32
+}
+
+func decodeOpenflowportCounters(data *[]byte) (SFlowOpenflowPortCounters, error) {
+	ofp := SFlowOpenflowPortCounters{}
+	var cdf SFlowCounterDataFormat
+
+	*data, cdf = (*data)[4:], SFlowCounterDataFormat(binary.BigEndian.Uint32((*data)[:4]))
+	ofp.EnterpriseID, ofp.Format = cdf.decode()
+	*data, ofp.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, ofp.DatapathID = (*data)[8:], binary.BigEndian.Uint64((*data)[:8])
+	*data, ofp.PortNo = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+
+	return ofp, nil
+}
+
+//SFlowAppresourcesCounters  :  OVS_Sflow App Resources Counter ( 48 Bytes )
+type SFlowAppresourcesCounters struct {
+	SFlowBaseCounterRecord
+	UserTime   uint32
+	SystemTime uint32
+	MemUsed    uint64
+	MemMax     uint64
+	FdOpen     uint32
+	FdMax      uint32
+	ConnOpen   uint32
+	ConnMax    uint32
+}
+
+func decodeAppresourcesCounters(data *[]byte) (SFlowAppresourcesCounters, error) {
+	app := SFlowAppresourcesCounters{}
+	var cdf SFlowCounterDataFormat
+
+	*data, cdf = (*data)[4:], SFlowCounterDataFormat(binary.BigEndian.Uint32((*data)[:4]))
+	app.EnterpriseID, app.Format = cdf.decode()
+	*data, app.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, app.UserTime = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, app.SystemTime = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, app.MemUsed = (*data)[8:], binary.BigEndian.Uint64((*data)[:8])
+	*data, app.MemMax = (*data)[8:], binary.BigEndian.Uint64((*data)[:8])
+	*data, app.FdOpen = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, app.FdMax = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, app.ConnOpen = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, app.ConnMax = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+
+	return app, nil
+}
+
+//SFlowOVSDPCounters  :  OVS-Sflow DataPath Counter  ( 32 Bytes )
+type SFlowOVSDPCounters struct {
+	SFlowBaseCounterRecord
+	NHit     uint32
+	NMissed  uint32
+	NLost    uint32
+	NMaskHit uint32
+	NFlows   uint32
+	NMasks   uint32
+}
+
+func decodeOVSDPCounters(data *[]byte) (SFlowOVSDPCounters, error) {
+	dp := SFlowOVSDPCounters{}
+	var cdf SFlowCounterDataFormat
+
+	*data, cdf = (*data)[4:], SFlowCounterDataFormat(binary.BigEndian.Uint32((*data)[:4]))
+	dp.EnterpriseID, dp.Format = cdf.decode()
+	*data, dp.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, dp.NHit = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, dp.NMissed = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, dp.NLost = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, dp.NMaskHit = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, dp.NFlows = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	*data, dp.NMasks = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+
+	return dp, nil
+}
+
+//SFlowPORTNAME  :  OVS-Sflow PORTNAME Counter Sampletype ( 20 Bytes )
+type SFlowPORTNAME struct {
+	SFlowBaseCounterRecord
+	Len uint32
+	Str string
+}
+
+func decodeString(data *[]byte) (len uint32, str string) {
+	*data, len = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	str = string((*data)[:len])
+	if (len % 4) != 0 {
+		len += 4 - len%4
+	}
+	*data = (*data)[len:]
+	return
+}
+
+func decodePortnameCounters(data *[]byte) (SFlowPORTNAME, error) {
+	pn := SFlowPORTNAME{}
+	var cdf SFlowCounterDataFormat
+
+	*data, cdf = (*data)[4:], SFlowCounterDataFormat(binary.BigEndian.Uint32((*data)[:4]))
+	pn.EnterpriseID, pn.Format = cdf.decode()
+	*data, pn.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
+	pn.Len, pn.Str = decodeString(data)
+
+	return pn, nil
+}