flags.go raw

   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