1 // Copyright 2021 The gVisor Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 15 package ports
16 17 // Flags represents the type of port reservation.
18 //
19 // +stateify savable
20 type Flags struct {
21 // MostRecent represents UDP SO_REUSEADDR.
22 MostRecent bool
23 24 // LoadBalanced indicates SO_REUSEPORT.
25 //
26 // LoadBalanced takes precedence over MostRecent.
27 LoadBalanced bool
28 29 // TupleOnly represents TCP SO_REUSEADDR.
30 TupleOnly bool
31 }
32 33 // Bits converts the Flags to their bitset form.
34 func (f Flags) Bits() BitFlags {
35 var rf BitFlags
36 if f.MostRecent {
37 rf |= MostRecentFlag
38 }
39 if f.LoadBalanced {
40 rf |= LoadBalancedFlag
41 }
42 if f.TupleOnly {
43 rf |= TupleOnlyFlag
44 }
45 return rf
46 }
47 48 // Effective returns the effective behavior of a flag config.
49 func (f Flags) Effective() Flags {
50 e := f
51 if e.LoadBalanced && e.MostRecent {
52 e.MostRecent = false
53 }
54 return e
55 }
56 57 // BitFlags is a bitset representation of Flags.
58 type BitFlags uint32
59 60 const (
61 // MostRecentFlag represents Flags.MostRecent.
62 MostRecentFlag BitFlags = 1 << iota
63 64 // LoadBalancedFlag represents Flags.LoadBalanced.
65 LoadBalancedFlag
66 67 // TupleOnlyFlag represents Flags.TupleOnly.
68 TupleOnlyFlag
69 70 // nextFlag is the value that the next added flag will have.
71 //
72 // It is used to calculate FlagMask below. It is also the number of
73 // valid flag states.
74 nextFlag
75 76 // FlagMask is a bit mask for BitFlags.
77 FlagMask = nextFlag - 1
78 79 // MultiBindFlagMask contains the flags that allow binding the same
80 // tuple multiple times.
81 MultiBindFlagMask = MostRecentFlag | LoadBalancedFlag
82 )
83 84 // ToFlags converts the bitset into a Flags struct.
85 func (f BitFlags) ToFlags() Flags {
86 return Flags{
87 MostRecent: f&MostRecentFlag != 0,
88 LoadBalanced: f&LoadBalancedFlag != 0,
89 TupleOnly: f&TupleOnlyFlag != 0,
90 }
91 }
92 93 // FlagCounter counts how many references each flag combination has.
94 //
95 // +stateify savable
96 type FlagCounter struct {
97 // refs stores the count for each possible flag combination, (0 though
98 // FlagMask).
99 refs [nextFlag]int
100 }
101 102 // AddRef increases the reference count for a specific flag combination.
103 func (c *FlagCounter) AddRef(flags BitFlags) {
104 c.refs[flags]++
105 }
106 107 // DropRef decreases the reference count for a specific flag combination.
108 func (c *FlagCounter) DropRef(flags BitFlags) {
109 c.refs[flags]--
110 }
111 112 // TotalRefs calculates the total number of references for all flag
113 // combinations.
114 func (c FlagCounter) TotalRefs() int {
115 var total int
116 for _, r := range c.refs {
117 total += r
118 }
119 return total
120 }
121 122 // FlagRefs returns the number of references with all specified flags.
123 func (c FlagCounter) FlagRefs(flags BitFlags) int {
124 var total int
125 for i, r := range c.refs {
126 if BitFlags(i)&flags == flags {
127 total += r
128 }
129 }
130 return total
131 }
132 133 // AllRefsHave returns if all references have all specified flags.
134 func (c FlagCounter) AllRefsHave(flags BitFlags) bool {
135 for i, r := range c.refs {
136 if BitFlags(i)&flags != flags && r > 0 {
137 return false
138 }
139 }
140 return true
141 }
142 143 // SharedFlags returns the set of flags shared by all references.
144 func (c FlagCounter) SharedFlags() BitFlags {
145 intersection := FlagMask
146 for i, r := range c.refs {
147 if r > 0 {
148 intersection &= BitFlags(i)
149 }
150 }
151 return intersection
152 }
153