gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/tcpip/ports/flags.go (about)

     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  type FlagCounter struct {
    95  	// refs stores the count for each possible flag combination, (0 though
    96  	// FlagMask).
    97  	refs [nextFlag]int
    98  }
    99  
   100  // AddRef increases the reference count for a specific flag combination.
   101  func (c *FlagCounter) AddRef(flags BitFlags) {
   102  	c.refs[flags]++
   103  }
   104  
   105  // DropRef decreases the reference count for a specific flag combination.
   106  func (c *FlagCounter) DropRef(flags BitFlags) {
   107  	c.refs[flags]--
   108  }
   109  
   110  // TotalRefs calculates the total number of references for all flag
   111  // combinations.
   112  func (c FlagCounter) TotalRefs() int {
   113  	var total int
   114  	for _, r := range c.refs {
   115  		total += r
   116  	}
   117  	return total
   118  }
   119  
   120  // FlagRefs returns the number of references with all specified flags.
   121  func (c FlagCounter) FlagRefs(flags BitFlags) int {
   122  	var total int
   123  	for i, r := range c.refs {
   124  		if BitFlags(i)&flags == flags {
   125  			total += r
   126  		}
   127  	}
   128  	return total
   129  }
   130  
   131  // AllRefsHave returns if all references have all specified flags.
   132  func (c FlagCounter) AllRefsHave(flags BitFlags) bool {
   133  	for i, r := range c.refs {
   134  		if BitFlags(i)&flags != flags && r > 0 {
   135  			return false
   136  		}
   137  	}
   138  	return true
   139  }
   140  
   141  // SharedFlags returns the set of flags shared by all references.
   142  func (c FlagCounter) SharedFlags() BitFlags {
   143  	intersection := FlagMask
   144  	for i, r := range c.refs {
   145  		if r > 0 {
   146  			intersection &= BitFlags(i)
   147  		}
   148  	}
   149  	return intersection
   150  }