1
2
3 package remotevm
4
5 import (
6 "context"
7 "encoding/json"
8 "fmt"
9 "strings"
10
11 "github.com/Microsoft/go-winio/pkg/guid"
12 "github.com/Microsoft/hcsshim/hcn"
13 "github.com/Microsoft/hcsshim/internal/vmservice"
14 "github.com/pkg/errors"
15 )
16
17 func getSwitchID(endpointID, portID string) (string, error) {
18
19 ep, err := hcn.GetEndpointByID(endpointID)
20 if err != nil {
21 return "", errors.Wrapf(err, "failed to get endpoint %q", endpointID)
22 }
23
24 type ExtraInfo struct {
25 Allocators []struct {
26 SwitchID string `json:"SwitchId"`
27 EndpointPortGUID string `json:"EndpointPortGuid"`
28 }
29 }
30
31 var exi ExtraInfo
32 if err := json.Unmarshal(ep.Health.Extra.Resources, &exi); err != nil {
33 return "", errors.Wrapf(err, "failed to unmarshal resource data from endpoint %q", endpointID)
34 }
35
36 if len(exi.Allocators) == 0 {
37 return "", errors.New("no resource data found for endpoint")
38 }
39
40
41
42
43 var switchID string
44 for _, allocator := range exi.Allocators {
45 if allocator.SwitchID != "" && strings.ToLower(allocator.EndpointPortGUID) == portID {
46 switchID = allocator.SwitchID
47 break
48 }
49 }
50 return switchID, nil
51 }
52
53 func (uvm *utilityVM) AddNIC(ctx context.Context, nicID, endpointID, macAddr string) error {
54 portID, err := guid.NewV4()
55 if err != nil {
56 return errors.Wrap(err, "failed to generate guid for port")
57 }
58
59 vmEndpointRequest := hcn.VmEndpointRequest{
60 PortId: portID,
61 VirtualNicName: fmt.Sprintf("%s--%s", nicID, portID),
62 VirtualMachineId: guid.GUID{},
63 }
64
65 m, err := json.Marshal(vmEndpointRequest)
66 if err != nil {
67 return errors.Wrap(err, "failed to marshal endpoint request json")
68 }
69
70 if err := hcn.ModifyEndpointSettings(endpointID, &hcn.ModifyEndpointSettingRequest{
71 ResourceType: hcn.EndpointResourceTypePort,
72 RequestType: hcn.RequestTypeAdd,
73 Settings: json.RawMessage(m),
74 }); err != nil {
75 return errors.Wrap(err, "failed to configure switch port")
76 }
77
78 switchID, err := getSwitchID(endpointID, portID.String())
79 if err != nil {
80 return err
81 }
82
83 nic := &vmservice.NICConfig{
84 NicID: nicID,
85 MacAddress: macAddr,
86 PortID: portID.String(),
87 SwitchID: switchID,
88 }
89
90 if _, err := uvm.client.ModifyResource(ctx,
91 &vmservice.ModifyResourceRequest{
92 Type: vmservice.ModifyType_ADD,
93 Resource: &vmservice.ModifyResourceRequest_NicConfig{
94 NicConfig: nic,
95 },
96 },
97 ); err != nil {
98 return errors.Wrap(err, "failed to add network adapter")
99 }
100
101 return nil
102 }
103
104 func (uvm *utilityVM) RemoveNIC(ctx context.Context, nicID, endpointID, macAddr string) error {
105 nic := &vmservice.NICConfig{
106 NicID: nicID,
107 MacAddress: macAddr,
108 }
109
110 if _, err := uvm.client.ModifyResource(ctx,
111 &vmservice.ModifyResourceRequest{
112 Type: vmservice.ModifyType_REMOVE,
113 Resource: &vmservice.ModifyResourceRequest_NicConfig{
114 NicConfig: nic,
115 },
116 },
117 ); err != nil {
118 return errors.Wrap(err, "failed to remove network adapter")
119 }
120
121 return nil
122 }
123
View as plain text