-
Notifications
You must be signed in to change notification settings - Fork 3
/
diversity_filter.go
161 lines (128 loc) · 4.87 KB
/
diversity_filter.go
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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
package zikade
import (
"sync"
"github.com/libp2p/go-libp2p-kbucket/peerdiversity"
"github.com/libp2p/go-libp2p/core/host"
"github.com/libp2p/go-libp2p/core/peer"
ma "github.com/multiformats/go-multiaddr"
"github.com/probe-lab/go-libdht/kad/triert"
"github.com/probe-lab/zikade/kadt"
)
var _ triert.NodeFilter[kadt.Key, kadt.PeerID] = (*TrieRTPeerDiversityFilter)(nil)
// TrieRTPeerDiversityFilter is a wrapper around the `peerdiversity.Filter` used
// as `triert.NodeFilter` to configure the diversity filter for the TrieRT
// Routing Table. TrieRTPeerDiversityFilter should be provided as in the TrieRT
// config, and is not applied directly on the `DHT` instance.
// Please see the docs for `peerdiversity.Filter` for more details
type TrieRTPeerDiversityFilter struct {
*peerdiversity.Filter
}
// NewRTPeerDiversityFilter constructs the `TrieRTPeerDiversityFilter` defining
// the diversity filter for the TrieRT Routing Table.
// `maxPerCpl` represents the maximum number of peers per common prefix length
// allowed to share the same /16 IP group.
// `maxForTable` represents the maximum number of peers in the routing table
// allowed to share the same /16 IP group.
func NewRTPeerDiversityFilter(h host.Host, maxPerCpl, maxForTable int) (*TrieRTPeerDiversityFilter, error) {
multiaddrsFn := func(p peer.ID) []ma.Multiaddr {
cs := h.Network().ConnsToPeer(p)
addr := make([]ma.Multiaddr, 0, len(cs))
for _, c := range cs {
addr = append(addr, c.RemoteMultiaddr())
}
return addr
}
peerIpGroupFilter := newRtPeerIPGroupFilter(maxPerCpl, maxForTable, multiaddrsFn)
filter, err := peerdiversity.NewFilter(peerIpGroupFilter, "triert/diversity",
func(p peer.ID) int {
return kadt.PeerID(h.ID()).Key().CommonPrefixLength(kadt.PeerID(p).Key())
})
if err != nil {
return nil, err
}
return &TrieRTPeerDiversityFilter{
Filter: filter,
}, nil
}
// TryAdd is called by TrieRT when a new node is added to the routing table.
func (f *TrieRTPeerDiversityFilter) TryAdd(rt *triert.TrieRT[kadt.Key, kadt.PeerID], n kadt.PeerID) bool {
return f.Filter.TryAdd(peer.ID(n))
}
// Remove is called by TrieRT when a node is removed from the routing table.
func (f *TrieRTPeerDiversityFilter) Remove(n kadt.PeerID) {
f.Filter.Remove(peer.ID(n))
}
var _ peerdiversity.PeerIPGroupFilter = (*rtPeerIPGroupFilter)(nil)
// rtPeerIPGroupFilter is an implementation of `peerdiversity.PeerIPGroupFilter`.
// Please see the docs for `peerdiversity.PeerIPGroupFilter` for more details.
type rtPeerIPGroupFilter struct {
mu sync.RWMutex
maxPerCpl int
maxForTable int
multiaddrsFn func(peer.ID) []ma.Multiaddr
cplIpGroupCount map[int]map[peerdiversity.PeerIPGroupKey]int
tableIpGroupCount map[peerdiversity.PeerIPGroupKey]int
}
// newRtPeerIPGroupFilter constructs the `PeerIPGroupFilter` that will be used
// to configure the diversity filter for the Routing Table.
func newRtPeerIPGroupFilter(maxPerCpl, maxForTable int,
multiaddrsFn func(peer.ID) []ma.Multiaddr) *rtPeerIPGroupFilter {
return &rtPeerIPGroupFilter{
multiaddrsFn: multiaddrsFn,
maxPerCpl: maxPerCpl,
maxForTable: maxForTable,
cplIpGroupCount: make(map[int]map[peerdiversity.PeerIPGroupKey]int),
tableIpGroupCount: make(map[peerdiversity.PeerIPGroupKey]int),
}
}
// Allow is called by the `peerdiversity.Filter` to check if a peer is allowed
// to be added to the routing table.
func (r *rtPeerIPGroupFilter) Allow(g peerdiversity.PeerGroupInfo) bool {
r.mu.RLock()
defer r.mu.RUnlock()
key := g.IPGroupKey
cpl := g.Cpl
if r.tableIpGroupCount[key] >= r.maxForTable {
return false
}
c, ok := r.cplIpGroupCount[cpl]
allow := !ok || c[key] < r.maxPerCpl
return allow
}
// Increment is called by the `peerdiversity.Filter` when a peer is added to the
// routing table.
func (r *rtPeerIPGroupFilter) Increment(g peerdiversity.PeerGroupInfo) {
r.mu.Lock()
defer r.mu.Unlock()
key := g.IPGroupKey
cpl := g.Cpl
r.tableIpGroupCount[key] = r.tableIpGroupCount[key] + 1
if _, ok := r.cplIpGroupCount[cpl]; !ok {
r.cplIpGroupCount[cpl] = make(map[peerdiversity.PeerIPGroupKey]int)
}
r.cplIpGroupCount[cpl][key] = r.cplIpGroupCount[cpl][key] + 1
}
// Decrement is called by the `peerdiversity.Filter` when a peer is removed from
// the routing table.
func (r *rtPeerIPGroupFilter) Decrement(g peerdiversity.PeerGroupInfo) {
r.mu.Lock()
defer r.mu.Unlock()
key := g.IPGroupKey
cpl := g.Cpl
r.tableIpGroupCount[key] = r.tableIpGroupCount[key] - 1
if r.tableIpGroupCount[key] == 0 {
delete(r.tableIpGroupCount, key)
}
r.cplIpGroupCount[cpl][key] = r.cplIpGroupCount[cpl][key] - 1
if r.cplIpGroupCount[cpl][key] == 0 {
delete(r.cplIpGroupCount[cpl], key)
}
if len(r.cplIpGroupCount[cpl]) == 0 {
delete(r.cplIpGroupCount, cpl)
}
}
// PeerAddresses is called by the `peerdiversity.Filter` to get the list of
// addresses of a peer.
func (r *rtPeerIPGroupFilter) PeerAddresses(p peer.ID) []ma.Multiaddr {
return r.multiaddrsFn(p)
}