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