github.com/telepresenceio/telepresence/v2@v2.20.0-pro.6.0.20240517030216-236ea954e789/pkg/client/rootd/vip/vip.go (about)

     1  package vip
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     6  	"sync/atomic"
     7  
     8  	"github.com/telepresenceio/telepresence/v2/pkg/subnet"
     9  )
    10  
    11  type Generator interface {
    12  	Next() (net.IP, error)
    13  	Subnet() *net.IPNet
    14  }
    15  
    16  // NewGenerator creates a generator for virtual IPs with in the given subnet.
    17  func NewGenerator(sn *net.IPNet) Generator {
    18  	lo := sn.IP.Mask(sn.Mask)
    19  	hi := subnet.MaxIP(sn)
    20  	if len(lo) == 4 {
    21  		return &ip4Generator{
    22  			subnet:        *sn,
    23  			nextVirtualIP: intFromIPV4(lo),
    24  			maxVirtualIP:  intFromIPV4(hi) + 1,
    25  		}
    26  	} else {
    27  		fixed, lo := intsFromIPV6(lo)
    28  		_, maxLo := intsFromIPV6(hi)
    29  		return &vip6Provider{
    30  			subnet:  *sn,
    31  			fixedHi: fixed,
    32  			nextLo:  lo,
    33  			maxLo:   maxLo,
    34  		}
    35  	}
    36  }
    37  
    38  type ip4Generator struct {
    39  	subnet        net.IPNet
    40  	maxVirtualIP  uint32 // Immutable
    41  	nextVirtualIP uint32
    42  }
    43  
    44  func (v *ip4Generator) Next() (net.IP, error) {
    45  	nxt := atomic.AddUint32(&v.nextVirtualIP, 1)
    46  	if nxt >= v.maxVirtualIP {
    47  		return nil, fmt.Errorf("virtual subnet CIDR %s is exhausted", v.Subnet())
    48  	}
    49  	return ipV4FromInt(nxt), nil
    50  }
    51  
    52  func (v *ip4Generator) Subnet() *net.IPNet {
    53  	return &v.subnet
    54  }
    55  
    56  func ipV4FromInt(v uint32) net.IP {
    57  	return net.IP{
    58  		byte(v & 0xff000000 >> 24),
    59  		byte(v & 0x00ff0000 >> 16),
    60  		byte(v & 0x0000ff00 >> 8),
    61  		byte(v & 0x000000ff),
    62  	}
    63  }
    64  
    65  func intFromIPV4(v net.IP) uint32 {
    66  	return uint32(v[0])<<24 | uint32(v[1])<<16 | uint32(v[2])<<8 | uint32(v[3])
    67  }
    68  
    69  type vip6Provider struct {
    70  	subnet  net.IPNet
    71  	fixedHi uint64
    72  	maxLo   uint64 // Immutable
    73  	nextLo  uint64
    74  }
    75  
    76  func (v *vip6Provider) Next() (net.IP, error) {
    77  	nxt := atomic.AddUint64(&v.nextLo, 1)
    78  	if nxt >= v.maxLo {
    79  		return nil, fmt.Errorf("virtual subnet CIDR %s is exhausted", v.Subnet())
    80  	}
    81  	return ipV6FromInts(v.fixedHi, nxt), nil
    82  }
    83  
    84  func (v *vip6Provider) Subnet() *net.IPNet {
    85  	return &v.subnet
    86  }
    87  
    88  func ipV6FromInts(hi, lo uint64) net.IP {
    89  	return net.IP{
    90  		byte(hi & 0xff00000000000000 >> 56),
    91  		byte(hi & 0x00ff000000000000 >> 48),
    92  		byte(hi & 0x0000ff0000000000 >> 40),
    93  		byte(hi & 0x000000ff00000000 >> 32),
    94  		byte(hi & 0x00000000ff000000 >> 24),
    95  		byte(hi & 0x0000000000ff0000 >> 16),
    96  		byte(hi & 0x000000000000ff00 >> 8),
    97  		byte(hi & 0x00000000000000ff),
    98  		byte(lo & 0xff00000000000000 >> 56),
    99  		byte(lo & 0x00ff000000000000 >> 48),
   100  		byte(lo & 0x0000ff0000000000 >> 40),
   101  		byte(lo & 0x000000ff00000000 >> 32),
   102  		byte(lo & 0x00000000ff000000 >> 24),
   103  		byte(lo & 0x0000000000ff0000 >> 16),
   104  		byte(lo & 0x000000000000ff00 >> 8),
   105  		byte(lo & 0x00000000000000ff),
   106  	}
   107  }
   108  
   109  func intsFromIPV6(v net.IP) (uint64, uint64) {
   110  	return uint64(v[0])<<56 | uint64(v[1])<<48 | uint64(v[2])<<40 | uint64(v[3])<<32 | uint64(v[4])<<24 | uint64(v[5])<<16 | uint64(v[6])<<8 | uint64(v[7]),
   111  		uint64(v[8])<<56 | uint64(v[9])<<48 | uint64(v[10])<<40 | uint64(v[11])<<32 | uint64(v[12])<<24 | uint64(v[13])<<16 | uint64(v[14])<<8 | uint64(v[15])
   112  }