@@ -54,17 +54,27 @@ type Flags struct {
54
54
LoadBalanced bool
55
55
}
56
56
57
- func (f Flags ) bits () reuseFlag {
58
- var rf reuseFlag
57
+ // Bits converts the Flags to their bitset form.
58
+ func (f Flags ) Bits () BitFlags {
59
+ var rf BitFlags
59
60
if f .MostRecent {
60
- rf |= mostRecentFlag
61
+ rf |= MostRecentFlag
61
62
}
62
63
if f .LoadBalanced {
63
- rf |= loadBalancedFlag
64
+ rf |= LoadBalancedFlag
64
65
}
65
66
return rf
66
67
}
67
68
69
+ // Effective returns the effective behavior of a flag config.
70
+ func (f Flags ) Effective () Flags {
71
+ e := f
72
+ if e .LoadBalanced && e .MostRecent {
73
+ e .MostRecent = false
74
+ }
75
+ return e
76
+ }
77
+
68
78
// PortManager manages allocating, reserving and releasing ports.
69
79
type PortManager struct {
70
80
mu sync.RWMutex
@@ -78,83 +88,115 @@ type PortManager struct {
78
88
hint uint32
79
89
}
80
90
81
- type reuseFlag int
91
+ // BitFlags is a bitset representation of Flags.
92
+ type BitFlags uint32
82
93
83
94
const (
84
- mostRecentFlag reuseFlag = 1 << iota
85
- loadBalancedFlag
95
+ // MostRecentFlag represents Flags.MostRecent.
96
+ MostRecentFlag BitFlags = 1 << iota
97
+
98
+ // LoadBalancedFlag represents Flags.LoadBalanced.
99
+ LoadBalancedFlag
100
+
101
+ // nextFlag is the value that the next added flag will have.
102
+ //
103
+ // It is used to calculate FlagMask below. It is also the number of
104
+ // valid flag states.
86
105
nextFlag
87
106
88
- flagMask = nextFlag - 1
107
+ // FlagMask is a bit mask for BitFlags.
108
+ FlagMask = nextFlag - 1
89
109
)
90
110
91
- type portNode struct {
92
- // refs stores the count for each possible flag combination.
111
+ // ToFlags converts the bitset into a Flags struct.
112
+ func (f BitFlags ) ToFlags () Flags {
113
+ return Flags {
114
+ MostRecent : f & MostRecentFlag != 0 ,
115
+ LoadBalanced : f & LoadBalancedFlag != 0 ,
116
+ }
117
+ }
118
+
119
+ // FlagCounter counts how many references each flag combination has.
120
+ type FlagCounter struct {
121
+ // refs stores the count for each possible flag combination, (0 though
122
+ // FlagMask).
93
123
refs [nextFlag ]int
94
124
}
95
125
96
- func (p portNode ) totalRefs () int {
126
+ // AddRef increases the reference count for a specific flag combination.
127
+ func (c * FlagCounter ) AddRef (flags BitFlags ) {
128
+ c .refs [flags ]++
129
+ }
130
+
131
+ // DropRef decreases the reference count for a specific flag combination.
132
+ func (c * FlagCounter ) DropRef (flags BitFlags ) {
133
+ c .refs [flags ]--
134
+ }
135
+
136
+ // TotalRefs calculates the total number of references for all flag
137
+ // combinations.
138
+ func (c FlagCounter ) TotalRefs () int {
97
139
var total int
98
- for _ , r := range p .refs {
140
+ for _ , r := range c .refs {
99
141
total += r
100
142
}
101
143
return total
102
144
}
103
145
104
- // flagRefs returns the number of references with all specified flags.
105
- func (p portNode ) flagRefs (flags reuseFlag ) int {
146
+ // FlagRefs returns the number of references with all specified flags.
147
+ func (c FlagCounter ) FlagRefs (flags BitFlags ) int {
106
148
var total int
107
- for i , r := range p .refs {
108
- if reuseFlag (i )& flags == flags {
149
+ for i , r := range c .refs {
150
+ if BitFlags (i )& flags == flags {
109
151
total += r
110
152
}
111
153
}
112
154
return total
113
155
}
114
156
115
- // allRefsHave returns if all references have all specified flags.
116
- func (p portNode ) allRefsHave (flags reuseFlag ) bool {
117
- for i , r := range p .refs {
118
- if reuseFlag (i )& flags = = flags && r > 0 {
157
+ // AllRefsHave returns if all references have all specified flags.
158
+ func (c FlagCounter ) AllRefsHave (flags BitFlags ) bool {
159
+ for i , r := range c .refs {
160
+ if BitFlags (i )& flags ! = flags && r > 0 {
119
161
return false
120
162
}
121
163
}
122
164
return true
123
165
}
124
166
125
- // intersectionRefs returns the set of flags shared by all references.
126
- func (p portNode ) intersectionRefs () reuseFlag {
127
- intersection := flagMask
128
- for i , r := range p .refs {
167
+ // IntersectionRefs returns the set of flags shared by all references.
168
+ func (c FlagCounter ) IntersectionRefs () BitFlags {
169
+ intersection := FlagMask
170
+ for i , r := range c .refs {
129
171
if r > 0 {
130
- intersection &= reuseFlag (i )
172
+ intersection &= BitFlags (i )
131
173
}
132
174
}
133
175
return intersection
134
176
}
135
177
136
178
// deviceNode is never empty. When it has no elements, it is removed from the
137
179
// map that references it.
138
- type deviceNode map [tcpip.NICID ]portNode
180
+ type deviceNode map [tcpip.NICID ]FlagCounter
139
181
140
182
// isAvailable checks whether binding is possible by device. If not binding to a
141
- // device, check against all portNodes . If binding to a specific device, check
183
+ // device, check against all FlagCounters . If binding to a specific device, check
142
184
// against the unspecified device and the provided device.
143
185
//
144
186
// If either of the port reuse flags is enabled on any of the nodes, all nodes
145
187
// sharing a port must share at least one reuse flag. This matches Linux's
146
188
// behavior.
147
189
func (d deviceNode ) isAvailable (flags Flags , bindToDevice tcpip.NICID ) bool {
148
- flagBits := flags .bits ()
190
+ flagBits := flags .Bits ()
149
191
if bindToDevice == 0 {
150
192
// Trying to binding all devices.
151
193
if flagBits == 0 {
152
194
// Can't bind because the (addr,port) is already bound.
153
195
return false
154
196
}
155
- intersection := flagMask
197
+ intersection := FlagMask
156
198
for _ , p := range d {
157
- i := p .intersectionRefs ()
199
+ i := p .IntersectionRefs ()
158
200
intersection &= i
159
201
if intersection & flagBits == 0 {
160
202
// Can't bind because the (addr,port) was
@@ -165,17 +207,17 @@ func (d deviceNode) isAvailable(flags Flags, bindToDevice tcpip.NICID) bool {
165
207
return true
166
208
}
167
209
168
- intersection := flagMask
210
+ intersection := FlagMask
169
211
170
212
if p , ok := d [0 ]; ok {
171
- intersection = p .intersectionRefs ()
213
+ intersection = p .IntersectionRefs ()
172
214
if intersection & flagBits == 0 {
173
215
return false
174
216
}
175
217
}
176
218
177
219
if p , ok := d [bindToDevice ]; ok {
178
- i := p .intersectionRefs ()
220
+ i := p .IntersectionRefs ()
179
221
intersection &= i
180
222
if intersection & flagBits == 0 {
181
223
return false
@@ -324,7 +366,7 @@ func (s *PortManager) reserveSpecificPort(networks []tcpip.NetworkProtocolNumber
324
366
if ! s .isPortAvailableLocked (networks , transport , addr , port , flags , bindToDevice ) {
325
367
return false
326
368
}
327
- flagBits := flags .bits ()
369
+ flagBits := flags .Bits ()
328
370
329
371
// Reserve port on all network protocols.
330
372
for _ , network := range networks {
@@ -340,7 +382,7 @@ func (s *PortManager) reserveSpecificPort(networks []tcpip.NetworkProtocolNumber
340
382
m [addr ] = d
341
383
}
342
384
n := d [bindToDevice ]
343
- n .refs [ flagBits ] ++
385
+ n .AddRef ( flagBits )
344
386
d [bindToDevice ] = n
345
387
}
346
388
@@ -353,7 +395,7 @@ func (s *PortManager) ReleasePort(networks []tcpip.NetworkProtocolNumber, transp
353
395
s .mu .Lock ()
354
396
defer s .mu .Unlock ()
355
397
356
- flagBits := flags .bits ()
398
+ flagBits := flags .Bits ()
357
399
358
400
for _ , network := range networks {
359
401
desc := portDescriptor {network , transport , port }
@@ -368,7 +410,7 @@ func (s *PortManager) ReleasePort(networks []tcpip.NetworkProtocolNumber, transp
368
410
}
369
411
n .refs [flagBits ]--
370
412
d [bindToDevice ] = n
371
- if n .refs == [ nextFlag ] int {} {
413
+ if n .TotalRefs () == 0 {
372
414
delete (d , bindToDevice )
373
415
}
374
416
if len (d ) == 0 {
0 commit comments