1
2
3 package hcn
4
5 import (
6 "encoding/json"
7 "errors"
8
9 "github.com/Microsoft/go-winio/pkg/guid"
10 "github.com/Microsoft/hcsshim/internal/interop"
11 "github.com/sirupsen/logrus"
12 )
13
14
15 type Route struct {
16 NextHop string `json:",omitempty"`
17 DestinationPrefix string `json:",omitempty"`
18 Metric uint16 `json:",omitempty"`
19 }
20
21
22 type Subnet struct {
23 IpAddressPrefix string `json:",omitempty"`
24 Policies []json.RawMessage `json:",omitempty"`
25 Routes []Route `json:",omitempty"`
26 }
27
28
29
30 type Ipam struct {
31 Type string `json:",omitempty"`
32 Subnets []Subnet `json:",omitempty"`
33 }
34
35
36 type MacRange struct {
37 StartMacAddress string `json:",omitempty"`
38 EndMacAddress string `json:",omitempty"`
39 }
40
41
42 type MacPool struct {
43 Ranges []MacRange `json:",omitempty"`
44 }
45
46
47 type Dns struct {
48 Domain string `json:",omitempty"`
49 Search []string `json:",omitempty"`
50 ServerList []string `json:",omitempty"`
51 Options []string `json:",omitempty"`
52 }
53
54
55 type NetworkType string
56
57
58 const (
59 NAT NetworkType = "NAT"
60 Transparent NetworkType = "Transparent"
61 L2Bridge NetworkType = "L2Bridge"
62 L2Tunnel NetworkType = "L2Tunnel"
63 ICS NetworkType = "ICS"
64 Private NetworkType = "Private"
65 Overlay NetworkType = "Overlay"
66 )
67
68
69 type NetworkFlags uint32
70
71
72 const (
73 None NetworkFlags = 0
74 EnableNonPersistent NetworkFlags = 8
75 )
76
77
78 type HostComputeNetwork struct {
79 Id string `json:"ID,omitempty"`
80 Name string `json:",omitempty"`
81 Type NetworkType `json:",omitempty"`
82 Policies []NetworkPolicy `json:",omitempty"`
83 MacPool MacPool `json:",omitempty"`
84 Dns Dns `json:",omitempty"`
85 Ipams []Ipam `json:",omitempty"`
86 Flags NetworkFlags `json:",omitempty"`
87 Health Health `json:",omitempty"`
88 SchemaVersion SchemaVersion `json:",omitempty"`
89 }
90
91
92 type NetworkResourceType string
93
94 var (
95
96 NetworkResourceTypePolicy NetworkResourceType = "Policy"
97
98 NetworkResourceTypeDNS NetworkResourceType = "DNS"
99
100 NetworkResourceTypeExtension NetworkResourceType = "Extension"
101 )
102
103
104
105 type ModifyNetworkSettingRequest struct {
106 ResourceType NetworkResourceType `json:",omitempty"`
107 RequestType RequestType `json:",omitempty"`
108 Settings json.RawMessage `json:",omitempty"`
109 }
110
111 type PolicyNetworkRequest struct {
112 Policies []NetworkPolicy `json:",omitempty"`
113 }
114
115 func getNetwork(networkGUID guid.GUID, query string) (*HostComputeNetwork, error) {
116
117 var (
118 networkHandle hcnNetwork
119 resultBuffer *uint16
120 propertiesBuffer *uint16
121 )
122 hr := hcnOpenNetwork(&networkGUID, &networkHandle, &resultBuffer)
123 if err := checkForErrors("hcnOpenNetwork", hr, resultBuffer); err != nil {
124 return nil, err
125 }
126
127 hr = hcnQueryNetworkProperties(networkHandle, query, &propertiesBuffer, &resultBuffer)
128 if err := checkForErrors("hcnQueryNetworkProperties", hr, resultBuffer); err != nil {
129 return nil, err
130 }
131 properties := interop.ConvertAndFreeCoTaskMemString(propertiesBuffer)
132
133 hr = hcnCloseNetwork(networkHandle)
134 if err := checkForErrors("hcnCloseNetwork", hr, nil); err != nil {
135 return nil, err
136 }
137
138 var outputNetwork HostComputeNetwork
139
140
141
142
143 outputNetwork.Type = NAT
144
145 if err := json.Unmarshal([]byte(properties), &outputNetwork); err != nil {
146 return nil, err
147 }
148 return &outputNetwork, nil
149 }
150
151 func enumerateNetworks(query string) ([]HostComputeNetwork, error) {
152
153 var (
154 resultBuffer *uint16
155 networkBuffer *uint16
156 )
157 hr := hcnEnumerateNetworks(query, &networkBuffer, &resultBuffer)
158 if err := checkForErrors("hcnEnumerateNetworks", hr, resultBuffer); err != nil {
159 return nil, err
160 }
161
162 networks := interop.ConvertAndFreeCoTaskMemString(networkBuffer)
163 var networkIds []guid.GUID
164 if err := json.Unmarshal([]byte(networks), &networkIds); err != nil {
165 return nil, err
166 }
167
168 var outputNetworks []HostComputeNetwork
169 for _, networkGUID := range networkIds {
170 network, err := getNetwork(networkGUID, query)
171 if err != nil {
172 return nil, err
173 }
174 outputNetworks = append(outputNetworks, *network)
175 }
176 return outputNetworks, nil
177 }
178
179 func createNetwork(settings string) (*HostComputeNetwork, error) {
180
181 var (
182 networkHandle hcnNetwork
183 resultBuffer *uint16
184 propertiesBuffer *uint16
185 )
186 networkGUID := guid.GUID{}
187 hr := hcnCreateNetwork(&networkGUID, settings, &networkHandle, &resultBuffer)
188 if err := checkForErrors("hcnCreateNetwork", hr, resultBuffer); err != nil {
189 return nil, err
190 }
191
192 hcnQuery := defaultQuery()
193 query, err := json.Marshal(hcnQuery)
194 if err != nil {
195 return nil, err
196 }
197 hr = hcnQueryNetworkProperties(networkHandle, string(query), &propertiesBuffer, &resultBuffer)
198 if err := checkForErrors("hcnQueryNetworkProperties", hr, resultBuffer); err != nil {
199 return nil, err
200 }
201 properties := interop.ConvertAndFreeCoTaskMemString(propertiesBuffer)
202
203 hr = hcnCloseNetwork(networkHandle)
204 if err := checkForErrors("hcnCloseNetwork", hr, nil); err != nil {
205 return nil, err
206 }
207
208 var outputNetwork HostComputeNetwork
209
210
211
212
213 outputNetwork.Type = NAT
214
215 if err := json.Unmarshal([]byte(properties), &outputNetwork); err != nil {
216 return nil, err
217 }
218 return &outputNetwork, nil
219 }
220
221 func modifyNetwork(networkID string, settings string) (*HostComputeNetwork, error) {
222 networkGUID, err := guid.FromString(networkID)
223 if err != nil {
224 return nil, errInvalidNetworkID
225 }
226
227 var (
228 networkHandle hcnNetwork
229 resultBuffer *uint16
230 propertiesBuffer *uint16
231 )
232 hr := hcnOpenNetwork(&networkGUID, &networkHandle, &resultBuffer)
233 if err := checkForErrors("hcnOpenNetwork", hr, resultBuffer); err != nil {
234 return nil, err
235 }
236
237 hr = hcnModifyNetwork(networkHandle, settings, &resultBuffer)
238 if err := checkForErrors("hcnModifyNetwork", hr, resultBuffer); err != nil {
239 return nil, err
240 }
241
242 hcnQuery := defaultQuery()
243 query, err := json.Marshal(hcnQuery)
244 if err != nil {
245 return nil, err
246 }
247 hr = hcnQueryNetworkProperties(networkHandle, string(query), &propertiesBuffer, &resultBuffer)
248 if err := checkForErrors("hcnQueryNetworkProperties", hr, resultBuffer); err != nil {
249 return nil, err
250 }
251 properties := interop.ConvertAndFreeCoTaskMemString(propertiesBuffer)
252
253 hr = hcnCloseNetwork(networkHandle)
254 if err := checkForErrors("hcnCloseNetwork", hr, nil); err != nil {
255 return nil, err
256 }
257
258 var outputNetwork HostComputeNetwork
259
260
261
262
263 outputNetwork.Type = NAT
264
265 if err := json.Unmarshal([]byte(properties), &outputNetwork); err != nil {
266 return nil, err
267 }
268 return &outputNetwork, nil
269 }
270
271 func deleteNetwork(networkID string) error {
272 networkGUID, err := guid.FromString(networkID)
273 if err != nil {
274 return errInvalidNetworkID
275 }
276 var resultBuffer *uint16
277 hr := hcnDeleteNetwork(&networkGUID, &resultBuffer)
278 if err := checkForErrors("hcnDeleteNetwork", hr, resultBuffer); err != nil {
279 return err
280 }
281 return nil
282 }
283
284
285 func ListNetworks() ([]HostComputeNetwork, error) {
286 hcnQuery := defaultQuery()
287 networks, err := ListNetworksQuery(hcnQuery)
288 if err != nil {
289 return nil, err
290 }
291 return networks, nil
292 }
293
294
295 func ListNetworksQuery(query HostComputeQuery) ([]HostComputeNetwork, error) {
296 queryJSON, err := json.Marshal(query)
297 if err != nil {
298 return nil, err
299 }
300
301 networks, err := enumerateNetworks(string(queryJSON))
302 if err != nil {
303 return nil, err
304 }
305 return networks, nil
306 }
307
308
309 func GetNetworkByID(networkID string) (*HostComputeNetwork, error) {
310 hcnQuery := defaultQuery()
311 mapA := map[string]string{"ID": networkID}
312 filter, err := json.Marshal(mapA)
313 if err != nil {
314 return nil, err
315 }
316 hcnQuery.Filter = string(filter)
317
318 networks, err := ListNetworksQuery(hcnQuery)
319 if err != nil {
320 return nil, err
321 }
322 if len(networks) == 0 {
323 return nil, NetworkNotFoundError{NetworkID: networkID}
324 }
325 return &networks[0], err
326 }
327
328
329 func GetNetworkByName(networkName string) (*HostComputeNetwork, error) {
330 hcnQuery := defaultQuery()
331 mapA := map[string]string{"Name": networkName}
332 filter, err := json.Marshal(mapA)
333 if err != nil {
334 return nil, err
335 }
336 hcnQuery.Filter = string(filter)
337
338 networks, err := ListNetworksQuery(hcnQuery)
339 if err != nil {
340 return nil, err
341 }
342 if len(networks) == 0 {
343 return nil, NetworkNotFoundError{NetworkName: networkName}
344 }
345 return &networks[0], err
346 }
347
348
349 func (network *HostComputeNetwork) Create() (*HostComputeNetwork, error) {
350 logrus.Debugf("hcn::HostComputeNetwork::Create id=%s", network.Id)
351 for _, ipam := range network.Ipams {
352 for _, subnet := range ipam.Subnets {
353 if subnet.IpAddressPrefix != "" {
354 hasDefault := false
355 for _, route := range subnet.Routes {
356 if route.NextHop == "" {
357 return nil, errors.New("network create error, subnet has address prefix but no gateway specified")
358 }
359 if route.DestinationPrefix == "0.0.0.0/0" || route.DestinationPrefix == "::/0" {
360 hasDefault = true
361 }
362 }
363 if !hasDefault {
364 return nil, errors.New("network create error, no default gateway")
365 }
366 }
367 }
368 }
369
370 jsonString, err := json.Marshal(network)
371 if err != nil {
372 return nil, err
373 }
374
375 logrus.Debugf("hcn::HostComputeNetwork::Create JSON: %s", jsonString)
376 network, hcnErr := createNetwork(string(jsonString))
377 if hcnErr != nil {
378 return nil, hcnErr
379 }
380 return network, nil
381 }
382
383
384 func (network *HostComputeNetwork) Delete() error {
385 logrus.Debugf("hcn::HostComputeNetwork::Delete id=%s", network.Id)
386
387 if err := deleteNetwork(network.Id); err != nil {
388 return err
389 }
390 return nil
391 }
392
393
394 func (network *HostComputeNetwork) ModifyNetworkSettings(request *ModifyNetworkSettingRequest) error {
395 logrus.Debugf("hcn::HostComputeNetwork::ModifyNetworkSettings id=%s", network.Id)
396
397 networkSettingsRequest, err := json.Marshal(request)
398 if err != nil {
399 return err
400 }
401
402 _, err = modifyNetwork(network.Id, string(networkSettingsRequest))
403 if err != nil {
404 return err
405 }
406 return nil
407 }
408
409
410 func (network *HostComputeNetwork) AddPolicy(networkPolicy PolicyNetworkRequest) error {
411 logrus.Debugf("hcn::HostComputeNetwork::AddPolicy id=%s", network.Id)
412
413 settingsJSON, err := json.Marshal(networkPolicy)
414 if err != nil {
415 return err
416 }
417 requestMessage := &ModifyNetworkSettingRequest{
418 ResourceType: NetworkResourceTypePolicy,
419 RequestType: RequestTypeAdd,
420 Settings: settingsJSON,
421 }
422
423 return network.ModifyNetworkSettings(requestMessage)
424 }
425
426
427 func (network *HostComputeNetwork) RemovePolicy(networkPolicy PolicyNetworkRequest) error {
428 logrus.Debugf("hcn::HostComputeNetwork::RemovePolicy id=%s", network.Id)
429
430 settingsJSON, err := json.Marshal(networkPolicy)
431 if err != nil {
432 return err
433 }
434 requestMessage := &ModifyNetworkSettingRequest{
435 ResourceType: NetworkResourceTypePolicy,
436 RequestType: RequestTypeRemove,
437 Settings: settingsJSON,
438 }
439
440 return network.ModifyNetworkSettings(requestMessage)
441 }
442
443
444 func (network *HostComputeNetwork) CreateEndpoint(endpoint *HostComputeEndpoint) (*HostComputeEndpoint, error) {
445 isRemote := endpoint.Flags&EndpointFlagsRemoteEndpoint != 0
446 logrus.Debugf("hcn::HostComputeNetwork::CreatEndpoint, networkId=%s remote=%t", network.Id, isRemote)
447
448 endpoint.HostComputeNetwork = network.Id
449 endpointSettings, err := json.Marshal(endpoint)
450 if err != nil {
451 return nil, err
452 }
453 newEndpoint, err := createEndpoint(network.Id, string(endpointSettings))
454 if err != nil {
455 return nil, err
456 }
457 return newEndpoint, nil
458 }
459
460
461 func (network *HostComputeNetwork) CreateRemoteEndpoint(endpoint *HostComputeEndpoint) (*HostComputeEndpoint, error) {
462 endpoint.Flags = EndpointFlagsRemoteEndpoint | endpoint.Flags
463 return network.CreateEndpoint(endpoint)
464 }
465
View as plain text