Skip to content
This repository was archived by the owner on Feb 19, 2025. It is now read-only.

Commit edb5e09

Browse files
author
Batyrkhan Koshenov
committed
decoders/netflow: add ReadFrom methods, change FlowSets field to avoid allocs; refactor String() method
Signed-off-by: Batyrkhan Koshenov <[email protected]>
1 parent 745f39f commit edb5e09

File tree

3 files changed

+287
-60
lines changed

3 files changed

+287
-60
lines changed

decoders/netflow/ipfix.go

Lines changed: 103 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
package netflow
22

33
import (
4+
"bytes"
45
"fmt"
56
"time"
7+
8+
"github.com/cloudflare/goflow/v3/decoders/utils"
69
)
710

811
const (
@@ -445,26 +448,98 @@ const (
445448
IPFIX_FIELD_natThresholdEvent = 467
446449
)
447450

451+
// IPFIXPacket is a representation of ipfix(netflow v10) protocol packet.
448452
type IPFIXPacket struct {
449-
Version uint16
450-
Length uint16
451-
ExportTime uint32
452-
SequenceNumber uint32
453+
// Version is version of ipfix records exported in this packet.
454+
Version uint16
455+
456+
// Length is a total length of the IPFIX packet, measured in octets,
457+
// including packet Header and Set(s).
458+
Length uint16
459+
460+
// ExportTime is a time at which the IPFIX Message Header leaves the Exporter,
461+
// expressed in seconds since the UNIX epoch of 1 January 1970 at
462+
// 00:00 UTC, encoded as an unsigned 32-bit integer.
463+
ExportTime uint32
464+
465+
// SequenceNumber is incremental sequence counter of all export packets sent by this export
466+
// device; This value is cumulative, and it can be used to identify whether
467+
// any export packets have been missed.
468+
SequenceNumber uint32
469+
470+
// ObservationDomainId is a 32-bit identifier of the Observation Domain that
471+
// is locally unique to the Exporting Process.
453472
ObservationDomainId uint32
454-
FlowSets []interface{}
473+
474+
FlowSets
455475
}
456476

477+
// ReadFrom reads into receiver's fields Uint values from buffer and returns
478+
// boolean flag telling if it was a success.
479+
//
480+
// Value is treated as big endian.
481+
func (x *IPFIXPacket) ReadFrom(b *bytes.Buffer) bool {
482+
if ok := utils.ReadUint16FromBuffer(b, &x.Length); !ok {
483+
return false
484+
}
485+
if ok := utils.ReadUint32FromBuffer(b, &x.ExportTime); !ok {
486+
return false
487+
}
488+
if ok := utils.ReadUint32FromBuffer(b, &x.SequenceNumber); !ok {
489+
return false
490+
}
491+
if ok := utils.ReadUint32FromBuffer(b, &x.ObservationDomainId); !ok {
492+
return false
493+
}
494+
return true
495+
}
496+
497+
// IPFIXOptionsTemplateFlowSet is a collection of Options Template Records.
457498
type IPFIXOptionsTemplateFlowSet struct {
458499
FlowSetHeader
459500
Records []IPFIXOptionsTemplateRecord
460501
}
461502

503+
// IPFIXOptionsTemplateRecord contains any combination of IANA-assigned and/or
504+
// enterprise-specific Information Element identifiers.
462505
type IPFIXOptionsTemplateRecord struct {
463-
TemplateId uint16
464-
FieldCount uint16
506+
// TemplateId is a unique number in the range 256 to 65535 used for matching
507+
// the type of IPFIX data it will be exporting.
508+
TemplateId uint16
509+
510+
// FieldCount is a number of all fields in this Options Template Record,
511+
// including the Scope Fields.
512+
FieldCount uint16
513+
514+
// ScopeFieldCount is a number of scope fields in this Options Template
515+
// Record. The Scope Fields are normal Fields, except that they are
516+
// interpreted as scope at the Collector.
465517
ScopeFieldCount uint16
466-
Options []Field
467-
Scopes []Field
518+
519+
// Options represents the type and length(in bytes) of the field that
520+
// appears in the options record.
521+
Options []Field
522+
523+
// Scopes is one or more Information Elements, specified in the Options
524+
// Template Record.
525+
Scopes []Field
526+
}
527+
528+
// ReadFrom reads into receiver's fields Uint values from buffer and returns
529+
// boolean flag telling if it was a success.
530+
//
531+
// Value is treated as big endian.
532+
func (x *IPFIXOptionsTemplateRecord) ReadFrom(b *bytes.Buffer) bool {
533+
if ok := utils.ReadUint16FromBuffer(b, &x.TemplateId); !ok {
534+
return false
535+
}
536+
if ok := utils.ReadUint16FromBuffer(b, &x.FieldCount); !ok {
537+
return false
538+
}
539+
if ok := utils.ReadUint16FromBuffer(b, &x.ScopeFieldCount); !ok {
540+
return false
541+
}
542+
return true
468543
}
469544

470545
func IPFIXTypeToString(typeId uint16) string {
@@ -950,7 +1025,6 @@ func (flowSet IPFIXOptionsTemplateFlowSet) String(TypeToString func(uint16) stri
9501025
}
9511026

9521027
}
953-
9541028
return str
9551029
}
9561030

