Skip to content

Commit

Permalink
Merge pull request #964 from katiewasnothere/ncproxy-iov
Browse files Browse the repository at this point in the history
Add support for modifying iov settings in ncproxy
  • Loading branch information
katiewasnothere authored Apr 1, 2021
2 parents 65090e5 + 557915e commit 628db61
Show file tree
Hide file tree
Showing 13 changed files with 2,059 additions and 401 deletions.
155 changes: 139 additions & 16 deletions cmd/ncproxy/ncproxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/Microsoft/hcsshim/cmd/ncproxy/nodenetsvc"
"github.com/Microsoft/hcsshim/hcn"
"github.com/Microsoft/hcsshim/internal/computeagent"
"github.com/Microsoft/hcsshim/internal/log"
"github.com/Microsoft/hcsshim/internal/ncproxyttrpc"
"github.com/Microsoft/hcsshim/internal/oc"
"github.com/Microsoft/hcsshim/internal/uvm"
Expand Down Expand Up @@ -56,6 +57,85 @@ func (s *grpcService) AddNIC(ctx context.Context, req *ncproxygrpc.AddNICRequest
return nil, status.Errorf(codes.FailedPrecondition, "No shim registered for namespace `%s`", req.ContainerID)
}

func (s *grpcService) ModifyNIC(ctx context.Context, req *ncproxygrpc.ModifyNICRequest) (_ *ncproxygrpc.ModifyNICResponse, err error) {
ctx, span := trace.StartSpan(ctx, "ModifyNIC")
defer span.End()
defer func() { oc.SetSpanStatus(span, err) }()

span.AddAttributes(
trace.StringAttribute("containerID", req.ContainerID),
trace.StringAttribute("endpointName", req.EndpointName),
trace.StringAttribute("nicID", req.NicID))

log.G(ctx).WithField("iov settings", req.IovPolicySettings).Info("ModifyNIC iov settings")

if req.ContainerID == "" || req.EndpointName == "" || req.NicID == "" || req.IovPolicySettings == nil {
return nil, status.Error(codes.InvalidArgument, "received empty field in request")
}

if client, ok := containerIDToShim[req.ContainerID]; ok {
caReq := &computeagent.ModifyNICInternalRequest{
NicID: req.NicID,
EndpointName: req.EndpointName,
IovPolicySettings: &computeagent.IovSettings{
IovOffloadWeight: req.IovPolicySettings.IovOffloadWeight,
QueuePairsRequested: req.IovPolicySettings.QueuePairsRequested,
InterruptModeration: req.IovPolicySettings.InterruptModeration,
},
}

hcnIOVSettings := &hcn.IovPolicySetting{
IovOffloadWeight: req.IovPolicySettings.IovOffloadWeight,
QueuePairsRequested: req.IovPolicySettings.QueuePairsRequested,
InterruptModeration: req.IovPolicySettings.InterruptModeration,
}
rawJSON, err := json.Marshal(hcnIOVSettings)
if err != nil {
return nil, err
}

iovPolicy := hcn.EndpointPolicy{
Type: hcn.IOV,
Settings: rawJSON,
}
policies := []hcn.EndpointPolicy{iovPolicy}

ep, err := hcn.GetEndpointByName(req.EndpointName)
if err != nil {
if _, ok := err.(hcn.EndpointNotFoundError); ok {
return nil, status.Errorf(codes.NotFound, "no endpoint with name `%s` found", req.EndpointName)
}
return nil, errors.Wrapf(err, "failed to get endpoint with name `%s`", req.EndpointName)
}

// To turn off iov offload on an endpoint, we need to first call into HCS to change the
// offload weight and then call into HNS to revoke the policy.
//
// To turn on iov offload, the reverse order is used.
if req.IovPolicySettings.IovOffloadWeight == 0 {
if _, err := client.ModifyNIC(ctx, caReq); err != nil {
return nil, err
}
if err := modifyEndpoint(ctx, ep.Id, policies, hcn.RequestTypeUpdate); err != nil {
return nil, errors.Wrap(err, "failed to modify network adapter")
}
if err := modifyEndpoint(ctx, ep.Id, policies, hcn.RequestTypeRemove); err != nil {
return nil, errors.Wrap(err, "failed to modify network adapter")
}
} else {
if err := modifyEndpoint(ctx, ep.Id, policies, hcn.RequestTypeUpdate); err != nil {
return nil, errors.Wrap(err, "failed to modify network adapter")
}
if _, err := client.ModifyNIC(ctx, caReq); err != nil {
return nil, err
}
}

return &ncproxygrpc.ModifyNICResponse{}, nil
}
return nil, status.Errorf(codes.FailedPrecondition, "No shim registered for containerID `%s`", req.ContainerID)
}

