mirror of
https://github.com/rancher/plugins.git
synced 2025-07-08 20:53:53 +00:00
252 lines
6.7 KiB
Go
252 lines
6.7 KiB
Go
package uvm
|
|
|
|
import (
|
|
"fmt"
|
|
"path"
|
|
|
|
"github.com/Microsoft/hcsshim/hcn"
|
|
"github.com/Microsoft/hcsshim/internal/guestrequest"
|
|
"github.com/Microsoft/hcsshim/internal/guid"
|
|
"github.com/Microsoft/hcsshim/internal/hns"
|
|
"github.com/Microsoft/hcsshim/internal/requesttype"
|
|
"github.com/Microsoft/hcsshim/internal/schema1"
|
|
"github.com/Microsoft/hcsshim/internal/schema2"
|
|
"github.com/Microsoft/hcsshim/osversion"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
// AddNetNS adds network namespace inside the guest & adds endpoints to the guest on that namepace
|
|
func (uvm *UtilityVM) AddNetNS(id string, endpoints []*hns.HNSEndpoint) (err error) {
|
|
uvm.m.Lock()
|
|
defer uvm.m.Unlock()
|
|
ns := uvm.namespaces[id]
|
|
if ns == nil {
|
|
ns = &namespaceInfo{}
|
|
|
|
if uvm.isNetworkNamespaceSupported() {
|
|
// Add a Guest Network namespace. On LCOW we add the adapters
|
|
// dynamically.
|
|
if uvm.operatingSystem == "windows" {
|
|
hcnNamespace, err := hcn.GetNamespaceByID(id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
guestNamespace := hcsschema.ModifySettingRequest{
|
|
GuestRequest: guestrequest.GuestRequest{
|
|
ResourceType: guestrequest.ResourceTypeNetworkNamespace,
|
|
RequestType: requesttype.Add,
|
|
Settings: hcnNamespace,
|
|
},
|
|
}
|
|
if err := uvm.Modify(&guestNamespace); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
|
|
defer func() {
|
|
if err != nil {
|
|
if e := uvm.removeNamespaceNICs(ns); e != nil {
|
|
logrus.Warnf("failed to undo NIC add: %v", e)
|
|
}
|
|
}
|
|
}()
|
|
for _, endpoint := range endpoints {
|
|
nicID := guid.New()
|
|
err = uvm.addNIC(nicID, endpoint)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
ns.nics = append(ns.nics, nicInfo{nicID, endpoint})
|
|
}
|
|
if uvm.namespaces == nil {
|
|
uvm.namespaces = make(map[string]*namespaceInfo)
|
|
}
|
|
uvm.namespaces[id] = ns
|
|
}
|
|
ns.refCount++
|
|
return nil
|
|
}
|
|
|
|
//RemoveNetNS removes the namespace information
|
|
func (uvm *UtilityVM) RemoveNetNS(id string) error {
|
|
uvm.m.Lock()
|
|
defer uvm.m.Unlock()
|
|
ns := uvm.namespaces[id]
|
|
if ns == nil || ns.refCount <= 0 {
|
|
panic(fmt.Errorf("removed a namespace that was not added: %s", id))
|
|
}
|
|
|
|
ns.refCount--
|
|
|
|
// Remove the Guest Network namespace
|
|
if uvm.isNetworkNamespaceSupported() {
|
|
if uvm.operatingSystem == "windows" {
|
|
hcnNamespace, err := hcn.GetNamespaceByID(id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
guestNamespace := hcsschema.ModifySettingRequest{
|
|
GuestRequest: guestrequest.GuestRequest{
|
|
ResourceType: guestrequest.ResourceTypeNetworkNamespace,
|
|
RequestType: requesttype.Remove,
|
|
Settings: hcnNamespace,
|
|
},
|
|
}
|
|
if err := uvm.Modify(&guestNamespace); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
|
|
var err error
|
|
if ns.refCount == 0 {
|
|
err = uvm.removeNamespaceNICs(ns)
|
|
delete(uvm.namespaces, id)
|
|
}
|
|
|
|
return err
|
|
}
|
|
|
|
// IsNetworkNamespaceSupported returns bool value specifying if network namespace is supported inside the guest
|
|
func (uvm *UtilityVM) isNetworkNamespaceSupported() bool {
|
|
p, err := uvm.ComputeSystem().Properties(schema1.PropertyTypeGuestConnection)
|
|
if err == nil {
|
|
return p.GuestConnectionInfo.GuestDefinedCapabilities.NamespaceAddRequestSupported
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func (uvm *UtilityVM) removeNamespaceNICs(ns *namespaceInfo) error {
|
|
for len(ns.nics) != 0 {
|
|
nic := ns.nics[len(ns.nics)-1]
|
|
err := uvm.removeNIC(nic.ID, nic.Endpoint)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
ns.nics = ns.nics[:len(ns.nics)-1]
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func getNetworkModifyRequest(adapterID string, requestType string, settings interface{}) interface{} {
|
|
if osversion.Get().Build >= osversion.RS5 {
|
|
return guestrequest.NetworkModifyRequest{
|
|
AdapterId: adapterID,
|
|
RequestType: requestType,
|
|
Settings: settings,
|
|
}
|
|
}
|
|
return guestrequest.RS4NetworkModifyRequest{
|
|
AdapterInstanceId: adapterID,
|
|
RequestType: requestType,
|
|
Settings: settings,
|
|
}
|
|
}
|
|
|
|
func (uvm *UtilityVM) addNIC(id guid.GUID, endpoint *hns.HNSEndpoint) error {
|
|
|
|
// First a pre-add. This is a guest-only request and is only done on Windows.
|
|
if uvm.operatingSystem == "windows" {
|
|
preAddRequest := hcsschema.ModifySettingRequest{
|
|
GuestRequest: guestrequest.GuestRequest{
|
|
ResourceType: guestrequest.ResourceTypeNetwork,
|
|
RequestType: requesttype.Add,
|
|
Settings: getNetworkModifyRequest(
|
|
id.String(),
|
|
requesttype.PreAdd,
|
|
endpoint),
|
|
},
|
|
}
|
|
if err := uvm.Modify(&preAddRequest); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
// Then the Add itself
|
|
request := hcsschema.ModifySettingRequest{
|
|
RequestType: requesttype.Add,
|
|
ResourcePath: path.Join("VirtualMachine/Devices/NetworkAdapters", id.String()),
|
|
Settings: hcsschema.NetworkAdapter{
|
|
EndpointId: endpoint.Id,
|
|
MacAddress: endpoint.MacAddress,
|
|
},
|
|
}
|
|
|
|
if uvm.operatingSystem == "windows" {
|
|
request.GuestRequest = guestrequest.GuestRequest{
|
|
ResourceType: guestrequest.ResourceTypeNetwork,
|
|
RequestType: requesttype.Add,
|
|
Settings: getNetworkModifyRequest(
|
|
id.String(),
|
|
requesttype.Add,
|
|
nil),
|
|
}
|
|
} else {
|
|
// Verify this version of LCOW supports Network HotAdd
|
|
if uvm.isNetworkNamespaceSupported() {
|
|
request.GuestRequest = guestrequest.GuestRequest{
|
|
ResourceType: guestrequest.ResourceTypeNetwork,
|
|
RequestType: requesttype.Add,
|
|
Settings: &guestrequest.LCOWNetworkAdapter{
|
|
NamespaceID: endpoint.Namespace.ID,
|
|
ID: id.String(),
|
|
MacAddress: endpoint.MacAddress,
|
|
IPAddress: endpoint.IPAddress.String(),
|
|
PrefixLength: endpoint.PrefixLength,
|
|
GatewayAddress: endpoint.GatewayAddress,
|
|
DNSSuffix: endpoint.DNSSuffix,
|
|
DNSServerList: endpoint.DNSServerList,
|
|
EnableLowMetric: endpoint.EnableLowMetric,
|
|
EncapOverhead: endpoint.EncapOverhead,
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
if err := uvm.Modify(&request); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (uvm *UtilityVM) removeNIC(id guid.GUID, endpoint *hns.HNSEndpoint) error {
|
|
request := hcsschema.ModifySettingRequest{
|
|
RequestType: requesttype.Remove,
|
|
ResourcePath: path.Join("VirtualMachine/Devices/NetworkAdapters", id.String()),
|
|
Settings: hcsschema.NetworkAdapter{
|
|
EndpointId: endpoint.Id,
|
|
MacAddress: endpoint.MacAddress,
|
|
},
|
|
}
|
|
|
|
if uvm.operatingSystem == "windows" {
|
|
request.GuestRequest = hcsschema.ModifySettingRequest{
|
|
RequestType: requesttype.Remove,
|
|
Settings: getNetworkModifyRequest(
|
|
id.String(),
|
|
requesttype.Remove,
|
|
nil),
|
|
}
|
|
} else {
|
|
// Verify this version of LCOW supports Network HotRemove
|
|
if uvm.isNetworkNamespaceSupported() {
|
|
request.GuestRequest = guestrequest.GuestRequest{
|
|
ResourceType: guestrequest.ResourceTypeNetwork,
|
|
RequestType: requesttype.Remove,
|
|
Settings: &guestrequest.LCOWNetworkAdapter{
|
|
NamespaceID: endpoint.Namespace.ID,
|
|
ID: endpoint.Id,
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
if err := uvm.Modify(&request); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|