blob: c56fe89d21fd11990f2b363c680a7e5872d7513d [file] [log] [blame]
Takahiro Suzukid7bf8202020-12-17 20:21:59 +09001// Copyright 2014 Google, Inc. All rights reserved.
2//
3// Use of this source code is governed by a BSD-style license
4// that can be found in the LICENSE file in the root of the source
5// tree.
6
7/*
8This layer decodes SFlow version 5 datagrams.
9
10The specification can be found here: http://sflow.org/sflow_version_5.txt
11
12Additional developer information about sflow can be found at:
13http://sflow.org/developers/specifications.php
14
15And SFlow in general:
16http://sflow.org/index.php
17
18Two forms of sample data are defined: compact and expanded. The
19Specification has this to say:
20
21 Compact and expand forms of counter and flow samples are defined.
22 An agent must not mix compact/expanded encodings. If an agent
23 will never use ifIndex numbers >= 2^24 then it must use compact
24 encodings for all interfaces. Otherwise the expanded formats must
25 be used for all interfaces.
26
27This decoder only supports the compact form, because that is the only
28one for which data was avaialble.
29
30The datagram is composed of one or more samples of type flow or counter,
31and each sample is composed of one or more records describing the sample.
32A sample is a single instance of sampled inforamtion, and each record in
33the sample gives additional / supplimentary information about the sample.
34
35The following sample record types are supported:
36
37 Raw Packet Header
38 opaque = flow_data; enterprise = 0; format = 1
39
40 Extended Switch Data
41 opaque = flow_data; enterprise = 0; format = 1001
42
43 Extended Router Data
44 opaque = flow_data; enterprise = 0; format = 1002
45
46 Extended Gateway Data
47 opaque = flow_data; enterprise = 0; format = 1003
48
49 Extended User Data
50 opaque = flow_data; enterprise = 0; format = 1004
51
52 Extended URL Data
53 opaque = flow_data; enterprise = 0; format = 1005
54
55The following types of counter records are supported:
56
57 Generic Interface Counters - see RFC 2233
58 opaque = counter_data; enterprise = 0; format = 1
59
60 Ethernet Interface Counters - see RFC 2358
61 opaque = counter_data; enterprise = 0; format = 2
62
63SFlow is encoded using XDR (RFC4506). There are a few places
64where the standard 4-byte fields are partitioned into two
65bitfields of different lengths. I'm not sure why the designers
66chose to pack together two values like this in some places, and
67in others they use the entire 4-byte value to store a number that
68will never be more than a few bits. In any case, there are a couple
69of types defined to handle the decoding of these bitfields, and
70that's why they're there. */
71
72package layers
73
74import (
75 "encoding/binary"
76 "errors"
77 "fmt"
78 "net"
79
80 "github.com/google/gopacket"
81)
82
83// SFlowRecord holds both flow sample records and counter sample records.
84// A Record is the structure that actually holds the sampled data
85// and / or counters.
86type SFlowRecord interface {
87}
88
89// SFlowDataSource encodes a 2-bit SFlowSourceFormat in its most significant
90// 2 bits, and an SFlowSourceValue in its least significant 30 bits.
91// These types and values define the meaning of the inteface information
92// presented in the sample metadata.
93type SFlowDataSource int32
94
95func (sdc SFlowDataSource) decode() (SFlowSourceFormat, SFlowSourceValue) {
96 leftField := sdc >> 30
97 rightField := uint32(0x3FFFFFFF) & uint32(sdc)
98 return SFlowSourceFormat(leftField), SFlowSourceValue(rightField)
99}
100
101type SFlowDataSourceExpanded struct {
102 SourceIDClass SFlowSourceFormat
103 SourceIDIndex SFlowSourceValue
104}
105
106func (sdce SFlowDataSourceExpanded) decode() (SFlowSourceFormat, SFlowSourceValue) {
107 leftField := sdce.SourceIDClass >> 30
108 rightField := uint32(0x3FFFFFFF) & uint32(sdce.SourceIDIndex)
109 return SFlowSourceFormat(leftField), SFlowSourceValue(rightField)
110}
111
112type SFlowSourceFormat uint32
113
114type SFlowSourceValue uint32
115
116const (
117 SFlowTypeSingleInterface SFlowSourceFormat = 0
118 SFlowTypePacketDiscarded SFlowSourceFormat = 1
119 SFlowTypeMultipleDestinations SFlowSourceFormat = 2
120)
121
122func (sdf SFlowSourceFormat) String() string {
123 switch sdf {
124 case SFlowTypeSingleInterface:
125 return "Single Interface"
126 case SFlowTypePacketDiscarded:
127 return "Packet Discarded"
128 case SFlowTypeMultipleDestinations:
129 return "Multiple Destinations"
130 default:
131 return "UNKNOWN"
132 }
133}
134
135func decodeSFlow(data []byte, p gopacket.PacketBuilder) error {
136 s := &SFlowDatagram{}
137 err := s.DecodeFromBytes(data, p)
138 if err != nil {
139 return err
140 }
141 p.AddLayer(s)
142 p.SetApplicationLayer(s)
143 return nil
144}
145
146// SFlowDatagram is the outermost container which holds some basic information
147// about the reporting agent, and holds at least one sample record
148type SFlowDatagram struct {
149 BaseLayer
150
151 DatagramVersion uint32
152 AgentAddress net.IP
153 SubAgentID uint32
154 SequenceNumber uint32
155 AgentUptime uint32
156 SampleCount uint32
157 FlowSamples []SFlowFlowSample
158 CounterSamples []SFlowCounterSample
159}
160
161// An SFlow datagram's outer container has the following
162// structure:
163
164// 0 15 31
165// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
166// | int sFlow version (2|4|5) |
167// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
168// | int IP version of the Agent (1=v4|2=v6) |
169// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
170// / Agent IP address (v4=4byte|v6=16byte) /
171// / /
172// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
173// | int sub agent id |
174// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
175// | int datagram sequence number |
176// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
177// | int switch uptime in ms |
178// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
179// | int n samples in datagram |
180// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
181// / n samples /
182// / /
183// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
184
185// SFlowDataFormat encodes the EnterpriseID in the most
186// significant 12 bits, and the SampleType in the least significant
187// 20 bits.
188type SFlowDataFormat uint32
189
190func (sdf SFlowDataFormat) decode() (SFlowEnterpriseID, SFlowSampleType) {
191 leftField := sdf >> 12
192 rightField := uint32(0xFFF) & uint32(sdf)
193 return SFlowEnterpriseID(leftField), SFlowSampleType(rightField)
194}
195
196// SFlowEnterpriseID is used to differentiate between the
197// official SFlow standard, and other, vendor-specific
198// types of flow data. (Similiar to SNMP's enterprise MIB
199// OIDs) Only the office SFlow Enterprise ID is decoded
200// here.
201type SFlowEnterpriseID uint32
202
203const (
204 SFlowStandard SFlowEnterpriseID = 0
205)
206
207func (eid SFlowEnterpriseID) String() string {
208 switch eid {
209 case SFlowStandard:
210 return "Standard SFlow"
211 default:
212 return ""
213 }
214}
215
216func (eid SFlowEnterpriseID) GetType() SFlowEnterpriseID {
217 return SFlowStandard
218}
219
220// SFlowSampleType specifies the type of sample. Only flow samples
221// and counter samples are supported
222type SFlowSampleType uint32
223
224const (
225 SFlowTypeFlowSample SFlowSampleType = 1
226 SFlowTypeCounterSample SFlowSampleType = 2
227 SFlowTypeExpandedFlowSample SFlowSampleType = 3
228 SFlowTypeExpandedCounterSample SFlowSampleType = 4
229)
230
231func (st SFlowSampleType) GetType() SFlowSampleType {
232 switch st {
233 case SFlowTypeFlowSample:
234 return SFlowTypeFlowSample
235 case SFlowTypeCounterSample:
236 return SFlowTypeCounterSample
237 case SFlowTypeExpandedFlowSample:
238 return SFlowTypeExpandedFlowSample
239 case SFlowTypeExpandedCounterSample:
240 return SFlowTypeExpandedCounterSample
241 default:
242 panic("Invalid Sample Type")
243 }
244}
245
246func (st SFlowSampleType) String() string {
247 switch st {
248 case SFlowTypeFlowSample:
249 return "Flow Sample"
250 case SFlowTypeCounterSample:
251 return "Counter Sample"
252 case SFlowTypeExpandedFlowSample:
253 return "Expanded Flow Sample"
254 case SFlowTypeExpandedCounterSample:
255 return "Expanded Counter Sample"
256 default:
257 return ""
258 }
259}
260
261func (s *SFlowDatagram) LayerType() gopacket.LayerType { return LayerTypeSFlow }
262
263func (d *SFlowDatagram) Payload() []byte { return nil }
264
265func (d *SFlowDatagram) CanDecode() gopacket.LayerClass { return LayerTypeSFlow }
266
267func (d *SFlowDatagram) NextLayerType() gopacket.LayerType { return gopacket.LayerTypePayload }
268
269// SFlowIPType determines what form the IP address being decoded will
270// take. This is an XDR union type allowing for both IPv4 and IPv6
271type SFlowIPType uint32
272
273const (
274 SFlowIPv4 SFlowIPType = 1
275 SFlowIPv6 SFlowIPType = 2
276)
277
278func (s SFlowIPType) String() string {
279 switch s {
280 case SFlowIPv4:
281 return "IPv4"
282 case SFlowIPv6:
283 return "IPv6"
284 default:
285 return ""
286 }
287}
288
289func (s SFlowIPType) Length() int {
290 switch s {
291 case SFlowIPv4:
292 return 4
293 case SFlowIPv6:
294 return 16
295 default:
296 return 0
297 }
298}
299
300func (s *SFlowDatagram) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
301 var agentAddressType SFlowIPType
302
303 data, s.DatagramVersion = data[4:], binary.BigEndian.Uint32(data[:4])
304 data, agentAddressType = data[4:], SFlowIPType(binary.BigEndian.Uint32(data[:4]))
305 data, s.AgentAddress = data[agentAddressType.Length():], data[:agentAddressType.Length()]
306 data, s.SubAgentID = data[4:], binary.BigEndian.Uint32(data[:4])
307 data, s.SequenceNumber = data[4:], binary.BigEndian.Uint32(data[:4])
308 data, s.AgentUptime = data[4:], binary.BigEndian.Uint32(data[:4])
309 data, s.SampleCount = data[4:], binary.BigEndian.Uint32(data[:4])
310
311 if s.SampleCount < 1 {
312 return fmt.Errorf("SFlow Datagram has invalid sample length: %d", s.SampleCount)
313 }
314 for i := uint32(0); i < s.SampleCount; i++ {
315 sdf := SFlowDataFormat(binary.BigEndian.Uint32(data[:4]))
316 _, sampleType := sdf.decode()
317 switch sampleType {
318 case SFlowTypeFlowSample:
319 if flowSample, err := decodeFlowSample(&data, false); err == nil {
320 s.FlowSamples = append(s.FlowSamples, flowSample)
321 } else {
322 return err
323 }
324 case SFlowTypeCounterSample:
325 if counterSample, err := decodeCounterSample(&data, false); err == nil {
326 s.CounterSamples = append(s.CounterSamples, counterSample)
327 } else {
328 return err
329 }
330 case SFlowTypeExpandedFlowSample:
331 if flowSample, err := decodeFlowSample(&data, true); err == nil {
332 s.FlowSamples = append(s.FlowSamples, flowSample)
333 } else {
334 return err
335 }
336 case SFlowTypeExpandedCounterSample:
337 if counterSample, err := decodeCounterSample(&data, true); err == nil {
338 s.CounterSamples = append(s.CounterSamples, counterSample)
339 } else {
340 return err
341 }
342
343 default:
344 return fmt.Errorf("Unsupported SFlow sample type %d", sampleType)
345 }
346 }
347 return nil
348}
349
350// SFlowFlowSample represents a sampled packet and contains
351// one or more records describing the packet
352type SFlowFlowSample struct {
353 EnterpriseID SFlowEnterpriseID
354 Format SFlowSampleType
355 SampleLength uint32
356 SequenceNumber uint32
357 SourceIDClass SFlowSourceFormat
358 SourceIDIndex SFlowSourceValue
359 SamplingRate uint32
360 SamplePool uint32
361 Dropped uint32
362 InputInterfaceFormat uint32
363 InputInterface uint32
364 OutputInterfaceFormat uint32
365 OutputInterface uint32
366 RecordCount uint32
367 Records []SFlowRecord
368}
369
370// Flow samples have the following structure. Note
371// the bit fields to encode the Enterprise ID and the
372// Flow record format: type 1
373
374// 0 15 31
375// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
376// | 20 bit Interprise (0) |12 bit format |
377// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
378// | sample length |
379// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
380// | int sample sequence number |
381// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
382// |id type | src id index value |
383// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
384// | int sampling rate |
385// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
386// | int sample pool |
387// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
388// | int drops |
389// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
390// | int input ifIndex |
391// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
392// | int output ifIndex |
393// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
394// | int number of records |
395// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
396// / flow records /
397// / /
398// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
399
400// Flow samples have the following structure.
401// Flow record format: type 3
402
403// 0 15 31
404// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
405// | 20 bit Interprise (0) |12 bit format |
406// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
407// | sample length |
408// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
409// | int sample sequence number |
410// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
411// | int src id type |
412// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
413// | int src id index value |
414// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
415// | int sampling rate |
416// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
417// | int sample pool |
418// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
419// | int drops |
420// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
421// | int input interface format |
422// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
423// | int input interface value |
424// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
425// | int output interface format |
426// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
427// | int output interface value |
428// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
429// | int number of records |
430// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
431// / flow records /
432// / /
433// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
434
435type SFlowFlowDataFormat uint32
436
437func (fdf SFlowFlowDataFormat) decode() (SFlowEnterpriseID, SFlowFlowRecordType) {
438 leftField := fdf >> 12
439 rightField := uint32(0xFFF) & uint32(fdf)
440 return SFlowEnterpriseID(leftField), SFlowFlowRecordType(rightField)
441}
442
443func (fs SFlowFlowSample) GetRecords() []SFlowRecord {
444 return fs.Records
445}
446
447func (fs SFlowFlowSample) GetType() SFlowSampleType {
448 return SFlowTypeFlowSample
449}
450
451func skipRecord(data *[]byte) {
452 recordLength := int(binary.BigEndian.Uint32((*data)[4:]))
453 *data = (*data)[(recordLength+((4-recordLength)%4))+8:]
454}
455
456func decodeFlowSample(data *[]byte, expanded bool) (SFlowFlowSample, error) {
457 s := SFlowFlowSample{}
458 var sdf SFlowDataFormat
459 *data, sdf = (*data)[4:], SFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
460 var sdc SFlowDataSource
461
462 s.EnterpriseID, s.Format = sdf.decode()
463 *data, s.SampleLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
464 *data, s.SequenceNumber = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
465 if expanded {
466 *data, s.SourceIDClass = (*data)[4:], SFlowSourceFormat(binary.BigEndian.Uint32((*data)[:4]))
467 *data, s.SourceIDIndex = (*data)[4:], SFlowSourceValue(binary.BigEndian.Uint32((*data)[:4]))
468 } else {
469 *data, sdc = (*data)[4:], SFlowDataSource(binary.BigEndian.Uint32((*data)[:4]))
470 s.SourceIDClass, s.SourceIDIndex = sdc.decode()
471 }
472 *data, s.SamplingRate = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
473 *data, s.SamplePool = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
474 *data, s.Dropped = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
475
476 if expanded {
477 *data, s.InputInterfaceFormat = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
478 *data, s.InputInterface = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
479 *data, s.OutputInterfaceFormat = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
480 *data, s.OutputInterface = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
481 } else {
482 *data, s.InputInterface = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
483 *data, s.OutputInterface = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
484 }
485 *data, s.RecordCount = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
486
487 for i := uint32(0); i < s.RecordCount; i++ {
488 rdf := SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
489 enterpriseID, flowRecordType := rdf.decode()
490
491 // Try to decode when EnterpriseID is 0 signaling
492 // default sflow structs are used according specification
493 // Unexpected behavior detected for e.g. with pmacct
494 if enterpriseID == 0 {
495 switch flowRecordType {
496 case SFlowTypeRawPacketFlow:
497 if record, err := decodeRawPacketFlowRecord(data); err == nil {
498 s.Records = append(s.Records, record)
499 } else {
500 return s, err
501 }
502 case SFlowTypeExtendedUserFlow:
503 if record, err := decodeExtendedUserFlow(data); err == nil {
504 s.Records = append(s.Records, record)
505 } else {
506 return s, err
507 }
508 case SFlowTypeExtendedUrlFlow:
509 if record, err := decodeExtendedURLRecord(data); err == nil {
510 s.Records = append(s.Records, record)
511 } else {
512 return s, err
513 }
514 case SFlowTypeExtendedSwitchFlow:
515 if record, err := decodeExtendedSwitchFlowRecord(data); err == nil {
516 s.Records = append(s.Records, record)
517 } else {
518 return s, err
519 }
520 case SFlowTypeExtendedRouterFlow:
521 if record, err := decodeExtendedRouterFlowRecord(data); err == nil {
522 s.Records = append(s.Records, record)
523 } else {
524 return s, err
525 }
526 case SFlowTypeExtendedGatewayFlow:
527 if record, err := decodeExtendedGatewayFlowRecord(data); err == nil {
528 s.Records = append(s.Records, record)
529 } else {
530 return s, err
531 }
532 case SFlowTypeEthernetFrameFlow:
533 if record, err := decodeEthernetFrameFlowRecord(data); err == nil {
534 s.Records = append(s.Records, record)
535 } else {
536 return s, err
537 }
538 case SFlowTypeIpv4Flow:
539 if record, err := decodeSFlowIpv4Record(data); err == nil {
540 s.Records = append(s.Records, record)
541 } else {
542 return s, err
543 }
544 case SFlowTypeIpv6Flow:
545 if record, err := decodeSFlowIpv6Record(data); err == nil {
546 s.Records = append(s.Records, record)
547 } else {
548 return s, err
549 }
550 case SFlowTypeExtendedMlpsFlow:
551 // TODO
552 skipRecord(data)
553 return s, errors.New("skipping TypeExtendedMlpsFlow")
554 case SFlowTypeExtendedNatFlow:
555 // TODO
556 skipRecord(data)
557 return s, errors.New("skipping TypeExtendedNatFlow")
558 case SFlowTypeExtendedMlpsTunnelFlow:
559 // TODO
560 skipRecord(data)
561 return s, errors.New("skipping TypeExtendedMlpsTunnelFlow")
562 case SFlowTypeExtendedMlpsVcFlow:
563 // TODO
564 skipRecord(data)
565 return s, errors.New("skipping TypeExtendedMlpsVcFlow")
566 case SFlowTypeExtendedMlpsFecFlow:
567 // TODO
568 skipRecord(data)
569 return s, errors.New("skipping TypeExtendedMlpsFecFlow")
570 case SFlowTypeExtendedMlpsLvpFecFlow:
571 // TODO
572 skipRecord(data)
573 return s, errors.New("skipping TypeExtendedMlpsLvpFecFlow")
574 case SFlowTypeExtendedVlanFlow:
575 // TODO
576 skipRecord(data)
577 return s, errors.New("skipping TypeExtendedVlanFlow")
578 case SFlowTypeExtendedIpv4TunnelEgressFlow:
579 if record, err := decodeExtendedIpv4TunnelEgress(data); err == nil {
580 s.Records = append(s.Records, record)
581 } else {
582 return s, err
583 }
584 case SFlowTypeExtendedIpv4TunnelIngressFlow:
585 if record, err := decodeExtendedIpv4TunnelIngress(data); err == nil {
586 s.Records = append(s.Records, record)
587 } else {
588 return s, err
589 }
590 case SFlowTypeExtendedIpv6TunnelEgressFlow:
591 if record, err := decodeExtendedIpv6TunnelEgress(data); err == nil {
592 s.Records = append(s.Records, record)
593 } else {
594 return s, err
595 }
596 case SFlowTypeExtendedIpv6TunnelIngressFlow:
597 if record, err := decodeExtendedIpv6TunnelIngress(data); err == nil {
598 s.Records = append(s.Records, record)
599 } else {
600 return s, err
601 }
602 case SFlowTypeExtendedDecapsulateEgressFlow:
603 if record, err := decodeExtendedDecapsulateEgress(data); err == nil {
604 s.Records = append(s.Records, record)
605 } else {
606 return s, err
607 }
608 case SFlowTypeExtendedDecapsulateIngressFlow:
609 if record, err := decodeExtendedDecapsulateIngress(data); err == nil {
610 s.Records = append(s.Records, record)
611 } else {
612 return s, err
613 }
614 case SFlowTypeExtendedVniEgressFlow:
615 if record, err := decodeExtendedVniEgress(data); err == nil {
616 s.Records = append(s.Records, record)
617 } else {
618 return s, err
619 }
620 case SFlowTypeExtendedVniIngressFlow:
621 if record, err := decodeExtendedVniIngress(data); err == nil {
622 s.Records = append(s.Records, record)
623 } else {
624 return s, err
625 }
626 default:
627 return s, fmt.Errorf("Unsupported flow record type: %d", flowRecordType)
628 }
629 } else {
630 skipRecord(data)
631 }
632 }
633 return s, nil
634}
635
636// Counter samples report information about various counter
637// objects. Typically these are items like IfInOctets, or
638// CPU / Memory stats, etc. SFlow will report these at regular
639// intervals as configured on the agent. If one were sufficiently
640// industrious, this could be used to replace the typical
641// SNMP polling used for such things.
642type SFlowCounterSample struct {
643 EnterpriseID SFlowEnterpriseID
644 Format SFlowSampleType
645 SampleLength uint32
646 SequenceNumber uint32
647 SourceIDClass SFlowSourceFormat
648 SourceIDIndex SFlowSourceValue
649 RecordCount uint32
650 Records []SFlowRecord
651}
652
653// Counter samples have the following structure:
654
655// 0 15 31
656// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
657// | int sample sequence number |
658// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
659// |id type | src id index value |
660// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
661// | int number of records |
662// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
663// / counter records /
664// / /
665// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
666
667type SFlowCounterDataFormat uint32
668
669func (cdf SFlowCounterDataFormat) decode() (SFlowEnterpriseID, SFlowCounterRecordType) {
670 leftField := cdf >> 12
671 rightField := uint32(0xFFF) & uint32(cdf)
672 return SFlowEnterpriseID(leftField), SFlowCounterRecordType(rightField)
673}
674
675// GetRecords will return a slice of interface types
676// representing records. A type switch can be used to
677// get at the underlying SFlowCounterRecordType.
678func (cs SFlowCounterSample) GetRecords() []SFlowRecord {
679 return cs.Records
680}
681
682// GetType will report the type of sample. Only the
683// compact form of counter samples is supported
684func (cs SFlowCounterSample) GetType() SFlowSampleType {
685 return SFlowTypeCounterSample
686}
687
688type SFlowCounterRecordType uint32
689
690const (
691 SFlowTypeGenericInterfaceCounters SFlowCounterRecordType = 1
692 SFlowTypeEthernetInterfaceCounters SFlowCounterRecordType = 2
693 SFlowTypeTokenRingInterfaceCounters SFlowCounterRecordType = 3
694 SFlowType100BaseVGInterfaceCounters SFlowCounterRecordType = 4
695 SFlowTypeVLANCounters SFlowCounterRecordType = 5
696 SFlowTypeLACPCounters SFlowCounterRecordType = 7
697 SFlowTypeProcessorCounters SFlowCounterRecordType = 1001
698 SFlowTypeOpenflowPortCounters SFlowCounterRecordType = 1004
699 SFlowTypePORTNAMECounters SFlowCounterRecordType = 1005
700 SFLowTypeAPPRESOURCESCounters SFlowCounterRecordType = 2203
701 SFlowTypeOVSDPCounters SFlowCounterRecordType = 2207
702)
703
704func (cr SFlowCounterRecordType) String() string {
705 switch cr {
706 case SFlowTypeGenericInterfaceCounters:
707 return "Generic Interface Counters"
708 case SFlowTypeEthernetInterfaceCounters:
709 return "Ethernet Interface Counters"
710 case SFlowTypeTokenRingInterfaceCounters:
711 return "Token Ring Interface Counters"
712 case SFlowType100BaseVGInterfaceCounters:
713 return "100BaseVG Interface Counters"
714 case SFlowTypeVLANCounters:
715 return "VLAN Counters"
716 case SFlowTypeLACPCounters:
717 return "LACP Counters"
718 case SFlowTypeProcessorCounters:
719 return "Processor Counters"
720 case SFlowTypeOpenflowPortCounters:
721 return "Openflow Port Counters"
722 case SFlowTypePORTNAMECounters:
723 return "PORT NAME Counters"
724 case SFLowTypeAPPRESOURCESCounters:
725 return "App Resources Counters"
726 case SFlowTypeOVSDPCounters:
727 return "OVSDP Counters"
728 default:
729 return ""
730
731 }
732}
733
734func decodeCounterSample(data *[]byte, expanded bool) (SFlowCounterSample, error) {
735 s := SFlowCounterSample{}
736 var sdc SFlowDataSource
737 var sdce SFlowDataSourceExpanded
738 var sdf SFlowDataFormat
739
740 *data, sdf = (*data)[4:], SFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
741 s.EnterpriseID, s.Format = sdf.decode()
742 *data, s.SampleLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
743 *data, s.SequenceNumber = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
744 if expanded {
745 *data, sdce = (*data)[8:], SFlowDataSourceExpanded{SFlowSourceFormat(binary.BigEndian.Uint32((*data)[:4])), SFlowSourceValue(binary.BigEndian.Uint32((*data)[4:8]))}
746 s.SourceIDClass, s.SourceIDIndex = sdce.decode()
747 } else {
748 *data, sdc = (*data)[4:], SFlowDataSource(binary.BigEndian.Uint32((*data)[:4]))
749 s.SourceIDClass, s.SourceIDIndex = sdc.decode()
750 }
751 *data, s.RecordCount = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
752
753 for i := uint32(0); i < s.RecordCount; i++ {
754 cdf := SFlowCounterDataFormat(binary.BigEndian.Uint32((*data)[:4]))
755 _, counterRecordType := cdf.decode()
756 switch counterRecordType {
757 case SFlowTypeGenericInterfaceCounters:
758 if record, err := decodeGenericInterfaceCounters(data); err == nil {
759 s.Records = append(s.Records, record)
760 } else {
761 return s, err
762 }
763 case SFlowTypeEthernetInterfaceCounters:
764 if record, err := decodeEthernetCounters(data); err == nil {
765 s.Records = append(s.Records, record)
766 } else {
767 return s, err
768 }
769 case SFlowTypeTokenRingInterfaceCounters:
770 skipRecord(data)
771 return s, errors.New("skipping TypeTokenRingInterfaceCounters")
772 case SFlowType100BaseVGInterfaceCounters:
773 skipRecord(data)
774 return s, errors.New("skipping Type100BaseVGInterfaceCounters")
775 case SFlowTypeVLANCounters:
776 if record, err := decodeVLANCounters(data); err == nil {
777 s.Records = append(s.Records, record)
778 } else {
779 return s, err
780 }
781 case SFlowTypeLACPCounters:
782 if record, err := decodeLACPCounters(data); err == nil {
783 s.Records = append(s.Records, record)
784 } else {
785 return s, err
786 }
787 case SFlowTypeProcessorCounters:
788 if record, err := decodeProcessorCounters(data); err == nil {
789 s.Records = append(s.Records, record)
790 } else {
791 return s, err
792 }
793 case SFlowTypeOpenflowPortCounters:
794 if record, err := decodeOpenflowportCounters(data); err == nil {
795 s.Records = append(s.Records, record)
796 } else {
797 return s, err
798 }
799 case SFlowTypePORTNAMECounters:
800 if record, err := decodePortnameCounters(data); err == nil {
801 s.Records = append(s.Records, record)
802 } else {
803 return s, err
804 }
805 case SFLowTypeAPPRESOURCESCounters:
806 if record, err := decodeAppresourcesCounters(data); err == nil {
807 s.Records = append(s.Records, record)
808 } else {
809 return s, err
810 }
811 case SFlowTypeOVSDPCounters:
812 if record, err := decodeOVSDPCounters(data); err == nil {
813 s.Records = append(s.Records, record)
814 } else {
815 return s, err
816 }
817 default:
818 return s, fmt.Errorf("Invalid counter record type: %d", counterRecordType)
819 }
820 }
821 return s, nil
822}
823
824// SFlowBaseFlowRecord holds the fields common to all records
825// of type SFlowFlowRecordType
826type SFlowBaseFlowRecord struct {
827 EnterpriseID SFlowEnterpriseID
828 Format SFlowFlowRecordType
829 FlowDataLength uint32
830}
831
832func (bfr SFlowBaseFlowRecord) GetType() SFlowFlowRecordType {
833 return bfr.Format
834}
835
836// SFlowFlowRecordType denotes what kind of Flow Record is
837// represented. See RFC 3176
838type SFlowFlowRecordType uint32
839
840const (
841 SFlowTypeRawPacketFlow SFlowFlowRecordType = 1
842 SFlowTypeEthernetFrameFlow SFlowFlowRecordType = 2
843 SFlowTypeIpv4Flow SFlowFlowRecordType = 3
844 SFlowTypeIpv6Flow SFlowFlowRecordType = 4
845 SFlowTypeExtendedSwitchFlow SFlowFlowRecordType = 1001
846 SFlowTypeExtendedRouterFlow SFlowFlowRecordType = 1002
847 SFlowTypeExtendedGatewayFlow SFlowFlowRecordType = 1003
848 SFlowTypeExtendedUserFlow SFlowFlowRecordType = 1004
849 SFlowTypeExtendedUrlFlow SFlowFlowRecordType = 1005
850 SFlowTypeExtendedMlpsFlow SFlowFlowRecordType = 1006
851 SFlowTypeExtendedNatFlow SFlowFlowRecordType = 1007
852 SFlowTypeExtendedMlpsTunnelFlow SFlowFlowRecordType = 1008
853 SFlowTypeExtendedMlpsVcFlow SFlowFlowRecordType = 1009
854 SFlowTypeExtendedMlpsFecFlow SFlowFlowRecordType = 1010
855 SFlowTypeExtendedMlpsLvpFecFlow SFlowFlowRecordType = 1011
856 SFlowTypeExtendedVlanFlow SFlowFlowRecordType = 1012
857 SFlowTypeExtendedIpv4TunnelEgressFlow SFlowFlowRecordType = 1023
858 SFlowTypeExtendedIpv4TunnelIngressFlow SFlowFlowRecordType = 1024
859 SFlowTypeExtendedIpv6TunnelEgressFlow SFlowFlowRecordType = 1025
860 SFlowTypeExtendedIpv6TunnelIngressFlow SFlowFlowRecordType = 1026
861 SFlowTypeExtendedDecapsulateEgressFlow SFlowFlowRecordType = 1027
862 SFlowTypeExtendedDecapsulateIngressFlow SFlowFlowRecordType = 1028
863 SFlowTypeExtendedVniEgressFlow SFlowFlowRecordType = 1029
864 SFlowTypeExtendedVniIngressFlow SFlowFlowRecordType = 1030
865)
866
867func (rt SFlowFlowRecordType) String() string {
868 switch rt {
869 case SFlowTypeRawPacketFlow:
870 return "Raw Packet Flow Record"
871 case SFlowTypeEthernetFrameFlow:
872 return "Ethernet Frame Flow Record"
873 case SFlowTypeIpv4Flow:
874 return "IPv4 Flow Record"
875 case SFlowTypeIpv6Flow:
876 return "IPv6 Flow Record"
877 case SFlowTypeExtendedSwitchFlow:
878 return "Extended Switch Flow Record"
879 case SFlowTypeExtendedRouterFlow:
880 return "Extended Router Flow Record"
881 case SFlowTypeExtendedGatewayFlow:
882 return "Extended Gateway Flow Record"
883 case SFlowTypeExtendedUserFlow:
884 return "Extended User Flow Record"
885 case SFlowTypeExtendedUrlFlow:
886 return "Extended URL Flow Record"
887 case SFlowTypeExtendedMlpsFlow:
888 return "Extended MPLS Flow Record"
889 case SFlowTypeExtendedNatFlow:
890 return "Extended NAT Flow Record"
891 case SFlowTypeExtendedMlpsTunnelFlow:
892 return "Extended MPLS Tunnel Flow Record"
893 case SFlowTypeExtendedMlpsVcFlow:
894 return "Extended MPLS VC Flow Record"
895 case SFlowTypeExtendedMlpsFecFlow:
896 return "Extended MPLS FEC Flow Record"
897 case SFlowTypeExtendedMlpsLvpFecFlow:
898 return "Extended MPLS LVP FEC Flow Record"
899 case SFlowTypeExtendedVlanFlow:
900 return "Extended VLAN Flow Record"
901 case SFlowTypeExtendedIpv4TunnelEgressFlow:
902 return "Extended IPv4 Tunnel Egress Record"
903 case SFlowTypeExtendedIpv4TunnelIngressFlow:
904 return "Extended IPv4 Tunnel Ingress Record"
905 case SFlowTypeExtendedIpv6TunnelEgressFlow:
906 return "Extended IPv6 Tunnel Egress Record"
907 case SFlowTypeExtendedIpv6TunnelIngressFlow:
908 return "Extended IPv6 Tunnel Ingress Record"
909 case SFlowTypeExtendedDecapsulateEgressFlow:
910 return "Extended Decapsulate Egress Record"
911 case SFlowTypeExtendedDecapsulateIngressFlow:
912 return "Extended Decapsulate Ingress Record"
913 case SFlowTypeExtendedVniEgressFlow:
914 return "Extended VNI Ingress Record"
915 case SFlowTypeExtendedVniIngressFlow:
916 return "Extended VNI Ingress Record"
917 default:
918 return ""
919 }
920}
921
922// SFlowRawPacketFlowRecords hold information about a sampled
923// packet grabbed as it transited the agent. This is
924// perhaps the most useful and interesting record type,
925// as it holds the headers of the sampled packet and
926// can be used to build up a complete picture of the
927// traffic patterns on a network.
928//
929// The raw packet header is sent back into gopacket for
930// decoding, and the resulting gopackt.Packet is stored
931// in the Header member
932type SFlowRawPacketFlowRecord struct {
933 SFlowBaseFlowRecord
934 HeaderProtocol SFlowRawHeaderProtocol
935 FrameLength uint32
936 PayloadRemoved uint32
937 HeaderLength uint32
938 Header gopacket.Packet
939}
940
941// Raw packet record types have the following structure:
942
943// 0 15 31
944// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
945// | 20 bit Interprise (0) |12 bit format |
946// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
947// | record length |
948// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
949// | Header Protocol |
950// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
951// | Frame Length |
952// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
953// | Payload Removed |
954// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
955// | Header Length |
956// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
957// \ Header \
958// \ \
959// \ \
960// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
961
962type SFlowRawHeaderProtocol uint32
963
964const (
965 SFlowProtoEthernet SFlowRawHeaderProtocol = 1
966 SFlowProtoISO88024 SFlowRawHeaderProtocol = 2
967 SFlowProtoISO88025 SFlowRawHeaderProtocol = 3
968 SFlowProtoFDDI SFlowRawHeaderProtocol = 4
969 SFlowProtoFrameRelay SFlowRawHeaderProtocol = 5
970 SFlowProtoX25 SFlowRawHeaderProtocol = 6
971 SFlowProtoPPP SFlowRawHeaderProtocol = 7
972 SFlowProtoSMDS SFlowRawHeaderProtocol = 8
973 SFlowProtoAAL5 SFlowRawHeaderProtocol = 9
974 SFlowProtoAAL5_IP SFlowRawHeaderProtocol = 10 /* e.g. Cisco AAL5 mux */
975 SFlowProtoIPv4 SFlowRawHeaderProtocol = 11
976 SFlowProtoIPv6 SFlowRawHeaderProtocol = 12
977 SFlowProtoMPLS SFlowRawHeaderProtocol = 13
978 SFlowProtoPOS SFlowRawHeaderProtocol = 14 /* RFC 1662, 2615 */
979)
980
981func (sfhp SFlowRawHeaderProtocol) String() string {
982 switch sfhp {
983 case SFlowProtoEthernet:
984 return "ETHERNET-ISO88023"
985 case SFlowProtoISO88024:
986 return "ISO88024-TOKENBUS"
987 case SFlowProtoISO88025:
988 return "ISO88025-TOKENRING"
989 case SFlowProtoFDDI:
990 return "FDDI"
991 case SFlowProtoFrameRelay:
992 return "FRAME-RELAY"
993 case SFlowProtoX25:
994 return "X25"
995 case SFlowProtoPPP:
996 return "PPP"
997 case SFlowProtoSMDS:
998 return "SMDS"
999 case SFlowProtoAAL5:
1000 return "AAL5"
1001 case SFlowProtoAAL5_IP:
1002 return "AAL5-IP"
1003 case SFlowProtoIPv4:
1004 return "IPv4"
1005 case SFlowProtoIPv6:
1006 return "IPv6"
1007 case SFlowProtoMPLS:
1008 return "MPLS"
1009 case SFlowProtoPOS:
1010 return "POS"
1011 }
1012 return "UNKNOWN"
1013}
1014
1015func decodeRawPacketFlowRecord(data *[]byte) (SFlowRawPacketFlowRecord, error) {
1016 rec := SFlowRawPacketFlowRecord{}
1017 header := []byte{}
1018 var fdf SFlowFlowDataFormat
1019
1020 *data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
1021 rec.EnterpriseID, rec.Format = fdf.decode()
1022 *data, rec.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
1023 *data, rec.HeaderProtocol = (*data)[4:], SFlowRawHeaderProtocol(binary.BigEndian.Uint32((*data)[:4]))
1024 *data, rec.FrameLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
1025 *data, rec.PayloadRemoved = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
1026 *data, rec.HeaderLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
1027 headerLenWithPadding := int(rec.HeaderLength + ((4 - rec.HeaderLength) % 4))
1028 *data, header = (*data)[headerLenWithPadding:], (*data)[:headerLenWithPadding]
1029 rec.Header = gopacket.NewPacket(header, LayerTypeEthernet, gopacket.Default)
1030 return rec, nil
1031}
1032
1033// SFlowExtendedSwitchFlowRecord give additional information
1034// about the sampled packet if it's available. It's mainly
1035// useful for getting at the incoming and outgoing VLANs
1036// An agent may or may not provide this information.
1037type SFlowExtendedSwitchFlowRecord struct {
1038 SFlowBaseFlowRecord
1039 IncomingVLAN uint32
1040 IncomingVLANPriority uint32
1041 OutgoingVLAN uint32
1042 OutgoingVLANPriority uint32
1043}
1044
1045// Extended switch records have the following structure:
1046
1047// 0 15 31
1048// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1049// | 20 bit Interprise (0) |12 bit format |
1050// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1051// | record length |
1052// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1053// | Incoming VLAN |
1054// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1055// | Incoming VLAN Priority |
1056// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1057// | Outgoing VLAN |
1058// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1059// | Outgoing VLAN Priority |
1060// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1061
1062func decodeExtendedSwitchFlowRecord(data *[]byte) (SFlowExtendedSwitchFlowRecord, error) {
1063 es := SFlowExtendedSwitchFlowRecord{}
1064 var fdf SFlowFlowDataFormat
1065
1066 *data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
1067 es.EnterpriseID, es.Format = fdf.decode()
1068 *data, es.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
1069 *data, es.IncomingVLAN = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
1070 *data, es.IncomingVLANPriority = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
1071 *data, es.OutgoingVLAN = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
1072 *data, es.OutgoingVLANPriority = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
1073 return es, nil
1074}
1075
1076// SFlowExtendedRouterFlowRecord gives additional information
1077// about the layer 3 routing information used to forward
1078// the packet
1079type SFlowExtendedRouterFlowRecord struct {
1080 SFlowBaseFlowRecord
1081 NextHop net.IP
1082 NextHopSourceMask uint32
1083 NextHopDestinationMask uint32
1084}
1085
1086// Extended router records have the following structure:
1087
1088// 0 15 31
1089// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1090// | 20 bit Interprise (0) |12 bit format |
1091// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1092// | record length |
1093// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1094// | IP version of next hop router (1=v4|2=v6) |
1095// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1096// / Next Hop address (v4=4byte|v6=16byte) /
1097// / /
1098// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1099// | Next Hop Source Mask |
1100// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1101// | Next Hop Destination Mask |
1102// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1103
1104func decodeExtendedRouterFlowRecord(data *[]byte) (SFlowExtendedRouterFlowRecord, error) {
1105 er := SFlowExtendedRouterFlowRecord{}
1106 var fdf SFlowFlowDataFormat
1107 var extendedRouterAddressType SFlowIPType
1108
1109 *data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
1110 er.EnterpriseID, er.Format = fdf.decode()
1111 *data, er.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
1112 *data, extendedRouterAddressType = (*data)[4:], SFlowIPType(binary.BigEndian.Uint32((*data)[:4]))
1113 *data, er.NextHop = (*data)[extendedRouterAddressType.Length():], (*data)[:extendedRouterAddressType.Length()]
1114 *data, er.NextHopSourceMask = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
1115 *data, er.NextHopDestinationMask = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
1116 return er, nil
1117}
1118
1119// SFlowExtendedGatewayFlowRecord describes information treasured by
1120// nework engineers everywhere: AS path information listing which
1121// BGP peer sent the packet, and various other BGP related info.
1122// This information is vital because it gives a picture of how much
1123// traffic is being sent from / received by various BGP peers.
1124
1125// Extended gateway records have the following structure:
1126
1127// 0 15 31
1128// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1129// | 20 bit Interprise (0) |12 bit format |
1130// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1131// | record length |
1132// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1133// | IP version of next hop router (1=v4|2=v6) |
1134// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1135// / Next Hop address (v4=4byte|v6=16byte) /
1136// / /
1137// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1138// | AS |
1139// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1140// | Source AS |
1141// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1142// | Peer AS |
1143// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1144// | AS Path Count |
1145// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1146// / AS Path / Sequence /
1147// / /
1148// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1149// / Communities /
1150// / /
1151// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1152// | Local Pref |
1153// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1154
1155// AS Path / Sequence:
1156
1157// 0 15 31
1158// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1159// | AS Source Type (Path=1 / Sequence=2) |
1160// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1161// | Path / Sequence length |
1162// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1163// / Path / Sequence Members /
1164// / /
1165// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1166
1167// Communities:
1168
1169// 0 15 31
1170// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1171// | communitiy length |
1172// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1173// / communitiy Members /
1174// / /
1175// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1176
1177type SFlowExtendedGatewayFlowRecord struct {
1178 SFlowBaseFlowRecord
1179 NextHop net.IP
1180 AS uint32
1181 SourceAS uint32
1182 PeerAS uint32
1183 ASPathCount uint32
1184 ASPath []SFlowASDestination
1185 Communities []uint32
1186 LocalPref uint32
1187}
1188
1189type SFlowASPathType uint32
1190
1191const (
1192 SFlowASSet SFlowASPathType = 1
1193 SFlowASSequence SFlowASPathType = 2
1194)
1195
1196func (apt SFlowASPathType) String() string {
1197 switch apt {
1198 case SFlowASSet:
1199 return "AS Set"
1200 case SFlowASSequence:
1201 return "AS Sequence"
1202 default:
1203 return ""
1204 }
1205}
1206
1207type SFlowASDestination struct {
1208 Type SFlowASPathType
1209 Count uint32
1210 Members []uint32
1211}
1212
1213func (asd SFlowASDestination) String() string {
1214 switch asd.Type {
1215 case SFlowASSet:
1216 return fmt.Sprint("AS Set:", asd.Members)
1217 case SFlowASSequence:
1218 return fmt.Sprint("AS Sequence:", asd.Members)
1219 default:
1220 return ""
1221 }
1222}
1223
1224func (ad *SFlowASDestination) decodePath(data *[]byte) {
1225 *data, ad.Type = (*data)[4:], SFlowASPathType(binary.BigEndian.Uint32((*data)[:4]))
1226 *data, ad.Count = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
1227 ad.Members = make([]uint32, ad.Count)
1228 for i := uint32(0); i < ad.Count; i++ {
1229 var member uint32
1230 *data, member = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
1231 ad.Members[i] = member
1232 }
1233}
1234
1235func decodeExtendedGatewayFlowRecord(data *[]byte) (SFlowExtendedGatewayFlowRecord, error) {
1236 eg := SFlowExtendedGatewayFlowRecord{}
1237 var fdf SFlowFlowDataFormat
1238 var extendedGatewayAddressType SFlowIPType
1239 var communitiesLength uint32
1240 var community uint32
1241
1242 *data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
1243 eg.EnterpriseID, eg.Format = fdf.decode()
1244 *data, eg.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
1245 *data, extendedGatewayAddressType = (*data)[4:], SFlowIPType(binary.BigEndian.Uint32((*data)[:4]))
1246 *data, eg.NextHop = (*data)[extendedGatewayAddressType.Length():], (*data)[:extendedGatewayAddressType.Length()]
1247 *data, eg.AS = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
1248 *data, eg.SourceAS = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
1249 *data, eg.PeerAS = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
1250 *data, eg.ASPathCount = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
1251 for i := uint32(0); i < eg.ASPathCount; i++ {
1252 asPath := SFlowASDestination{}
1253 asPath.decodePath(data)
1254 eg.ASPath = append(eg.ASPath, asPath)
1255 }
1256 *data, communitiesLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
1257 eg.Communities = make([]uint32, communitiesLength)
1258 for j := uint32(0); j < communitiesLength; j++ {
1259 *data, community = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
1260 eg.Communities[j] = community
1261 }
1262 *data, eg.LocalPref = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
1263 return eg, nil
1264}
1265
1266// **************************************************
1267// Extended URL Flow Record
1268// **************************************************
1269
1270// 0 15 31
1271// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1272// | 20 bit Interprise (0) |12 bit format |
1273// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1274// | record length |
1275// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1276// | direction |
1277// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1278// | URL |
1279// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1280// | Host |
1281// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1282
1283type SFlowURLDirection uint32
1284
1285const (
1286 SFlowURLsrc SFlowURLDirection = 1
1287 SFlowURLdst SFlowURLDirection = 2
1288)
1289
1290func (urld SFlowURLDirection) String() string {
1291 switch urld {
1292 case SFlowURLsrc:
1293 return "Source address is the server"
1294 case SFlowURLdst:
1295 return "Destination address is the server"
1296 default:
1297 return ""
1298 }
1299}
1300
1301type SFlowExtendedURLRecord struct {
1302 SFlowBaseFlowRecord
1303 Direction SFlowURLDirection
1304 URL string
1305 Host string
1306}
1307
1308func decodeExtendedURLRecord(data *[]byte) (SFlowExtendedURLRecord, error) {
1309 eur := SFlowExtendedURLRecord{}
1310 var fdf SFlowFlowDataFormat
1311 var urlLen uint32
1312 var urlLenWithPad int
1313 var hostLen uint32
1314 var hostLenWithPad int
1315 var urlBytes []byte
1316 var hostBytes []byte
1317
1318 *data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
1319 eur.EnterpriseID, eur.Format = fdf.decode()
1320 *data, eur.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
1321 *data, eur.Direction = (*data)[4:], SFlowURLDirection(binary.BigEndian.Uint32((*data)[:4]))
1322 *data, urlLen = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
1323 urlLenWithPad = int(urlLen + ((4 - urlLen) % 4))
1324 *data, urlBytes = (*data)[urlLenWithPad:], (*data)[:urlLenWithPad]
1325 eur.URL = string(urlBytes[:urlLen])
1326 *data, hostLen = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
1327 hostLenWithPad = int(hostLen + ((4 - hostLen) % 4))
1328 *data, hostBytes = (*data)[hostLenWithPad:], (*data)[:hostLenWithPad]
1329 eur.Host = string(hostBytes[:hostLen])
1330 return eur, nil
1331}
1332
1333// **************************************************
1334// Extended User Flow Record
1335// **************************************************
1336
1337// 0 15 31
1338// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1339// | 20 bit Interprise (0) |12 bit format |
1340// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1341// | record length |
1342// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1343// | Source Character Set |
1344// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1345// | Source User Id |
1346// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1347// | Destination Character Set |
1348// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1349// | Destination User ID |
1350// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1351
1352type SFlowExtendedUserFlow struct {
1353 SFlowBaseFlowRecord
1354 SourceCharSet SFlowCharSet
1355 SourceUserID string
1356 DestinationCharSet SFlowCharSet
1357 DestinationUserID string
1358}
1359
1360type SFlowCharSet uint32
1361
1362const (
1363 SFlowCSunknown SFlowCharSet = 2
1364 SFlowCSASCII SFlowCharSet = 3
1365 SFlowCSISOLatin1 SFlowCharSet = 4
1366 SFlowCSISOLatin2 SFlowCharSet = 5
1367 SFlowCSISOLatin3 SFlowCharSet = 6
1368 SFlowCSISOLatin4 SFlowCharSet = 7
1369 SFlowCSISOLatinCyrillic SFlowCharSet = 8
1370 SFlowCSISOLatinArabic SFlowCharSet = 9
1371 SFlowCSISOLatinGreek SFlowCharSet = 10
1372 SFlowCSISOLatinHebrew SFlowCharSet = 11
1373 SFlowCSISOLatin5 SFlowCharSet = 12
1374 SFlowCSISOLatin6 SFlowCharSet = 13
1375 SFlowCSISOTextComm SFlowCharSet = 14
1376 SFlowCSHalfWidthKatakana SFlowCharSet = 15
1377 SFlowCSJISEncoding SFlowCharSet = 16
1378 SFlowCSShiftJIS SFlowCharSet = 17
1379 SFlowCSEUCPkdFmtJapanese SFlowCharSet = 18
1380 SFlowCSEUCFixWidJapanese SFlowCharSet = 19
1381 SFlowCSISO4UnitedKingdom SFlowCharSet = 20
1382 SFlowCSISO11SwedishForNames SFlowCharSet = 21
1383 SFlowCSISO15Italian SFlowCharSet = 22
1384 SFlowCSISO17Spanish SFlowCharSet = 23
1385 SFlowCSISO21German SFlowCharSet = 24
1386 SFlowCSISO60DanishNorwegian SFlowCharSet = 25
1387 SFlowCSISO69French SFlowCharSet = 26
1388 SFlowCSISO10646UTF1 SFlowCharSet = 27
1389 SFlowCSISO646basic1983 SFlowCharSet = 28
1390 SFlowCSINVARIANT SFlowCharSet = 29
1391 SFlowCSISO2IntlRefVersion SFlowCharSet = 30
1392 SFlowCSNATSSEFI SFlowCharSet = 31
1393 SFlowCSNATSSEFIADD SFlowCharSet = 32
1394 SFlowCSNATSDANO SFlowCharSet = 33
1395 SFlowCSNATSDANOADD SFlowCharSet = 34
1396 SFlowCSISO10Swedish SFlowCharSet = 35
1397 SFlowCSKSC56011987 SFlowCharSet = 36
1398 SFlowCSISO2022KR SFlowCharSet = 37
1399 SFlowCSEUCKR SFlowCharSet = 38
1400 SFlowCSISO2022JP SFlowCharSet = 39
1401 SFlowCSISO2022JP2 SFlowCharSet = 40
1402 SFlowCSISO13JISC6220jp SFlowCharSet = 41
1403 SFlowCSISO14JISC6220ro SFlowCharSet = 42
1404 SFlowCSISO16Portuguese SFlowCharSet = 43
1405 SFlowCSISO18Greek7Old SFlowCharSet = 44
1406 SFlowCSISO19LatinGreek SFlowCharSet = 45
1407 SFlowCSISO25French SFlowCharSet = 46
1408 SFlowCSISO27LatinGreek1 SFlowCharSet = 47
1409 SFlowCSISO5427Cyrillic SFlowCharSet = 48
1410 SFlowCSISO42JISC62261978 SFlowCharSet = 49
1411 SFlowCSISO47BSViewdata SFlowCharSet = 50
1412 SFlowCSISO49INIS SFlowCharSet = 51
1413 SFlowCSISO50INIS8 SFlowCharSet = 52
1414 SFlowCSISO51INISCyrillic SFlowCharSet = 53
1415 SFlowCSISO54271981 SFlowCharSet = 54
1416 SFlowCSISO5428Greek SFlowCharSet = 55
1417 SFlowCSISO57GB1988 SFlowCharSet = 56
1418 SFlowCSISO58GB231280 SFlowCharSet = 57
1419 SFlowCSISO61Norwegian2 SFlowCharSet = 58
1420 SFlowCSISO70VideotexSupp1 SFlowCharSet = 59
1421 SFlowCSISO84Portuguese2 SFlowCharSet = 60
1422 SFlowCSISO85Spanish2 SFlowCharSet = 61
1423 SFlowCSISO86Hungarian SFlowCharSet = 62
1424 SFlowCSISO87JISX0208 SFlowCharSet = 63
1425 SFlowCSISO88Greek7 SFlowCharSet = 64
1426 SFlowCSISO89ASMO449 SFlowCharSet = 65
1427 SFlowCSISO90 SFlowCharSet = 66
1428 SFlowCSISO91JISC62291984a SFlowCharSet = 67
1429 SFlowCSISO92JISC62991984b SFlowCharSet = 68
1430 SFlowCSISO93JIS62291984badd SFlowCharSet = 69
1431 SFlowCSISO94JIS62291984hand SFlowCharSet = 70
1432 SFlowCSISO95JIS62291984handadd SFlowCharSet = 71
1433 SFlowCSISO96JISC62291984kana SFlowCharSet = 72
1434 SFlowCSISO2033 SFlowCharSet = 73
1435 SFlowCSISO99NAPLPS SFlowCharSet = 74
1436 SFlowCSISO102T617bit SFlowCharSet = 75
1437 SFlowCSISO103T618bit SFlowCharSet = 76
1438 SFlowCSISO111ECMACyrillic SFlowCharSet = 77
1439 SFlowCSa71 SFlowCharSet = 78
1440 SFlowCSa72 SFlowCharSet = 79
1441 SFlowCSISO123CSAZ24341985gr SFlowCharSet = 80
1442 SFlowCSISO88596E SFlowCharSet = 81
1443 SFlowCSISO88596I SFlowCharSet = 82
1444 SFlowCSISO128T101G2 SFlowCharSet = 83
1445 SFlowCSISO88598E SFlowCharSet = 84
1446 SFlowCSISO88598I SFlowCharSet = 85
1447 SFlowCSISO139CSN369103 SFlowCharSet = 86
1448 SFlowCSISO141JUSIB1002 SFlowCharSet = 87
1449 SFlowCSISO143IECP271 SFlowCharSet = 88
1450 SFlowCSISO146Serbian SFlowCharSet = 89
1451 SFlowCSISO147Macedonian SFlowCharSet = 90
1452 SFlowCSISO150 SFlowCharSet = 91
1453 SFlowCSISO151Cuba SFlowCharSet = 92
1454 SFlowCSISO6937Add SFlowCharSet = 93
1455 SFlowCSISO153GOST1976874 SFlowCharSet = 94
1456 SFlowCSISO8859Supp SFlowCharSet = 95
1457 SFlowCSISO10367Box SFlowCharSet = 96
1458 SFlowCSISO158Lap SFlowCharSet = 97
1459 SFlowCSISO159JISX02121990 SFlowCharSet = 98
1460 SFlowCSISO646Danish SFlowCharSet = 99
1461 SFlowCSUSDK SFlowCharSet = 100
1462 SFlowCSDKUS SFlowCharSet = 101
1463 SFlowCSKSC5636 SFlowCharSet = 102
1464 SFlowCSUnicode11UTF7 SFlowCharSet = 103
1465 SFlowCSISO2022CN SFlowCharSet = 104
1466 SFlowCSISO2022CNEXT SFlowCharSet = 105
1467 SFlowCSUTF8 SFlowCharSet = 106
1468 SFlowCSISO885913 SFlowCharSet = 109
1469 SFlowCSISO885914 SFlowCharSet = 110
1470 SFlowCSISO885915 SFlowCharSet = 111
1471 SFlowCSISO885916 SFlowCharSet = 112
1472 SFlowCSGBK SFlowCharSet = 113
1473 SFlowCSGB18030 SFlowCharSet = 114
1474 SFlowCSOSDEBCDICDF0415 SFlowCharSet = 115
1475 SFlowCSOSDEBCDICDF03IRV SFlowCharSet = 116
1476 SFlowCSOSDEBCDICDF041 SFlowCharSet = 117
1477 SFlowCSISO115481 SFlowCharSet = 118
1478 SFlowCSKZ1048 SFlowCharSet = 119
1479 SFlowCSUnicode SFlowCharSet = 1000
1480 SFlowCSUCS4 SFlowCharSet = 1001
1481 SFlowCSUnicodeASCII SFlowCharSet = 1002
1482 SFlowCSUnicodeLatin1 SFlowCharSet = 1003
1483 SFlowCSUnicodeJapanese SFlowCharSet = 1004
1484 SFlowCSUnicodeIBM1261 SFlowCharSet = 1005
1485 SFlowCSUnicodeIBM1268 SFlowCharSet = 1006
1486 SFlowCSUnicodeIBM1276 SFlowCharSet = 1007
1487 SFlowCSUnicodeIBM1264 SFlowCharSet = 1008
1488 SFlowCSUnicodeIBM1265 SFlowCharSet = 1009
1489 SFlowCSUnicode11 SFlowCharSet = 1010
1490 SFlowCSSCSU SFlowCharSet = 1011
1491 SFlowCSUTF7 SFlowCharSet = 1012
1492 SFlowCSUTF16BE SFlowCharSet = 1013
1493 SFlowCSUTF16LE SFlowCharSet = 1014
1494 SFlowCSUTF16 SFlowCharSet = 1015
1495 SFlowCSCESU8 SFlowCharSet = 1016
1496 SFlowCSUTF32 SFlowCharSet = 1017
1497 SFlowCSUTF32BE SFlowCharSet = 1018
1498 SFlowCSUTF32LE SFlowCharSet = 1019
1499 SFlowCSBOCU1 SFlowCharSet = 1020
1500 SFlowCSWindows30Latin1 SFlowCharSet = 2000
1501 SFlowCSWindows31Latin1 SFlowCharSet = 2001
1502 SFlowCSWindows31Latin2 SFlowCharSet = 2002
1503 SFlowCSWindows31Latin5 SFlowCharSet = 2003
1504 SFlowCSHPRoman8 SFlowCharSet = 2004
1505 SFlowCSAdobeStandardEncoding SFlowCharSet = 2005
1506 SFlowCSVenturaUS SFlowCharSet = 2006
1507 SFlowCSVenturaInternational SFlowCharSet = 2007
1508 SFlowCSDECMCS SFlowCharSet = 2008
1509 SFlowCSPC850Multilingual SFlowCharSet = 2009
1510 SFlowCSPCp852 SFlowCharSet = 2010
1511 SFlowCSPC8CodePage437 SFlowCharSet = 2011
1512 SFlowCSPC8DanishNorwegian SFlowCharSet = 2012
1513 SFlowCSPC862LatinHebrew SFlowCharSet = 2013
1514 SFlowCSPC8Turkish SFlowCharSet = 2014
1515 SFlowCSIBMSymbols SFlowCharSet = 2015
1516 SFlowCSIBMThai SFlowCharSet = 2016
1517 SFlowCSHPLegal SFlowCharSet = 2017
1518 SFlowCSHPPiFont SFlowCharSet = 2018
1519 SFlowCSHPMath8 SFlowCharSet = 2019
1520 SFlowCSHPPSMath SFlowCharSet = 2020
1521 SFlowCSHPDesktop SFlowCharSet = 2021
1522 SFlowCSVenturaMath SFlowCharSet = 2022
1523 SFlowCSMicrosoftPublishing SFlowCharSet = 2023
1524 SFlowCSWindows31J SFlowCharSet = 2024
1525 SFlowCSGB2312 SFlowCharSet = 2025
1526 SFlowCSBig5 SFlowCharSet = 2026
1527 SFlowCSMacintosh SFlowCharSet = 2027
1528 SFlowCSIBM037 SFlowCharSet = 2028
1529 SFlowCSIBM038 SFlowCharSet = 2029
1530 SFlowCSIBM273 SFlowCharSet = 2030
1531 SFlowCSIBM274 SFlowCharSet = 2031
1532 SFlowCSIBM275 SFlowCharSet = 2032
1533 SFlowCSIBM277 SFlowCharSet = 2033
1534 SFlowCSIBM278 SFlowCharSet = 2034
1535 SFlowCSIBM280 SFlowCharSet = 2035
1536 SFlowCSIBM281 SFlowCharSet = 2036
1537 SFlowCSIBM284 SFlowCharSet = 2037
1538 SFlowCSIBM285 SFlowCharSet = 2038
1539 SFlowCSIBM290 SFlowCharSet = 2039
1540 SFlowCSIBM297 SFlowCharSet = 2040
1541 SFlowCSIBM420 SFlowCharSet = 2041
1542 SFlowCSIBM423 SFlowCharSet = 2042
1543 SFlowCSIBM424 SFlowCharSet = 2043
1544 SFlowCSIBM500 SFlowCharSet = 2044
1545 SFlowCSIBM851 SFlowCharSet = 2045
1546 SFlowCSIBM855 SFlowCharSet = 2046
1547 SFlowCSIBM857 SFlowCharSet = 2047
1548 SFlowCSIBM860 SFlowCharSet = 2048
1549 SFlowCSIBM861 SFlowCharSet = 2049
1550 SFlowCSIBM863 SFlowCharSet = 2050
1551 SFlowCSIBM864 SFlowCharSet = 2051
1552 SFlowCSIBM865 SFlowCharSet = 2052
1553 SFlowCSIBM868 SFlowCharSet = 2053
1554 SFlowCSIBM869 SFlowCharSet = 2054
1555 SFlowCSIBM870 SFlowCharSet = 2055
1556 SFlowCSIBM871 SFlowCharSet = 2056
1557 SFlowCSIBM880 SFlowCharSet = 2057
1558 SFlowCSIBM891 SFlowCharSet = 2058
1559 SFlowCSIBM903 SFlowCharSet = 2059
1560 SFlowCSIBBM904 SFlowCharSet = 2060
1561 SFlowCSIBM905 SFlowCharSet = 2061
1562 SFlowCSIBM918 SFlowCharSet = 2062
1563 SFlowCSIBM1026 SFlowCharSet = 2063
1564 SFlowCSIBMEBCDICATDE SFlowCharSet = 2064
1565 SFlowCSEBCDICATDEA SFlowCharSet = 2065
1566 SFlowCSEBCDICCAFR SFlowCharSet = 2066
1567 SFlowCSEBCDICDKNO SFlowCharSet = 2067
1568 SFlowCSEBCDICDKNOA SFlowCharSet = 2068
1569 SFlowCSEBCDICFISE SFlowCharSet = 2069
1570 SFlowCSEBCDICFISEA SFlowCharSet = 2070
1571 SFlowCSEBCDICFR SFlowCharSet = 2071
1572 SFlowCSEBCDICIT SFlowCharSet = 2072
1573 SFlowCSEBCDICPT SFlowCharSet = 2073
1574 SFlowCSEBCDICES SFlowCharSet = 2074
1575 SFlowCSEBCDICESA SFlowCharSet = 2075
1576 SFlowCSEBCDICESS SFlowCharSet = 2076
1577 SFlowCSEBCDICUK SFlowCharSet = 2077
1578 SFlowCSEBCDICUS SFlowCharSet = 2078
1579 SFlowCSUnknown8BiT SFlowCharSet = 2079
1580 SFlowCSMnemonic SFlowCharSet = 2080
1581 SFlowCSMnem SFlowCharSet = 2081
1582 SFlowCSVISCII SFlowCharSet = 2082
1583 SFlowCSVIQR SFlowCharSet = 2083
1584 SFlowCSKOI8R SFlowCharSet = 2084
1585 SFlowCSHZGB2312 SFlowCharSet = 2085
1586 SFlowCSIBM866 SFlowCharSet = 2086
1587 SFlowCSPC775Baltic SFlowCharSet = 2087
1588 SFlowCSKOI8U SFlowCharSet = 2088
1589 SFlowCSIBM00858 SFlowCharSet = 2089
1590 SFlowCSIBM00924 SFlowCharSet = 2090
1591 SFlowCSIBM01140 SFlowCharSet = 2091
1592 SFlowCSIBM01141 SFlowCharSet = 2092
1593 SFlowCSIBM01142 SFlowCharSet = 2093
1594 SFlowCSIBM01143 SFlowCharSet = 2094
1595 SFlowCSIBM01144 SFlowCharSet = 2095
1596 SFlowCSIBM01145 SFlowCharSet = 2096
1597 SFlowCSIBM01146 SFlowCharSet = 2097
1598 SFlowCSIBM01147 SFlowCharSet = 2098
1599 SFlowCSIBM01148 SFlowCharSet = 2099
1600 SFlowCSIBM01149 SFlowCharSet = 2100
1601 SFlowCSBig5HKSCS SFlowCharSet = 2101
1602 SFlowCSIBM1047 SFlowCharSet = 2102
1603 SFlowCSPTCP154 SFlowCharSet = 2103
1604 SFlowCSAmiga1251 SFlowCharSet = 2104
1605 SFlowCSKOI7switched SFlowCharSet = 2105
1606 SFlowCSBRF SFlowCharSet = 2106
1607 SFlowCSTSCII SFlowCharSet = 2107
1608 SFlowCSCP51932 SFlowCharSet = 2108
1609 SFlowCSWindows874 SFlowCharSet = 2109
1610 SFlowCSWindows1250 SFlowCharSet = 2250
1611 SFlowCSWindows1251 SFlowCharSet = 2251
1612 SFlowCSWindows1252 SFlowCharSet = 2252
1613 SFlowCSWindows1253 SFlowCharSet = 2253
1614 SFlowCSWindows1254 SFlowCharSet = 2254
1615 SFlowCSWindows1255 SFlowCharSet = 2255
1616 SFlowCSWindows1256 SFlowCharSet = 2256
1617 SFlowCSWindows1257 SFlowCharSet = 2257
1618 SFlowCSWindows1258 SFlowCharSet = 2258
1619 SFlowCSTIS620 SFlowCharSet = 2259
1620 SFlowCS50220 SFlowCharSet = 2260
1621 SFlowCSreserved SFlowCharSet = 3000
1622)
1623
1624func decodeExtendedUserFlow(data *[]byte) (SFlowExtendedUserFlow, error) {
1625 eu := SFlowExtendedUserFlow{}
1626 var fdf SFlowFlowDataFormat
1627 var srcUserLen uint32
1628 var srcUserLenWithPad int
1629 var srcUserBytes []byte
1630 var dstUserLen uint32
1631 var dstUserLenWithPad int
1632 var dstUserBytes []byte
1633
1634 *data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
1635 eu.EnterpriseID, eu.Format = fdf.decode()
1636 *data, eu.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
1637 *data, eu.SourceCharSet = (*data)[4:], SFlowCharSet(binary.BigEndian.Uint32((*data)[:4]))
1638 *data, srcUserLen = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
1639 srcUserLenWithPad = int(srcUserLen + ((4 - srcUserLen) % 4))
1640 *data, srcUserBytes = (*data)[srcUserLenWithPad:], (*data)[:srcUserLenWithPad]
1641 eu.SourceUserID = string(srcUserBytes[:srcUserLen])
1642 *data, eu.DestinationCharSet = (*data)[4:], SFlowCharSet(binary.BigEndian.Uint32((*data)[:4]))
1643 *data, dstUserLen = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
1644 dstUserLenWithPad = int(dstUserLen + ((4 - dstUserLen) % 4))
1645 *data, dstUserBytes = (*data)[dstUserLenWithPad:], (*data)[:dstUserLenWithPad]
1646 eu.DestinationUserID = string(dstUserBytes[:dstUserLen])
1647 return eu, nil
1648}
1649
1650// **************************************************
1651// Packet IP version 4 Record
1652// **************************************************
1653
1654// 0 15 31
1655// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1656// | Length |
1657// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1658// | Protocol |
1659// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1660// | Source IPv4 |
1661// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1662// | Destination IPv4 |
1663// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1664// | Source Port |
1665// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1666// | Destionation Port |
1667// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1668// | TCP Flags |
1669// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1670// | TOS |
1671// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1672type SFlowIpv4Record struct {
1673 // The length of the IP packet excluding ower layer encapsulations
1674 Length uint32
1675 // IP Protocol type (for example, TCP = 6, UDP = 17)
1676 Protocol uint32
1677 // Source IP Address
1678 IPSrc net.IP
1679 // Destination IP Address
1680 IPDst net.IP
1681 // TCP/UDP source port number or equivalent
1682 PortSrc uint32
1683 // TCP/UDP destination port number or equivalent
1684 PortDst uint32
1685 // TCP flags
1686 TCPFlags uint32
1687 // IP type of service
1688 TOS uint32
1689}
1690
1691func decodeSFlowIpv4Record(data *[]byte) (SFlowIpv4Record, error) {
1692 si := SFlowIpv4Record{}
1693
1694 *data, si.Length = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
1695 *data, si.Protocol = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
1696 *data, si.IPSrc = (*data)[4:], net.IP((*data)[:4])
1697 *data, si.IPDst = (*data)[4:], net.IP((*data)[:4])
1698 *data, si.PortSrc = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
1699 *data, si.PortDst = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
1700 *data, si.TCPFlags = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
1701 *data, si.TOS = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
1702
1703 return si, nil
1704}
1705
1706// **************************************************
1707// Packet IP version 6 Record
1708// **************************************************
1709
1710// 0 15 31
1711// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1712// | Length |
1713// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1714// | Protocol |
1715// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1716// | Source IPv4 |
1717// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1718// | Destination IPv4 |
1719// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1720// | Source Port |
1721// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1722// | Destionation Port |
1723// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1724// | TCP Flags |
1725// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1726// | Priority |
1727// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1728type SFlowIpv6Record struct {
1729 // The length of the IP packet excluding ower layer encapsulations
1730 Length uint32
1731 // IP Protocol type (for example, TCP = 6, UDP = 17)
1732 Protocol uint32
1733 // Source IP Address
1734 IPSrc net.IP
1735 // Destination IP Address
1736 IPDst net.IP
1737 // TCP/UDP source port number or equivalent
1738 PortSrc uint32
1739 // TCP/UDP destination port number or equivalent
1740 PortDst uint32
1741 // TCP flags
1742 TCPFlags uint32
1743 // IP priority
1744 Priority uint32
1745}
1746
1747func decodeSFlowIpv6Record(data *[]byte) (SFlowIpv6Record, error) {
1748 si := SFlowIpv6Record{}
1749
1750 *data, si.Length = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
1751 *data, si.Protocol = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
1752 *data, si.IPSrc = (*data)[16:], net.IP((*data)[:16])
1753 *data, si.IPDst = (*data)[16:], net.IP((*data)[:16])
1754 *data, si.PortSrc = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
1755 *data, si.PortDst = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
1756 *data, si.TCPFlags = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
1757 *data, si.Priority = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
1758
1759 return si, nil
1760}
1761
1762// **************************************************
1763// Extended IPv4 Tunnel Egress
1764// **************************************************
1765
1766// 0 15 31
1767// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1768// | 20 bit Interprise (0) |12 bit format |
1769// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1770// | record length |
1771// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1772// / Packet IP version 4 Record /
1773// / /
1774// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1775type SFlowExtendedIpv4TunnelEgressRecord struct {
1776 SFlowBaseFlowRecord
1777 SFlowIpv4Record SFlowIpv4Record
1778}
1779
1780func decodeExtendedIpv4TunnelEgress(data *[]byte) (SFlowExtendedIpv4TunnelEgressRecord, error) {
1781 rec := SFlowExtendedIpv4TunnelEgressRecord{}
1782 var fdf SFlowFlowDataFormat
1783
1784 *data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
1785 rec.EnterpriseID, rec.Format = fdf.decode()
1786 *data, rec.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
1787 rec.SFlowIpv4Record, _ = decodeSFlowIpv4Record(data)
1788
1789 return rec, nil
1790}
1791
1792// **************************************************
1793// Extended IPv4 Tunnel Ingress
1794// **************************************************
1795
1796// 0 15 31
1797// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1798// | 20 bit Interprise (0) |12 bit format |
1799// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1800// | record length |
1801// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1802// / Packet IP version 4 Record /
1803// / /
1804// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1805type SFlowExtendedIpv4TunnelIngressRecord struct {
1806 SFlowBaseFlowRecord
1807 SFlowIpv4Record SFlowIpv4Record
1808}
1809
1810func decodeExtendedIpv4TunnelIngress(data *[]byte) (SFlowExtendedIpv4TunnelIngressRecord, error) {
1811 rec := SFlowExtendedIpv4TunnelIngressRecord{}
1812 var fdf SFlowFlowDataFormat
1813
1814 *data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
1815 rec.EnterpriseID, rec.Format = fdf.decode()
1816 *data, rec.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
1817 rec.SFlowIpv4Record, _ = decodeSFlowIpv4Record(data)
1818
1819 return rec, nil
1820}
1821
1822// **************************************************
1823// Extended IPv6 Tunnel Egress
1824// **************************************************
1825
1826// 0 15 31
1827// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1828// | 20 bit Interprise (0) |12 bit format |
1829// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1830// | record length |
1831// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1832// / Packet IP version 6 Record /
1833// / /
1834// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1835type SFlowExtendedIpv6TunnelEgressRecord struct {
1836 SFlowBaseFlowRecord
1837 SFlowIpv6Record
1838}
1839
1840func decodeExtendedIpv6TunnelEgress(data *[]byte) (SFlowExtendedIpv6TunnelEgressRecord, error) {
1841 rec := SFlowExtendedIpv6TunnelEgressRecord{}
1842 var fdf SFlowFlowDataFormat
1843
1844 *data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
1845 rec.EnterpriseID, rec.Format = fdf.decode()
1846 *data, rec.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
1847 rec.SFlowIpv6Record, _ = decodeSFlowIpv6Record(data)
1848
1849 return rec, nil
1850}
1851
1852// **************************************************
1853// Extended IPv6 Tunnel Ingress
1854// **************************************************
1855
1856// 0 15 31
1857// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1858// | 20 bit Interprise (0) |12 bit format |
1859// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1860// | record length |
1861// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1862// / Packet IP version 6 Record /
1863// / /
1864// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1865type SFlowExtendedIpv6TunnelIngressRecord struct {
1866 SFlowBaseFlowRecord
1867 SFlowIpv6Record
1868}
1869
1870func decodeExtendedIpv6TunnelIngress(data *[]byte) (SFlowExtendedIpv6TunnelIngressRecord, error) {
1871 rec := SFlowExtendedIpv6TunnelIngressRecord{}
1872 var fdf SFlowFlowDataFormat
1873
1874 *data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
1875 rec.EnterpriseID, rec.Format = fdf.decode()
1876 *data, rec.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
1877 rec.SFlowIpv6Record, _ = decodeSFlowIpv6Record(data)
1878
1879 return rec, nil
1880}
1881
1882// **************************************************
1883// Extended Decapsulate Egress
1884// **************************************************
1885
1886// 0 15 31
1887// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1888// | 20 bit Interprise (0) |12 bit format |
1889// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1890// | record length |
1891// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1892// | Inner Header Offset |
1893// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1894type SFlowExtendedDecapsulateEgressRecord struct {
1895 SFlowBaseFlowRecord
1896 InnerHeaderOffset uint32
1897}
1898
1899func decodeExtendedDecapsulateEgress(data *[]byte) (SFlowExtendedDecapsulateEgressRecord, error) {
1900 rec := SFlowExtendedDecapsulateEgressRecord{}
1901 var fdf SFlowFlowDataFormat
1902
1903 *data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
1904 rec.EnterpriseID, rec.Format = fdf.decode()
1905 *data, rec.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
1906 *data, rec.InnerHeaderOffset = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
1907
1908 return rec, nil
1909}
1910
1911// **************************************************
1912// Extended Decapsulate Ingress
1913// **************************************************
1914
1915// 0 15 31
1916// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1917// | 20 bit Interprise (0) |12 bit format |
1918// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1919// | record length |
1920// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1921// | Inner Header Offset |
1922// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1923type SFlowExtendedDecapsulateIngressRecord struct {
1924 SFlowBaseFlowRecord
1925 InnerHeaderOffset uint32
1926}
1927
1928func decodeExtendedDecapsulateIngress(data *[]byte) (SFlowExtendedDecapsulateIngressRecord, error) {
1929 rec := SFlowExtendedDecapsulateIngressRecord{}
1930 var fdf SFlowFlowDataFormat
1931
1932 *data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
1933 rec.EnterpriseID, rec.Format = fdf.decode()
1934 *data, rec.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
1935 *data, rec.InnerHeaderOffset = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
1936
1937 return rec, nil
1938}
1939
1940// **************************************************
1941// Extended VNI Egress
1942// **************************************************
1943
1944// 0 15 31
1945// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1946// | 20 bit Interprise (0) |12 bit format |
1947// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1948// | record length |
1949// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1950// | VNI |
1951// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1952type SFlowExtendedVniEgressRecord struct {
1953 SFlowBaseFlowRecord
1954 VNI uint32
1955}
1956
1957func decodeExtendedVniEgress(data *[]byte) (SFlowExtendedVniEgressRecord, error) {
1958 rec := SFlowExtendedVniEgressRecord{}
1959 var fdf SFlowFlowDataFormat
1960
1961 *data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
1962 rec.EnterpriseID, rec.Format = fdf.decode()
1963 *data, rec.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
1964 *data, rec.VNI = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
1965
1966 return rec, nil
1967}
1968
1969// **************************************************
1970// Extended VNI Ingress
1971// **************************************************
1972
1973// 0 15 31
1974// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1975// | 20 bit Interprise (0) |12 bit format |
1976// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1977// | record length |
1978// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1979// | VNI |
1980// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1981type SFlowExtendedVniIngressRecord struct {
1982 SFlowBaseFlowRecord
1983 VNI uint32
1984}
1985
1986func decodeExtendedVniIngress(data *[]byte) (SFlowExtendedVniIngressRecord, error) {
1987 rec := SFlowExtendedVniIngressRecord{}
1988 var fdf SFlowFlowDataFormat
1989
1990 *data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
1991 rec.EnterpriseID, rec.Format = fdf.decode()
1992 *data, rec.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
1993 *data, rec.VNI = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
1994
1995 return rec, nil
1996}
1997
1998// **************************************************
1999// Counter Record
2000// **************************************************
2001
2002// 0 15 31
2003// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2004// | 20 bit Interprise (0) |12 bit format |
2005// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2006// | counter length |
2007// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2008// / counter data /
2009// / /
2010// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2011
2012type SFlowBaseCounterRecord struct {
2013 EnterpriseID SFlowEnterpriseID
2014 Format SFlowCounterRecordType
2015 FlowDataLength uint32
2016}
2017
2018func (bcr SFlowBaseCounterRecord) GetType() SFlowCounterRecordType {
2019 switch bcr.Format {
2020 case SFlowTypeGenericInterfaceCounters:
2021 return SFlowTypeGenericInterfaceCounters
2022 case SFlowTypeEthernetInterfaceCounters:
2023 return SFlowTypeEthernetInterfaceCounters
2024 case SFlowTypeTokenRingInterfaceCounters:
2025 return SFlowTypeTokenRingInterfaceCounters
2026 case SFlowType100BaseVGInterfaceCounters:
2027 return SFlowType100BaseVGInterfaceCounters
2028 case SFlowTypeVLANCounters:
2029 return SFlowTypeVLANCounters
2030 case SFlowTypeLACPCounters:
2031 return SFlowTypeLACPCounters
2032 case SFlowTypeProcessorCounters:
2033 return SFlowTypeProcessorCounters
2034 case SFlowTypeOpenflowPortCounters:
2035 return SFlowTypeOpenflowPortCounters
2036 case SFlowTypePORTNAMECounters:
2037 return SFlowTypePORTNAMECounters
2038 case SFLowTypeAPPRESOURCESCounters:
2039 return SFLowTypeAPPRESOURCESCounters
2040 case SFlowTypeOVSDPCounters:
2041 return SFlowTypeOVSDPCounters
2042 }
2043 unrecognized := fmt.Sprint("Unrecognized counter record type:", bcr.Format)
2044 panic(unrecognized)
2045}
2046
2047// **************************************************
2048// Counter Record
2049// **************************************************
2050
2051// 0 15 31
2052// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2053// | 20 bit Interprise (0) |12 bit format |
2054// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2055// | counter length |
2056// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2057// | IfIndex |
2058// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2059// | IfType |
2060// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2061// | IfSpeed |
2062// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2063// | IfDirection |
2064// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2065// | IfStatus |
2066// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2067// | IFInOctets |
2068// | |
2069// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2070// | IfInUcastPkts |
2071// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2072// | IfInMulticastPkts |
2073// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2074// | IfInBroadcastPkts |
2075// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2076// | IfInDiscards |
2077// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2078// | InInErrors |
2079// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2080// | IfInUnknownProtos |
2081// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2082// | IfOutOctets |
2083// | |
2084// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2085// | IfOutUcastPkts |
2086// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2087// | IfOutMulticastPkts |
2088// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2089// | IfOutBroadcastPkts |
2090// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2091// | IfOutDiscards |
2092// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2093// | IfOUtErrors |
2094// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2095// | IfPromiscouousMode |
2096// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2097
2098type SFlowGenericInterfaceCounters struct {
2099 SFlowBaseCounterRecord
2100 IfIndex uint32
2101 IfType uint32
2102 IfSpeed uint64
2103 IfDirection uint32
2104 IfStatus uint32
2105 IfInOctets uint64
2106 IfInUcastPkts uint32
2107 IfInMulticastPkts uint32
2108 IfInBroadcastPkts uint32
2109 IfInDiscards uint32
2110 IfInErrors uint32
2111 IfInUnknownProtos uint32
2112 IfOutOctets uint64
2113 IfOutUcastPkts uint32
2114 IfOutMulticastPkts uint32
2115 IfOutBroadcastPkts uint32
2116 IfOutDiscards uint32
2117 IfOutErrors uint32
2118 IfPromiscuousMode uint32
2119}
2120
2121func decodeGenericInterfaceCounters(data *[]byte) (SFlowGenericInterfaceCounters, error) {
2122 gic := SFlowGenericInterfaceCounters{}
2123 var cdf SFlowCounterDataFormat
2124
2125 *data, cdf = (*data)[4:], SFlowCounterDataFormat(binary.BigEndian.Uint32((*data)[:4]))
2126 gic.EnterpriseID, gic.Format = cdf.decode()
2127 *data, gic.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2128 *data, gic.IfIndex = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2129 *data, gic.IfType = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2130 *data, gic.IfSpeed = (*data)[8:], binary.BigEndian.Uint64((*data)[:8])
2131 *data, gic.IfDirection = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2132 *data, gic.IfStatus = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2133 *data, gic.IfInOctets = (*data)[8:], binary.BigEndian.Uint64((*data)[:8])
2134 *data, gic.IfInUcastPkts = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2135 *data, gic.IfInMulticastPkts = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2136 *data, gic.IfInBroadcastPkts = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2137 *data, gic.IfInDiscards = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2138 *data, gic.IfInErrors = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2139 *data, gic.IfInUnknownProtos = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2140 *data, gic.IfOutOctets = (*data)[8:], binary.BigEndian.Uint64((*data)[:8])
2141 *data, gic.IfOutUcastPkts = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2142 *data, gic.IfOutMulticastPkts = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2143 *data, gic.IfOutBroadcastPkts = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2144 *data, gic.IfOutDiscards = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2145 *data, gic.IfOutErrors = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2146 *data, gic.IfPromiscuousMode = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2147 return gic, nil
2148}
2149
2150// **************************************************
2151// Counter Record
2152// **************************************************
2153
2154// 0 15 31
2155// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2156// | 20 bit Interprise (0) |12 bit format |
2157// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2158// | counter length |
2159// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2160// / counter data /
2161// / /
2162// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2163
2164type SFlowEthernetCounters struct {
2165 SFlowBaseCounterRecord
2166 AlignmentErrors uint32
2167 FCSErrors uint32
2168 SingleCollisionFrames uint32
2169 MultipleCollisionFrames uint32
2170 SQETestErrors uint32
2171 DeferredTransmissions uint32
2172 LateCollisions uint32
2173 ExcessiveCollisions uint32
2174 InternalMacTransmitErrors uint32
2175 CarrierSenseErrors uint32
2176 FrameTooLongs uint32
2177 InternalMacReceiveErrors uint32
2178 SymbolErrors uint32
2179}
2180
2181func decodeEthernetCounters(data *[]byte) (SFlowEthernetCounters, error) {
2182 ec := SFlowEthernetCounters{}
2183 var cdf SFlowCounterDataFormat
2184
2185 *data, cdf = (*data)[4:], SFlowCounterDataFormat(binary.BigEndian.Uint32((*data)[:4]))
2186 ec.EnterpriseID, ec.Format = cdf.decode()
2187 *data, ec.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2188 *data, ec.AlignmentErrors = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2189 *data, ec.FCSErrors = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2190 *data, ec.SingleCollisionFrames = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2191 *data, ec.MultipleCollisionFrames = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2192 *data, ec.SQETestErrors = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2193 *data, ec.DeferredTransmissions = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2194 *data, ec.LateCollisions = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2195 *data, ec.ExcessiveCollisions = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2196 *data, ec.InternalMacTransmitErrors = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2197 *data, ec.CarrierSenseErrors = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2198 *data, ec.FrameTooLongs = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2199 *data, ec.InternalMacReceiveErrors = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2200 *data, ec.SymbolErrors = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2201 return ec, nil
2202}
2203
2204// VLAN Counter
2205
2206type SFlowVLANCounters struct {
2207 SFlowBaseCounterRecord
2208 VlanID uint32
2209 Octets uint64
2210 UcastPkts uint32
2211 MulticastPkts uint32
2212 BroadcastPkts uint32
2213 Discards uint32
2214}
2215
2216func decodeVLANCounters(data *[]byte) (SFlowVLANCounters, error) {
2217 vc := SFlowVLANCounters{}
2218 var cdf SFlowCounterDataFormat
2219
2220 *data, cdf = (*data)[4:], SFlowCounterDataFormat(binary.BigEndian.Uint32((*data)[:4]))
2221 vc.EnterpriseID, vc.Format = cdf.decode()
2222 vc.EnterpriseID, vc.Format = cdf.decode()
2223 *data, vc.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2224 *data, vc.VlanID = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2225 *data, vc.Octets = (*data)[8:], binary.BigEndian.Uint64((*data)[:8])
2226 *data, vc.UcastPkts = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2227 *data, vc.MulticastPkts = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2228 *data, vc.BroadcastPkts = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2229 *data, vc.Discards = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2230 return vc, nil
2231}
2232
2233//SFLLACPportState : SFlow LACP Port State (All(4) - 32 bit)
2234type SFLLACPPortState struct {
2235 PortStateAll uint32
2236}
2237
2238//LACPcounters : LACP SFlow Counters ( 64 Bytes )
2239type SFlowLACPCounters struct {
2240 SFlowBaseCounterRecord
2241 ActorSystemID net.HardwareAddr
2242 PartnerSystemID net.HardwareAddr
2243 AttachedAggID uint32
2244 LacpPortState SFLLACPPortState
2245 LACPDUsRx uint32
2246 MarkerPDUsRx uint32
2247 MarkerResponsePDUsRx uint32
2248 UnknownRx uint32
2249 IllegalRx uint32
2250 LACPDUsTx uint32
2251 MarkerPDUsTx uint32
2252 MarkerResponsePDUsTx uint32
2253}
2254
2255func decodeLACPCounters(data *[]byte) (SFlowLACPCounters, error) {
2256 la := SFlowLACPCounters{}
2257 var cdf SFlowCounterDataFormat
2258
2259 *data, cdf = (*data)[4:], SFlowCounterDataFormat(binary.BigEndian.Uint32((*data)[:4]))
2260 la.EnterpriseID, la.Format = cdf.decode()
2261 *data, la.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2262 *data, la.ActorSystemID = (*data)[6:], (*data)[:6]
2263 *data = (*data)[2:] // remove padding
2264 *data, la.PartnerSystemID = (*data)[6:], (*data)[:6]
2265 *data = (*data)[2:] //remove padding
2266 *data, la.AttachedAggID = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2267 *data, la.LacpPortState.PortStateAll = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2268 *data, la.LACPDUsRx = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2269 *data, la.MarkerPDUsRx = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2270 *data, la.MarkerResponsePDUsRx = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2271 *data, la.UnknownRx = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2272 *data, la.IllegalRx = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2273 *data, la.LACPDUsTx = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2274 *data, la.MarkerPDUsTx = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2275 *data, la.MarkerResponsePDUsTx = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2276
2277 return la, nil
2278
2279}
2280
2281// **************************************************
2282// Processor Counter Record
2283// **************************************************
2284// 0 15 31
2285// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2286// | 20 bit Interprise (0) |12 bit format |
2287// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2288// | counter length |
2289// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2290// | FiveSecCpu |
2291// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2292// | OneMinCpu |
2293// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2294// | GiveMinCpu |
2295// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2296// | TotalMemory |
2297// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2298// | FreeMemory |
2299// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2300
2301type SFlowProcessorCounters struct {
2302 SFlowBaseCounterRecord
2303 FiveSecCpu uint32 // 5 second average CPU utilization
2304 OneMinCpu uint32 // 1 minute average CPU utilization
2305 FiveMinCpu uint32 // 5 minute average CPU utilization
2306 TotalMemory uint64 // total memory (in bytes)
2307 FreeMemory uint64 // free memory (in bytes)
2308}
2309
2310func decodeProcessorCounters(data *[]byte) (SFlowProcessorCounters, error) {
2311 pc := SFlowProcessorCounters{}
2312 var cdf SFlowCounterDataFormat
2313 var high32, low32 uint32
2314
2315 *data, cdf = (*data)[4:], SFlowCounterDataFormat(binary.BigEndian.Uint32((*data)[:4]))
2316 pc.EnterpriseID, pc.Format = cdf.decode()
2317 *data, pc.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2318
2319 *data, pc.FiveSecCpu = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2320 *data, pc.OneMinCpu = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2321 *data, pc.FiveMinCpu = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2322 *data, high32 = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2323 *data, low32 = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2324 pc.TotalMemory = (uint64(high32) << 32) + uint64(low32)
2325 *data, high32 = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2326 *data, low32 = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2327 pc.FreeMemory = (uint64(high32)) + uint64(low32)
2328
2329 return pc, nil
2330}
2331
2332// SFlowEthernetFrameFlowRecord give additional information
2333// about the sampled packet if it's available.
2334// An agent may or may not provide this information.
2335type SFlowEthernetFrameFlowRecord struct {
2336 SFlowBaseFlowRecord
2337 FrameLength uint32
2338 SrcMac net.HardwareAddr
2339 DstMac net.HardwareAddr
2340 Type uint32
2341}
2342
2343// Ethernet frame flow records have the following structure:
2344
2345// 0 15 31
2346// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2347// | 20 bit Interprise (0) |12 bit format |
2348// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2349// | record length |
2350// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2351// | Source Mac Address |
2352// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2353// | Destination Mac Address |
2354// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2355// | Ethernet Packet Type |
2356// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2357
2358func decodeEthernetFrameFlowRecord(data *[]byte) (SFlowEthernetFrameFlowRecord, error) {
2359 es := SFlowEthernetFrameFlowRecord{}
2360 var fdf SFlowFlowDataFormat
2361
2362 *data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4]))
2363 es.EnterpriseID, es.Format = fdf.decode()
2364 *data, es.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2365
2366 *data, es.FrameLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2367 *data, es.SrcMac = (*data)[8:], net.HardwareAddr((*data)[:6])
2368 *data, es.DstMac = (*data)[8:], net.HardwareAddr((*data)[:6])
2369 *data, es.Type = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2370 return es, nil
2371}
2372
2373//SFlowOpenflowPortCounters : OVS-Sflow OpenFlow Port Counter ( 20 Bytes )
2374type SFlowOpenflowPortCounters struct {
2375 SFlowBaseCounterRecord
2376 DatapathID uint64
2377 PortNo uint32
2378}
2379
2380func decodeOpenflowportCounters(data *[]byte) (SFlowOpenflowPortCounters, error) {
2381 ofp := SFlowOpenflowPortCounters{}
2382 var cdf SFlowCounterDataFormat
2383
2384 *data, cdf = (*data)[4:], SFlowCounterDataFormat(binary.BigEndian.Uint32((*data)[:4]))
2385 ofp.EnterpriseID, ofp.Format = cdf.decode()
2386 *data, ofp.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2387 *data, ofp.DatapathID = (*data)[8:], binary.BigEndian.Uint64((*data)[:8])
2388 *data, ofp.PortNo = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2389
2390 return ofp, nil
2391}
2392
2393//SFlowAppresourcesCounters : OVS_Sflow App Resources Counter ( 48 Bytes )
2394type SFlowAppresourcesCounters struct {
2395 SFlowBaseCounterRecord
2396 UserTime uint32
2397 SystemTime uint32
2398 MemUsed uint64
2399 MemMax uint64
2400 FdOpen uint32
2401 FdMax uint32
2402 ConnOpen uint32
2403 ConnMax uint32
2404}
2405
2406func decodeAppresourcesCounters(data *[]byte) (SFlowAppresourcesCounters, error) {
2407 app := SFlowAppresourcesCounters{}
2408 var cdf SFlowCounterDataFormat
2409
2410 *data, cdf = (*data)[4:], SFlowCounterDataFormat(binary.BigEndian.Uint32((*data)[:4]))
2411 app.EnterpriseID, app.Format = cdf.decode()
2412 *data, app.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2413 *data, app.UserTime = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2414 *data, app.SystemTime = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2415 *data, app.MemUsed = (*data)[8:], binary.BigEndian.Uint64((*data)[:8])
2416 *data, app.MemMax = (*data)[8:], binary.BigEndian.Uint64((*data)[:8])
2417 *data, app.FdOpen = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2418 *data, app.FdMax = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2419 *data, app.ConnOpen = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2420 *data, app.ConnMax = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2421
2422 return app, nil
2423}
2424
2425//SFlowOVSDPCounters : OVS-Sflow DataPath Counter ( 32 Bytes )
2426type SFlowOVSDPCounters struct {
2427 SFlowBaseCounterRecord
2428 NHit uint32
2429 NMissed uint32
2430 NLost uint32
2431 NMaskHit uint32
2432 NFlows uint32
2433 NMasks uint32
2434}
2435
2436func decodeOVSDPCounters(data *[]byte) (SFlowOVSDPCounters, error) {
2437 dp := SFlowOVSDPCounters{}
2438 var cdf SFlowCounterDataFormat
2439
2440 *data, cdf = (*data)[4:], SFlowCounterDataFormat(binary.BigEndian.Uint32((*data)[:4]))
2441 dp.EnterpriseID, dp.Format = cdf.decode()
2442 *data, dp.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2443 *data, dp.NHit = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2444 *data, dp.NMissed = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2445 *data, dp.NLost = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2446 *data, dp.NMaskHit = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2447 *data, dp.NFlows = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2448 *data, dp.NMasks = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2449
2450 return dp, nil
2451}
2452
2453//SFlowPORTNAME : OVS-Sflow PORTNAME Counter Sampletype ( 20 Bytes )
2454type SFlowPORTNAME struct {
2455 SFlowBaseCounterRecord
2456 Len uint32
2457 Str string
2458}
2459
2460func decodeString(data *[]byte) (len uint32, str string) {
2461 *data, len = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2462 str = string((*data)[:len])
2463 if (len % 4) != 0 {
2464 len += 4 - len%4
2465 }
2466 *data = (*data)[len:]
2467 return
2468}
2469
2470func decodePortnameCounters(data *[]byte) (SFlowPORTNAME, error) {
2471 pn := SFlowPORTNAME{}
2472 var cdf SFlowCounterDataFormat
2473
2474 *data, cdf = (*data)[4:], SFlowCounterDataFormat(binary.BigEndian.Uint32((*data)[:4]))
2475 pn.EnterpriseID, pn.Format = cdf.decode()
2476 *data, pn.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4])
2477 pn.Len, pn.Str = decodeString(data)
2478
2479 return pn, nil
2480}