File: input_seq.go

package info (click to toggle)
golang-github-farsightsec-go-nmsg 0.3.0-1
  • links: PTS, VCS
  • area: main
  • in suites: experimental, forky, sid, trixie
  • size: 500 kB
  • sloc: sh: 21; makefile: 3
file content (91 lines) | stat: -rw-r--r-- 1,726 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
/*
 * Copyright (c) 2018 by Farsight Security, Inc.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

package nmsg

import (
	"container/list"
	"time"
)

type seqCacheEntry struct {
	lastUsed time.Time
	seqid    uint64
	nextSeq  uint32
}

type seqCache struct {
	expiry time.Duration
	idmap  map[uint64]*list.Element
	lru    *list.List
}

func newSequenceCache(expiry time.Duration) *seqCache {
	return &seqCache{
		expiry: expiry,
		idmap:  make(map[uint64]*list.Element),
		lru:    list.New(),
	}
}

const maxDrop = 1048576

func (sc *seqCache) Update(n *Nmsg) (missed int) {
	if n.Sequence == nil || n.SequenceId == nil {
		return
	}
	seqid := n.GetSequenceId()
	lruent, ok := sc.idmap[seqid]
	if !ok {
		sc.idmap[seqid] = sc.lru.PushBack(
			&seqCacheEntry{
				lastUsed: time.Now(),
				seqid:    seqid,
				nextSeq:  n.GetSequence() + 1,
			})
		return 0
	}
	seq := n.GetSequence()
	ent := lruent.Value.(*seqCacheEntry)

	ent.lastUsed = time.Now()
	sc.lru.MoveToBack(lruent)

	if seq == ent.nextSeq {
		ent.nextSeq++
		return 0
	}

	if seq > ent.nextSeq {
		if seq-ent.nextSeq < maxDrop {
			missed = int(seq - ent.nextSeq)
		}
		ent.nextSeq = seq + 1
		return missed
	}

	delta := int64(int64(seq) + (1 << 32) - int64(ent.nextSeq))
	if delta < maxDrop {
		missed = int(delta)
	}

	ent.nextSeq = seq + 1
	return missed
}

func (sc *seqCache) Expire() {
	for sc.lru.Len() > 0 {
		lruent := sc.lru.Front()
		ent := lruent.Value.(*seqCacheEntry)
		if time.Since(ent.lastUsed) <= sc.expiry {
			break
		}
		sc.lru.Remove(lruent)
		delete(sc.idmap, ent.seqid)
	}
}