Skip to content

Commit fc38e3e

Browse files
committed
refactor(rule-engine): Revamp rule engine
Refactor the rule engine code by moving it into a separate package and segregating the main building blocks into distinct source files. Along the way, shift the state machine states from expression names to simple integer indices representing sequence ids.
1 parent 33d4a67 commit fc38e3e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+2809
-2311
lines changed

cmd/fibratus/app/rules/validate.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"github.com/rabbitstack/fibratus/internal/bootstrap"
2525
"github.com/rabbitstack/fibratus/pkg/filter"
2626
"github.com/rabbitstack/fibratus/pkg/filter/fields"
27+
"github.com/rabbitstack/fibratus/pkg/rules"
2728
"path/filepath"
2829
"strings"
2930
)
@@ -91,7 +92,7 @@ func validateRules() error {
9192
f := filter.New(rule.Condition, cfg)
9293
err := f.Compile()
9394
if err != nil {
94-
return fmt.Errorf("%v %v", emoji.DisappointedFace, filter.ErrInvalidFilter(rule.Name, err))
95+
return fmt.Errorf("%v %v", emoji.DisappointedFace, rules.ErrInvalidFilter(rule.Name, err))
9596
}
9697

9798
w := warning{rule: rule.Name}

internal/bootstrap/bootstrap.go

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030
"github.com/rabbitstack/fibratus/pkg/handle"
3131
"github.com/rabbitstack/fibratus/pkg/kcap"
3232
"github.com/rabbitstack/fibratus/pkg/ps"
33+
"github.com/rabbitstack/fibratus/pkg/rules"
3334
"github.com/rabbitstack/fibratus/pkg/symbolize"
3435
"github.com/rabbitstack/fibratus/pkg/sys"
3536
"github.com/rabbitstack/fibratus/pkg/util/multierror"
@@ -52,7 +53,7 @@ type App struct {
5253
config *config.Config
5354
evs *EventSourceControl
5455
symbolizer *symbolize.Symbolizer
55-
rules *filter.Rules
56+
engine *rules.Engine
5657
hsnap handle.Snapshotter
5758
psnap ps.Snapshotter
5859
filament filament.Filament
@@ -134,34 +135,34 @@ func NewApp(cfg *config.Config, options ...Option) (*App, error) {
134135
hsnap := handle.NewSnapshotter(cfg, opts.handleSnapshotFn)
135136
psnap := ps.NewSnapshotter(hsnap, cfg)
136137

137-
var (
138-
rules *filter.Rules
139-
res *config.RulesCompileResult
140-
)
138+
var engine *rules.Engine
139+
var rs *config.RulesCompileResult
140+
141141
if cfg.Filters.Rules.Enabled && !cfg.ForwardMode && !cfg.IsCaptureSet() {
142-
rules = filter.NewRules(psnap, cfg)
142+
engine = rules.NewEngine(psnap, cfg)
143143
var err error
144-
res, err = rules.Compile()
144+
rs, err = engine.Compile()
145145
if err != nil {
146146
return nil, err
147147
}
148-
if res != nil {
149-
log.Infof("rules compile summary: %s", res)
148+
if rs != nil {
149+
log.Infof("rules compile summary: %s", rs)
150150
}
151151
} else {
152152
log.Info("rule engine is disabled")
153153
}
154154

155-
evs := NewEventSourceControl(psnap, hsnap, cfg, res)
155+
evs := NewEventSourceControl(psnap, hsnap, cfg, rs)
156156

157157
app := &App{
158158
config: cfg,
159159
evs: evs,
160-
rules: rules,
160+
engine: engine,
161161
hsnap: hsnap,
162162
psnap: psnap,
163163
signals: sigs,
164164
}
165+
165166
return app, nil
166167
}
167168

@@ -234,8 +235,8 @@ func (f *App) Run(args []string) error {
234235
f.evs.RegisterEventListener(f.symbolizer)
235236
}
236237
// register rule engine
237-
if f.rules != nil {
238-
f.evs.RegisterEventListener(f.rules)
238+
if f.engine != nil {
239+
f.evs.RegisterEventListener(f.engine)
239240
}
240241
// register YARA scanner
241242
if cfg.Yara.Enabled {

pkg/filter/_fixtures/sequence_gc.yml

Lines changed: 0 additions & 16 deletions
This file was deleted.

pkg/filter/_fixtures/sequence_rule_bound_fields.yml

Lines changed: 0 additions & 15 deletions
This file was deleted.

pkg/filter/_fixtures/sequence_rule_bound_fields_with_functions.yml

Lines changed: 0 additions & 26 deletions
This file was deleted.

pkg/filter/_fixtures/sequence_rule_expire.yml

Lines changed: 0 additions & 12 deletions
This file was deleted.

pkg/filter/_fixtures/sequence_rule_out_of_order.yml

Lines changed: 0 additions & 17 deletions
This file was deleted.

pkg/filter/_fixtures/sequence_rule_simple_max_span.yml

Lines changed: 0 additions & 13 deletions
This file was deleted.

pkg/filter/filter.go

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ type Filter interface {
5353
// RunSequence runs a filter with sequence expressions. Sequence rules depend
5454
// on the state machine transitions and partial matches to decide whether the
5555
// rule is fired.
56-
RunSequence(evt *kevent.Kevent, seqID uint16, partials map[uint16][]*kevent.Kevent, rawMatch bool) bool
56+
RunSequence(evt *kevent.Kevent, seqID int, partials map[int][]*kevent.Kevent, rawMatch bool) bool
5757
// GetStringFields returns field names mapped to their string values.
5858
GetStringFields() map[fields.Field][]string
5959
// GetFields returns all fields used in the filter expression.
@@ -87,7 +87,7 @@ type filter struct {
8787
segments []fields.Segment
8888
boundFields []*ql.BoundFieldLiteral
8989
// seqBoundFields contains per-sequence bound fields resolved from bound field literals
90-
seqBoundFields map[uint16][]BoundField
90+
seqBoundFields map[int][]BoundField
9191
// stringFields contains filter field names mapped to their string values
9292
stringFields map[fields.Field][]string
9393
hasFunctions bool
@@ -182,22 +182,22 @@ func (f *filter) Compile() error {
182182
return f.checkBoundRefs()
183183
}
184184

185-
func (f *filter) Run(kevt *kevent.Kevent) bool {
185+
func (f *filter) Run(e *kevent.Kevent) bool {
186186
if f.expr == nil {
187187
return false
188188
}
189-
return ql.Eval(f.expr, f.mapValuer(kevt), f.hasFunctions)
189+
return ql.Eval(f.expr, f.mapValuer(e), f.hasFunctions)
190190
}
191191

192-
func (f *filter) RunSequence(kevt *kevent.Kevent, seqID uint16, partials map[uint16][]*kevent.Kevent, rawMatch bool) bool {
192+
func (f *filter) RunSequence(e *kevent.Kevent, seqID int, partials map[int][]*kevent.Kevent, rawMatch bool) bool {
193193
if f.seq == nil {
194194
return false
195195
}
196-
nseqs := uint16(len(f.seq.Expressions))
196+
nseqs := len(f.seq.Expressions)
197197
if seqID > nseqs-1 {
198198
return false
199199
}
200-
valuer := f.mapValuer(kevt)
200+
valuer := f.mapValuer(e)
201201
expr := f.seq.Expressions[seqID]
202202

203203
if rawMatch {
@@ -213,12 +213,12 @@ func (f *filter) RunSequence(kevt *kevent.Kevent, seqID uint16, partials map[uin
213213
// aliases
214214
p := make(map[string][]*kevent.Kevent)
215215
nslots := len(partials[seqID])
216-
for i := uint16(0); i < seqID; i++ {
216+
for i := 0; i < seqID; i++ {
217217
alias := f.seq.Expressions[i].Alias
218218
if alias == "" {
219219
continue
220220
}
221-
p[alias] = partials[i+1]
221+
p[alias] = partials[i]
222222
if len(p[alias]) > nslots {
223223
nslots = len(p[alias])
224224
}
@@ -292,8 +292,8 @@ func (f *filter) RunSequence(kevt *kevent.Kevent, seqID uint16, partials map[uin
292292
match = ql.Eval(expr.Expr, valuer, f.hasFunctions)
293293
if match {
294294
// compute sequence key hash to tie the events
295-
evt.AddMeta(kevent.RuleSequenceByKey, hashers.FnvUint64(hash))
296-
kevt.AddMeta(kevent.RuleSequenceByKey, hashers.FnvUint64(hash))
295+
evt.AddMeta(kevent.RuleSequenceLink, hashers.FnvUint64(hash))
296+
e.AddMeta(kevent.RuleSequenceLink, hashers.FnvUint64(hash))
297297
break
298298
}
299299
}
@@ -308,9 +308,9 @@ func (f *filter) RunSequence(kevt *kevent.Kevent, seqID uint16, partials map[uin
308308
joins := make([]bool, seqID)
309309
joinID := valuer[by.Value]
310310
outer:
311-
for i := uint16(0); i < seqID; i++ {
312-
for _, p := range partials[i+1] {
313-
if compareSeqJoin(joinID, p.SequenceBy()) {
311+
for i := 0; i < seqID; i++ {
312+
for _, p := range partials[i] {
313+
if CompareSeqLink(joinID, p.SequenceLink()) {
314314
joins[i] = true
315315
continue outer
316316
}
@@ -323,7 +323,7 @@ func (f *filter) RunSequence(kevt *kevent.Kevent, seqID uint16, partials map[uin
323323

324324
if match && by != nil {
325325
if v := valuer[by.Value]; v != nil {
326-
kevt.AddMeta(kevent.RuleSequenceByKey, v)
326+
e.AddMeta(kevent.RuleSequenceLink, v)
327327
}
328328
}
329329
}
@@ -456,7 +456,7 @@ func (f *filter) addSegment(segment *ql.BoundSegmentLiteral) {
456456
// addSeqBoundFields receives the sequence id and the list of bound field literals
457457
// and populates the list of bound fields containing the field structure convenient
458458
// for accessors.
459-
func (f *filter) addSeqBoundFields(seqID uint16, fields []*ql.BoundFieldLiteral) []BoundField {
459+
func (f *filter) addSeqBoundFields(seqID int, fields []*ql.BoundFieldLiteral) []BoundField {
460460
flds := make([]BoundField, 0, len(fields))
461461
for _, field := range fields {
462462
flds = append(flds,
@@ -497,9 +497,9 @@ func (f *filter) checkBoundRefs() error {
497497
return nil
498498
}
499499

500-
// compareSeqJoin returns true if both values
500+
// CompareSeqLink returns true if both values
501501
// representing the sequence joins are equal.
502-
func compareSeqJoin(s1, s2 any) bool {
502+
func CompareSeqLink(s1, s2 any) bool {
503503
if s1 == nil || s2 == nil {
504504
return false
505505
}

pkg/filter/filter_windows.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ func New(expr string, config *config.Config, options ...Option) Filter {
9999
segments: make([]fields.Segment, 0),
100100
stringFields: make(map[fields.Field][]string),
101101
boundFields: make([]*ql.BoundFieldLiteral, 0),
102-
seqBoundFields: make(map[uint16][]BoundField),
102+
seqBoundFields: make(map[int][]BoundField),
103103
}
104104
}
105105

@@ -129,7 +129,7 @@ func NewFromCLIWithAllAccessors(args []string) (Filter, error) {
129129
segments: make([]fields.Segment, 0),
130130
stringFields: make(map[fields.Field][]string),
131131
boundFields: make([]*ql.BoundFieldLiteral, 0),
132-
seqBoundFields: make(map[uint16][]BoundField),
132+
seqBoundFields: make(map[int][]BoundField),
133133
}
134134
if err := filter.Compile(); err != nil {
135135
return nil, fmt.Errorf("bad filter:\n %v", err)

0 commit comments

Comments
 (0)