pool.go raw

   1  // Copyright 2022-2025 The sacloud/iaas-api-go 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 fake
  16  
  17  import (
  18  	"math"
  19  	"net"
  20  	"sync"
  21  
  22  	"github.com/sacloud/iaas-api-go"
  23  	"github.com/sacloud/iaas-api-go/types"
  24  	"github.com/sacloud/packages-go/cidr"
  25  )
  26  
  27  const (
  28  	valuePoolMagicID     = types.ID(math.MaxInt64)
  29  	valuePoolResourceKey = "meta"
  30  )
  31  
  32  func pool() *valuePool {
  33  	InitDataStore()
  34  	return vp
  35  }
  36  
  37  var vp *valuePool
  38  
  39  type valuePool struct {
  40  	CurrentID            int64
  41  	CurrentSharedIP      net.IP
  42  	SharedNetMaskLen     int
  43  	SharedDefaultGateway net.IP
  44  	CurrentMACAddress    net.HardwareAddr
  45  	CurrentSubnets       map[int]string
  46  	dataStore            Store
  47  	mu                   sync.Mutex
  48  }
  49  
  50  var poolMu sync.Mutex
  51  
  52  func initValuePool(s Store) *valuePool {
  53  	poolMu.Lock()
  54  	defer poolMu.Unlock()
  55  
  56  	v := s.Get(valuePoolResourceKey, iaas.APIDefaultZone, valuePoolMagicID)
  57  	if v != nil {
  58  		vp = v.(*valuePool)
  59  		vp.dataStore = s
  60  		return vp
  61  	}
  62  
  63  	vp = &valuePool{
  64  		CurrentID:            int64(100000000000),
  65  		CurrentSharedIP:      net.IP{192, 0, 2, 2},
  66  		SharedNetMaskLen:     24,
  67  		SharedDefaultGateway: net.IP{192, 0, 2, 1},
  68  		CurrentMACAddress:    net.HardwareAddr{0x00, 0x00, 0x5E, 0x00, 0x53, 0x00},
  69  		CurrentSubnets: map[int]string{
  70  			24: "24.0.0.0/24",
  71  			25: "25.0.0.0/25",
  72  			26: "26.0.0.0/26",
  73  			27: "27.0.0.0/27",
  74  			28: "28.0.0.0/28",
  75  		},
  76  		dataStore: s,
  77  	}
  78  	return vp
  79  }
  80  
  81  func (p *valuePool) store() {
  82  	p.dataStore.Put(valuePoolResourceKey, iaas.APIDefaultZone, valuePoolMagicID, p)
  83  }
  84  
  85  func (p *valuePool) generateID() types.ID {
  86  	p.mu.Lock()
  87  	defer p.mu.Unlock()
  88  
  89  	p.CurrentID++
  90  
  91  	p.store()
  92  	return types.ID(p.CurrentID)
  93  }
  94  
  95  func (p *valuePool) nextSharedIP() net.IP {
  96  	p.mu.Lock()
  97  	defer p.mu.Unlock()
  98  
  99  	ip := p.CurrentSharedIP.To4()
 100  	ip[3]++
 101  	p.CurrentSharedIP = ip
 102  	p.store()
 103  
 104  	ret := net.IP{0x00, 0x00, 0x00, 0x00}
 105  	copy(ret, ip)
 106  	return ret
 107  }
 108  
 109  func (p *valuePool) nextMACAddress() net.HardwareAddr {
 110  	p.mu.Lock()
 111  	defer p.mu.Unlock()
 112  
 113  	mac := []byte(p.CurrentMACAddress)
 114  	mac[5]++
 115  	p.CurrentMACAddress = mac
 116  	p.store()
 117  
 118  	ret := net.HardwareAddr{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
 119  	copy(ret, mac)
 120  	return ret
 121  }
 122  
 123  func (p *valuePool) nextSubnet(maskLen int) *assignedSubnet {
 124  	p.mu.Lock()
 125  	defer p.mu.Unlock()
 126  
 127  	_, currentSubnet, _ := net.ParseCIDR(p.CurrentSubnets[maskLen])
 128  	next, _ := cidr.NextSubnet(currentSubnet, maskLen) // ignore result
 129  	p.CurrentSubnets[maskLen] = next.String()
 130  
 131  	count := cidr.AddressCount(next)
 132  	current := next.IP
 133  	var defaultGateway, networkAddr string
 134  
 135  	var addresses []string
 136  	for i := uint64(0); i < count; i++ {
 137  		// [0]: ネットワークアドレス
 138  		// [1:3]: ルータ自身が利用
 139  		// [len]: ブロードキャスト
 140  		if i < 4 || i == count-1 {
 141  			if i == 0 {
 142  				networkAddr = current.String()
 143  			}
 144  			if i == 1 {
 145  				defaultGateway = current.String()
 146  			}
 147  			current = cidr.Inc(current)
 148  			continue
 149  		}
 150  		addresses = append(addresses, current.String())
 151  		current = cidr.Inc(current)
 152  	}
 153  
 154  	p.store()
 155  	return &assignedSubnet{
 156  		defaultRoute:   defaultGateway,
 157  		networkAddress: networkAddr,
 158  		networkMaskLen: maskLen,
 159  		addresses:      addresses,
 160  	}
 161  }
 162  
 163  func (p *valuePool) nextSubnetFull(maskLen int, defaultRoute string) *assignedSubnet {
 164  	p.mu.Lock()
 165  	defer p.mu.Unlock()
 166  
 167  	_, currentSubnet, _ := net.ParseCIDR(p.CurrentSubnets[maskLen])
 168  	next, _ := cidr.NextSubnet(currentSubnet, maskLen) // ignore result
 169  	p.CurrentSubnets[maskLen] = next.String()
 170  
 171  	count := cidr.AddressCount(next)
 172  	current := next.IP
 173  	var networkAddr string
 174  
 175  	var addresses []string
 176  	for i := uint64(0); i < count; i++ {
 177  		addresses = append(addresses, current.String())
 178  		current = cidr.Inc(current)
 179  	}
 180  
 181  	p.store()
 182  	return &assignedSubnet{
 183  		defaultRoute:   defaultRoute,
 184  		networkAddress: networkAddr,
 185  		networkMaskLen: maskLen,
 186  		addresses:      addresses,
 187  	}
 188  }
 189  
 190  type assignedSubnet struct {
 191  	defaultRoute   string
 192  	networkMaskLen int
 193  	networkAddress string
 194  	addresses      []string
 195  }
 196