blob: a8d7bff25f3711489752c29b42a13575bccff644 [file] [log] [blame]
// Copyright 2021 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package ports
// Flags represents the type of port reservation.
//
// +stateify savable
type Flags struct {
// MostRecent represents UDP SO_REUSEADDR.
MostRecent bool
// LoadBalanced indicates SO_REUSEPORT.
//
// LoadBalanced takes precidence over MostRecent.
LoadBalanced bool
// TupleOnly represents TCP SO_REUSEADDR.
TupleOnly bool
}
// Bits converts the Flags to their bitset form.
func (f Flags) Bits() BitFlags {
var rf BitFlags
if f.MostRecent {
rf |= MostRecentFlag
}
if f.LoadBalanced {
rf |= LoadBalancedFlag
}
if f.TupleOnly {
rf |= TupleOnlyFlag
}
return rf
}
// Effective returns the effective behavior of a flag config.
func (f Flags) Effective() Flags {
e := f
if e.LoadBalanced && e.MostRecent {
e.MostRecent = false
}
return e
}
// BitFlags is a bitset representation of Flags.
type BitFlags uint32
const (
// MostRecentFlag represents Flags.MostRecent.
MostRecentFlag BitFlags = 1 << iota
// LoadBalancedFlag represents Flags.LoadBalanced.
LoadBalancedFlag
// TupleOnlyFlag represents Flags.TupleOnly.
TupleOnlyFlag
// nextFlag is the value that the next added flag will have.
//
// It is used to calculate FlagMask below. It is also the number of
// valid flag states.
nextFlag
// FlagMask is a bit mask for BitFlags.
FlagMask = nextFlag - 1
// MultiBindFlagMask contains the flags that allow binding the same
// tuple multiple times.
MultiBindFlagMask = MostRecentFlag | LoadBalancedFlag
)
// ToFlags converts the bitset into a Flags struct.
func (f BitFlags) ToFlags() Flags {
return Flags{
MostRecent: f&MostRecentFlag != 0,
LoadBalanced: f&LoadBalancedFlag != 0,
TupleOnly: f&TupleOnlyFlag != 0,
}
}
// FlagCounter counts how many references each flag combination has.
type FlagCounter struct {
// refs stores the count for each possible flag combination, (0 though
// FlagMask).
refs [nextFlag]int
}
// AddRef increases the reference count for a specific flag combination.
func (c *FlagCounter) AddRef(flags BitFlags) {
c.refs[flags]++
}
// DropRef decreases the reference count for a specific flag combination.
func (c *FlagCounter) DropRef(flags BitFlags) {
c.refs[flags]--
}
// TotalRefs calculates the total number of references for all flag
// combinations.
func (c FlagCounter) TotalRefs() int {
var total int
for _, r := range c.refs {
total += r
}
return total
}
// FlagRefs returns the number of references with all specified flags.
func (c FlagCounter) FlagRefs(flags BitFlags) int {
var total int
for i, r := range c.refs {
if BitFlags(i)&flags == flags {
total += r
}
}
return total
}
// AllRefsHave returns if all references have all specified flags.
func (c FlagCounter) AllRefsHave(flags BitFlags) bool {
for i, r := range c.refs {
if BitFlags(i)&flags != flags && r > 0 {
return false
}
}
return true
}
// SharedFlags returns the set of flags shared by all references.
func (c FlagCounter) SharedFlags() BitFlags {
intersection := FlagMask
for i, r := range c.refs {
if r > 0 {
intersection &= BitFlags(i)
}
}
return intersection
}