func (s *grpcService) DeleteNIC(ctx context.Context, req *ncproxygrpc.DeleteNICRequest) (_ *ncproxygrpc.DeleteNICResponse, err error) {
ctx, span := trace.StartSpan(ctx, "DeleteNIC")
defer span.End()
Expand Down Expand Up @@ -176,6 +256,43 @@ func (s *grpcService) CreateNetwork(ctx context.Context, req *ncproxygrpc.Create
}, nil
}

func constructEndpointPolicies(req *ncproxygrpc.CreateEndpointRequest) ([]hcn.EndpointPolicy, error) {
policies := []hcn.EndpointPolicy{}
if req.IovPolicySettings != nil {
iovSettings := hcn.IovPolicySetting{
IovOffloadWeight: req.IovPolicySettings.IovOffloadWeight,
QueuePairsRequested: req.IovPolicySettings.QueuePairsRequested,
InterruptModeration: req.IovPolicySettings.InterruptModeration,
}
iovJSON, err := json.Marshal(iovSettings)
if err != nil {
return []hcn.EndpointPolicy{}, errors.Wrap(err, "failed to marshal IovPolicySettings")
}
policy := hcn.EndpointPolicy{
Type: hcn.IOV,
Settings: iovJSON,
}
policies = append(policies, policy)
}

if req.PortnamePolicySetting != nil {
portPolicy := hcn.PortnameEndpointPolicySetting{
Name: req.PortnamePolicySetting.PortName,
}
portPolicyJSON, err := json.Marshal(portPolicy)
if err != nil {
return []hcn.EndpointPolicy{}, errors.Wrap(err, "failed to marshal portname")
}
policy := hcn.EndpointPolicy{
Type: hcn.PortName,
Settings: portPolicyJSON,
}
policies = append(policies, policy)
}

return policies, nil
}

func (s *grpcService) CreateEndpoint(ctx context.Context, req *ncproxygrpc.CreateEndpointRequest) (_ *ncproxygrpc.CreateEndpointResponse, err error) {
ctx, span := trace.StartSpan(ctx, "CreateEndpoint") //nolint:ineffassign,staticcheck
defer span.End()
Expand Down Expand Up @@ -210,30 +327,17 @@ func (s *grpcService) CreateEndpoint(ctx context.Context, req *ncproxygrpc.Creat
PrefixLength: uint8(prefixLen),
}

// Construct the portname policy we'll be setting on the endpoint.
var portPolicy hcn.PortnameEndpointPolicySetting
if req.PortnamePolicySetting != nil {
portPolicy = hcn.PortnameEndpointPolicySetting{
Name: req.PortnamePolicySetting.PortName,
}
}
portPolicyJSON, err := json.Marshal(portPolicy)
policies, err := constructEndpointPolicies(req)
if err != nil {
return nil, errors.Wrap(err, "failed to marshal portname")
}

// Construct endpoint policy
epPolicy := hcn.EndpointPolicy{
Type: hcn.EndpointPolicyType(req.PolicyType.String()),
Settings: portPolicyJSON,
return nil, errors.Wrap(err, "failed to construct endpoint policies")
}

endpoint := &hcn.HostComputeEndpoint{
Name: req.Name,
HostComputeNetwork: network.Id,
MacAddress: req.Macaddress,
IpConfigurations: []hcn.IpConfig{ipConfig},
Policies: []hcn.EndpointPolicy{epPolicy},
Policies: policies,
SchemaVersion: hcn.SchemaVersion{
Major: 2,
Minor: 0,
Expand Down Expand Up @@ -498,3 +602,22 @@ func (s *ttrpcService) ConfigureNetworking(ctx context.Context, req *ncproxyttrp
}
return &ncproxyttrpc.ConfigureNetworkingInternalResponse{}, nil
}

func modifyEndpoint(ctx context.Context, id string, policies []hcn.EndpointPolicy, requestType hcn.RequestType) error {
endpointRequest := hcn.PolicyEndpointRequest{
Policies: policies,
}

settingsJSON, err := json.Marshal(endpointRequest)
if err != nil {
return err
}

requestMessage := &hcn.ModifyEndpointSettingRequest{
ResourceType: hcn.EndpointResourceTypePolicy,
RequestType: requestType,
Settings: settingsJSON,
}

return hcn.ModifyEndpointSettings(id, requestMessage)
}
Loading

0 comments on commit 628db61

Please sign in to comment.