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