286 lines
7.3 KiB
Go
286 lines
7.3 KiB
Go
package sflow
|
|
|
|
import (
|
|
"net"
|
|
"strconv"
|
|
)
|
|
|
|
const (
|
|
AddressTypeIPv6 uint32 = 2 // sflow_version_5.txt line: 1384
|
|
AddressTypeIPv4 uint32 = 1 // sflow_version_5.txt line: 1383
|
|
|
|
IPProtocolTCP uint8 = 6
|
|
IPProtocolUDP uint8 = 17
|
|
|
|
metricName = "sflow"
|
|
)
|
|
|
|
var ETypeMap = map[uint16]string{
|
|
0x0800: "IPv4",
|
|
0x86DD: "IPv6",
|
|
}
|
|
|
|
var IPvMap = map[uint32]string{
|
|
1: "IPV4", // sflow_version_5.txt line: 1383
|
|
2: "IPV6", // sflow_version_5.txt line: 1384
|
|
}
|
|
|
|
type ContainsMetricData interface {
|
|
GetTags() map[string]string
|
|
GetFields() map[string]interface{}
|
|
}
|
|
|
|
// V5Format answers and decoder.Directive capable of decoding sFlow v5 packets in accordance
|
|
// with SFlow v5 specification at https://sflow.org/sflow_version_5.txt
|
|
type V5Format struct {
|
|
Version uint32
|
|
AgentAddress net.IPAddr
|
|
SubAgentID uint32
|
|
SequenceNumber uint32
|
|
Uptime uint32
|
|
Samples []Sample
|
|
}
|
|
|
|
type SampleType uint32
|
|
|
|
const (
|
|
SampleTypeFlowSample SampleType = 1 // sflow_version_5.txt line: 1614
|
|
SampleTypeFlowSampleExpanded SampleType = 3 // sflow_version_5.txt line: 1698
|
|
)
|
|
|
|
type SampleData interface{}
|
|
|
|
type Sample struct {
|
|
SampleType SampleType
|
|
SampleData SampleDataFlowSampleExpanded
|
|
}
|
|
|
|
type SampleDataFlowSampleExpanded struct {
|
|
SequenceNumber uint32
|
|
SourceIDType uint32
|
|
SourceIDIndex uint32
|
|
SamplingRate uint32
|
|
SamplePool uint32
|
|
Drops uint32
|
|
SampleDirection string // ingress/egress
|
|
InputIfFormat uint32
|
|
InputIfIndex uint32
|
|
OutputIfFormat uint32
|
|
OutputIfIndex uint32
|
|
FlowRecords []FlowRecord
|
|
}
|
|
|
|
type FlowFormatType uint32
|
|
|
|
const (
|
|
FlowFormatTypeRawPacketHeader FlowFormatType = 1 // sflow_version_5.txt line: 1938
|
|
)
|
|
|
|
type FlowData ContainsMetricData
|
|
|
|
type FlowRecord struct {
|
|
FlowFormat FlowFormatType
|
|
FlowData FlowData
|
|
}
|
|
|
|
type HeaderProtocolType uint32
|
|
|
|
const (
|
|
HeaderProtocolTypeEthernetISO88023 HeaderProtocolType = 1
|
|
HeaderProtocolTypeISO88024TokenBus HeaderProtocolType = 2
|
|
HeaderProtocolTypeISO88025TokenRing HeaderProtocolType = 3
|
|
HeaderProtocolTypeFDDI HeaderProtocolType = 4
|
|
HeaderProtocolTypeFrameRelay HeaderProtocolType = 5
|
|
HeaderProtocolTypeX25 HeaderProtocolType = 6
|
|
HeaderProtocolTypePPP HeaderProtocolType = 7
|
|
HeaderProtocolTypeSMDS HeaderProtocolType = 8
|
|
HeaderProtocolTypeAAL5 HeaderProtocolType = 9
|
|
HeaderProtocolTypeAAL5IP HeaderProtocolType = 10 /* e.g. Cisco AAL5 mux */
|
|
HeaderProtocolTypeIPv4 HeaderProtocolType = 11
|
|
HeaderProtocolTypeIPv6 HeaderProtocolType = 12
|
|
HeaderProtocolTypeMPLS HeaderProtocolType = 13
|
|
HeaderProtocolTypePOS HeaderProtocolType = 14 /* RFC 1662, 2615 */
|
|
)
|
|
|
|
var HeaderProtocolMap = map[HeaderProtocolType]string{
|
|
HeaderProtocolTypeEthernetISO88023: "ETHERNET-ISO88023", // sflow_version_5.txt line: 1920
|
|
}
|
|
|
|
type Header ContainsMetricData
|
|
|
|
type RawPacketHeaderFlowData struct {
|
|
HeaderProtocol HeaderProtocolType
|
|
FrameLength uint32
|
|
Bytes uint32
|
|
StrippedOctets uint32
|
|
HeaderLength uint32
|
|
Header Header
|
|
}
|
|
|
|
func (h RawPacketHeaderFlowData) GetTags() map[string]string {
|
|
t := h.Header.GetTags()
|
|
t["header_protocol"] = HeaderProtocolMap[h.HeaderProtocol]
|
|
return t
|
|
}
|
|
func (h RawPacketHeaderFlowData) GetFields() map[string]interface{} {
|
|
f := h.Header.GetFields()
|
|
f["bytes"] = h.Bytes
|
|
f["frame_length"] = h.FrameLength
|
|
f["header_length"] = h.HeaderLength
|
|
return f
|
|
}
|
|
|
|
type IPHeader ContainsMetricData
|
|
|
|
type EthHeader struct {
|
|
DestinationMAC [6]byte
|
|
SourceMAC [6]byte
|
|
TagProtocolIdentifier uint16
|
|
TagControlInformation uint16
|
|
EtherTypeCode uint16
|
|
EtherType string
|
|
IPHeader IPHeader
|
|
}
|
|
|
|
func (h EthHeader) GetTags() map[string]string {
|
|
t := h.IPHeader.GetTags()
|
|
t["src_mac"] = net.HardwareAddr(h.SourceMAC[:]).String()
|
|
t["dst_mac"] = net.HardwareAddr(h.DestinationMAC[:]).String()
|
|
t["ether_type"] = h.EtherType
|
|
return t
|
|
}
|
|
func (h EthHeader) GetFields() map[string]interface{} {
|
|
return h.IPHeader.GetFields()
|
|
}
|
|
|
|
type ProtocolHeader ContainsMetricData
|
|
|
|
// https://en.wikipedia.org/wiki/IPv4#Header
|
|
type IPV4Header struct {
|
|
Version uint8 // 4 bit
|
|
InternetHeaderLength uint8 // 4 bit
|
|
DSCP uint8
|
|
ECN uint8
|
|
TotalLength uint16
|
|
Identification uint16
|
|
Flags uint8
|
|
FragmentOffset uint16
|
|
TTL uint8
|
|
Protocol uint8 // https://en.wikipedia.org/wiki/List_of_IP_protocol_numbers
|
|
HeaderChecksum uint16
|
|
SourceIP [4]byte
|
|
DestIP [4]byte
|
|
ProtocolHeader ProtocolHeader
|
|
}
|
|
|
|
func (h IPV4Header) GetTags() map[string]string {
|
|
var t map[string]string
|
|
if h.ProtocolHeader != nil {
|
|
t = h.ProtocolHeader.GetTags()
|
|
} else {
|
|
t = map[string]string{}
|
|
}
|
|
t["src_ip"] = net.IP(h.SourceIP[:]).String()
|
|
t["dst_ip"] = net.IP(h.DestIP[:]).String()
|
|
return t
|
|
}
|
|
func (h IPV4Header) GetFields() map[string]interface{} {
|
|
var f map[string]interface{}
|
|
if h.ProtocolHeader != nil {
|
|
f = h.ProtocolHeader.GetFields()
|
|
} else {
|
|
f = map[string]interface{}{}
|
|
}
|
|
f["ip_dscp"] = strconv.FormatUint(uint64(h.DSCP), 10)
|
|
f["ip_ecn"] = strconv.FormatUint(uint64(h.ECN), 10)
|
|
f["ip_flags"] = h.Flags
|
|
f["ip_fragment_offset"] = h.FragmentOffset
|
|
f["ip_total_length"] = h.TotalLength
|
|
f["ip_ttl"] = h.TTL
|
|
return f
|
|
}
|
|
|
|
// https://en.wikipedia.org/wiki/IPv6_packet
|
|
type IPV6Header struct {
|
|
DSCP uint8
|
|
ECN uint8
|
|
PayloadLength uint16
|
|
NextHeaderProto uint8 // tcp/udp?
|
|
HopLimit uint8
|
|
SourceIP [16]byte
|
|
DestIP [16]byte
|
|
ProtocolHeader ProtocolHeader
|
|
}
|
|
|
|
func (h IPV6Header) GetTags() map[string]string {
|
|
var t map[string]string
|
|
if h.ProtocolHeader != nil {
|
|
t = h.ProtocolHeader.GetTags()
|
|
} else {
|
|
t = map[string]string{}
|
|
}
|
|
t["src_ip"] = net.IP(h.SourceIP[:]).String()
|
|
t["dst_ip"] = net.IP(h.DestIP[:]).String()
|
|
return t
|
|
}
|
|
func (h IPV6Header) GetFields() map[string]interface{} {
|
|
var f map[string]interface{}
|
|
if h.ProtocolHeader != nil {
|
|
f = h.ProtocolHeader.GetFields()
|
|
} else {
|
|
f = map[string]interface{}{}
|
|
}
|
|
f["ip_dscp"] = strconv.FormatUint(uint64(h.DSCP), 10)
|
|
f["ip_ecn"] = strconv.FormatUint(uint64(h.ECN), 10)
|
|
f["payload_length"] = h.PayloadLength
|
|
return f
|
|
}
|
|
|
|
// https://en.wikipedia.org/wiki/Transmission_Control_Protocol
|
|
type TCPHeader struct {
|
|
SourcePort uint16
|
|
DestinationPort uint16
|
|
Sequence uint32
|
|
AckNumber uint32
|
|
TCPHeaderLength uint8
|
|
Flags uint16
|
|
TCPWindowSize uint16
|
|
Checksum uint16
|
|
TCPUrgentPointer uint16
|
|
}
|
|
|
|
func (h TCPHeader) GetTags() map[string]string {
|
|
t := map[string]string{
|
|
"dst_port": strconv.FormatUint(uint64(h.DestinationPort), 10),
|
|
"src_port": strconv.FormatUint(uint64(h.SourcePort), 10),
|
|
}
|
|
return t
|
|
}
|
|
func (h TCPHeader) GetFields() map[string]interface{} {
|
|
return map[string]interface{}{
|
|
"tcp_header_length": h.TCPHeaderLength,
|
|
"tcp_urgent_pointer": h.TCPUrgentPointer,
|
|
"tcp_window_size": h.TCPWindowSize,
|
|
}
|
|
}
|
|
|
|
type UDPHeader struct {
|
|
SourcePort uint16
|
|
DestinationPort uint16
|
|
UDPLength uint16
|
|
Checksum uint16
|
|
}
|
|
|
|
func (h UDPHeader) GetTags() map[string]string {
|
|
t := map[string]string{
|
|
"dst_port": strconv.FormatUint(uint64(h.DestinationPort), 10),
|
|
"src_port": strconv.FormatUint(uint64(h.SourcePort), 10),
|
|
}
|
|
return t
|
|
}
|
|
func (h UDPHeader) GetFields() map[string]interface{} {
|
|
return map[string]interface{}{
|
|
"udp_length": h.UDPLength,
|
|
}
|
|
}
|