@@ -964,26 +1038,26 @@ func (p IPFIXPacket) String() string {
9641038
str += fmt.Sprintf(" ExportTime: %v\n", exportTime.String())
9651039
str += fmt.Sprintf(" SequenceNumber: %v\n", p.SequenceNumber)
9661040
str += fmt.Sprintf(" ObservationDomainId: %v\n", p.ObservationDomainId)
967-
str += fmt.Sprintf(" FlowSets (%v):\n", len(p.FlowSets))
968-
969-
for i, flowSet := range p.FlowSets {
970-
switch flowSet := flowSet.(type) {
971-
case TemplateFlowSet:
972-
str += fmt.Sprintf(" - TemplateFlowSet %v:\n", i)
973-
str += flowSet.String(IPFIXTypeToString)
974-
case IPFIXOptionsTemplateFlowSet:
975-
str += fmt.Sprintf(" - OptionsTemplateFlowSet %v:\n", i)
976-
str += flowSet.String(IPFIXTypeToString)
977-
case DataFlowSet:
978-
str += fmt.Sprintf(" - DataFlowSet %v:\n", i)
979-
str += flowSet.String(IPFIXTypeToString)
980-
case OptionsDataFlowSet:
981-
str += fmt.Sprintf(" - OptionsDataFlowSet %v:\n", i)
982-
str += flowSet.String(IPFIXTypeToString, IPFIXTypeToString)
983-
default:
984-
str += fmt.Sprintf(" - (unknown type) %v: %v\n", i, flowSet)
985-
}
1041+
str += fmt.Sprintf(" FlowSets (%v):\n", len(p.DataFS)+len(p.IPFIXOptionsTemplateFS)+len(p.OptionsDataFS)+len(p.TemplateFS))
1042+
1043+
for i, fs := range p.TemplateFS {
1044+
str += fmt.Sprintf(" - TemplateFlowSet %v:\n", i)
1045+
str += fs.String(IPFIXTypeToString)
1046+
}
1047+
1048+
for i, fs := range p.IPFIXOptionsTemplateFS {
1049+
str += fmt.Sprintf(" - OptionsTemplateFlowSet %v:\n", i)
1050+
str += fs.String(IPFIXTypeToString)
9861051
}
9871052

1053+
for i, fs := range p.DataFS {
1054+
str += fmt.Sprintf(" - DataFlowSet %v:\n", i)
1055+
str += fs.String(IPFIXTypeToString)
1056+
}
1057+
1058+
for i, fs := range p.OptionsDataFS {
1059+
str += fmt.Sprintf(" - OptionsDataFlowSet %v:\n", i)
1060+
str += fs.String(IPFIXTypeToString, IPFIXTypeToString)
1061+
}
9881062
return str
9891063
}

decoders/netflow/nfv9.go

Lines changed: 108 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
package netflow
22

33
import (
4+
"bytes"
45
"fmt"
56
"time"
7+
8+
"github.com/cloudflare/goflow/v3/decoders/utils"
69
)
710

811
const (
@@ -101,27 +104,101 @@ const (
101104
NFV9_FIELD_layer2packetSectionData = 104
102105
)
103106

107+
// NFv9Packet is a representation of netflow(v9) protocol packet
104108
type NFv9Packet struct {
105-
Version uint16
106-
Count uint16
107-
SystemUptime uint32
108-
UnixSeconds uint32
109+
// Version is version of NetFlow records exported in this packet.
110+
Version uint16
111+
112+
// Count is a number of FlowSet records (both template and data) contained
113+
// within this packet.
114+
Count uint16
115+
116+
// SystemUptime is a time in milliseconds since this device was first booted.
117+
SystemUptime uint32
118+
119+
// UnixSeconds is seconds since 0000 Coordinated Universal Time (UTC) 1970.
120+
UnixSeconds uint32
121+
122+
// SequenceNumber is incremental sequence counter of all export packets sent by this export
123+
// device; This value is cumulative, and it can be used to identify whether
124+
// any export packets have been missed.
109125
SequenceNumber uint32
110-
SourceId uint32
111-
FlowSets []interface{}
126+
127+
// SourceId is a field is a 32-bit value that is used to guarantee
128+
// uniqueness for all flows exported from a particular device.
129+
SourceId uint32
130+
131+
FlowSets
132+
}
133+
134+
// ReadFrom reads into receiver's fields Uint values from buffer and returns
135+
// boolean flag telling if it was a success.
136+
//
137+
// Value is treated as big endian.
138+
func (x *NFv9Packet) ReadFrom(b *bytes.Buffer) bool {
139+
if ok := utils.ReadUint16FromBuffer(b, &x.Count); !ok {
140+
return false
141+
}
142+
if ok := utils.ReadUint32FromBuffer(b, &x.SystemUptime); !ok {
143+
return false
144+
}
145+
if ok := utils.ReadUint32FromBuffer(b, &x.UnixSeconds); !ok {
146+
return false
147+
}
148+
if ok := utils.ReadUint32FromBuffer(b, &x.SequenceNumber); !ok {
149+
return false
150+
}
151+
if ok := utils.ReadUint32FromBuffer(b, &x.SourceId); !ok {
152+
return false
153+
}
154+
return true
112155
}
113156

157+
// NFv9OptionsTemplateFlowSet is a collection of Options Template Records.
114158
type NFv9OptionsTemplateFlowSet struct {
115159
FlowSetHeader
116160
Records []NFv9OptionsTemplateRecord
117161
}
118162

163+
// NFv9OptionsTemplateRecord is a special type of template record used to
164+
// communicate the format of data related to the NetFlow process.
119165
type NFv9OptionsTemplateRecord struct {
120-
TemplateId uint16
121-
ScopeLength uint16
166+
// TemplateId is a unique number in the range 256 to 65535 used for matching
167+
// the type of NetFlow data it will be exporting.
168+
TemplateId uint16
169+
170+
// ScopeLength is the length in bytes of any scope fields contained in
171+
// this options template.
172+
ScopeLength uint16
173+
174+
// OptionLength is the length (in bytes) of any Options field definitions
175+
// contained in this options template.
122176
OptionLength uint16
123-
Scopes []Field
124-
Options []Field
177+
178+
// Scopes is one or more Information Elements, specified in the Options
179+
// Template Record.
180+
Scopes []Field
181+
182+
// Options represents the type and length(in bytes) of the field that
183+
// appears in the options record.
184+
Options []Field
185+
}
186+
187+
// ReadFrom reads into receiver's fields Uint values from buffer and returns
188+
// boolean flag telling if it was a success.
189+
//
190+
// Value is treated as big endian.
191+
func (x *NFv9OptionsTemplateRecord) ReadFrom(b *bytes.Buffer) bool {
192+
if ok := utils.ReadUint16FromBuffer(b, &x.TemplateId); !ok {
193+
return false
194+
}
195+
if ok := utils.ReadUint16FromBuffer(b, &x.ScopeLength); !ok {
196+
return false
197+
}
198+
if ok := utils.ReadUint16FromBuffer(b, &x.OptionLength); !ok {
199+
return false
200+
}
201+
return true
125202
}
126203

127204
func NFv9TypeToString(typeId uint16) string {
@@ -293,25 +370,27 @@ func (p NFv9Packet) String() string {
293370
str += fmt.Sprintf(" UnixSeconds: %v\n", unixSeconds.String())
294371
str += fmt.Sprintf(" SequenceNumber: %v\n", p.SequenceNumber)
295372
str += fmt.Sprintf(" SourceId: %v\n", p.SourceId)
296-
str += fmt.Sprintf(" FlowSets (%v):\n", len(p.FlowSets))
297-
298-
for i, flowSet := range p.FlowSets {
299-
switch flowSet := flowSet.(type) {
300-
case TemplateFlowSet:
301-
str += fmt.Sprintf(" - TemplateFlowSet %v:\n", i)
302-
str += flowSet.String(NFv9TypeToString)
303-
case NFv9OptionsTemplateFlowSet:
304-
str += fmt.Sprintf(" - OptionsTemplateFlowSet %v:\n", i)
305-
str += flowSet.String(NFv9TypeToString)
306-
case DataFlowSet:
307-
str += fmt.Sprintf(" - DataFlowSet %v:\n", i)
308-
str += flowSet.String(NFv9TypeToString)
309-
case OptionsDataFlowSet:
310-
str += fmt.Sprintf(" - OptionsDataFlowSet %v:\n", i)
311-
str += flowSet.String(NFv9TypeToString, NFv9ScopeToString)
312-
default:
313-
str += fmt.Sprintf(" - (unknown type) %v: %v\n", i, flowSet)
314-
}
373+
str += fmt.Sprintf(" FlowSets (%v):\n", len(p.DataFS)+len(p.NFv9OptionsTemplateFS)+len(p.OptionsDataFS)+len(p.TemplateFS))
374+
375+
for i, fs := range p.TemplateFS {
376+
str += fmt.Sprintf(" - TemplateFlowSet %v:\n", i)
377+
str += fs.String(NFv9TypeToString)
378+
}
379+
380+
for i, fs := range p.NFv9OptionsTemplateFS {
381+
str += fmt.Sprintf(" - OptionsTemplateFlowSet %v:\n", i)
382+
str += fs.String(NFv9TypeToString)
383+
}
384+
385+
for i, fs := range p.OptionsDataFS {
386+
str += fmt.Sprintf(" - OptionsDataFlowSet %v:\n", i)
387+
str += fs.String(NFv9TypeToString, NFv9ScopeToString)
388+
}
389+
390+
for i, fs := range p.DataFS {
391+
str += fmt.Sprintf(" - DataFlowSet %v:\n", i)
392+
str += fs.String(NFv9TypeToString)
315393
}
394+
316395
return str
317396
}

0 commit comments

Comments
 (0)