From f943e5d91f6922c599b46727e2dfd5e8e7e5bea8 Mon Sep 17 00:00:00 2001 From: jiangpengfei Date: Wed, 19 Aug 2020 22:43:54 +0800 Subject: [PATCH 50/50] runtime: add kata-network upate-iface subcommand reason: add kata-network update-iface subcommand to update the exist interface in the Kata VM. Signed-off-by: jiangpengfei --- cli/network.go | 37 +++++++++- virtcontainers/api.go | 25 +++++-- virtcontainers/implementation.go | 5 ++ virtcontainers/interfaces.go | 1 + virtcontainers/pkg/vcmock/mock.go | 8 +++ virtcontainers/pkg/vcmock/types.go | 1 + virtcontainers/sandbox.go | 137 +++++++++++++++++++++++++++++++++++++ 7 files changed, 207 insertions(+), 7 deletions(-) diff --git a/cli/network.go b/cli/network.go index 3dd0971e..7dce0528 100644 --- a/cli/network.go +++ b/cli/network.go @@ -65,8 +65,9 @@ var addIfaceCommand = cli.Command{ "hwAddr":"", "linkType":"tap", "vhostUserSocket":"" + "queues": } - device,name,mtu,hwAddr are required, IPAddresses and vhostUserSocket are optional. + device,name,mtu,hwAddr are required, IPAddresses, queues and vhostUserSocket are optional. `, Flags: []cli.Flag{}, Action: func(context *cli.Context) error { @@ -104,6 +105,34 @@ var delIfaceCommand = cli.Command{ }, } +var updateIfaceCommand = cli.Command{ + Name: "update-iface", + Usage: "update the interface in container", + ArgsUsage: `update-iface file or - for stdin + file or stdin for example: + { + "device":"", + "name":"", + "IPAddresses":[{"address":"","mask":""}], + "mtu":0, + "hwAddr":"", + "linkType":"", + "vhostUserSocket":"", + "queues":0 + } + name is required,IPAddresses is optional,device,mtu,hwAddr,linkType,queues and vhostUserSocket should be 0 or empty. + `, + Flags: []cli.Flag{}, + Action: func(context *cli.Context) error { + ctx, err := cliContextToContext(context) + if err != nil { + return err + } + + return networkModifyCommand(ctx, context.Args().First(), context.Args().Get(1), interfaceType, vcTypes.NetworkOpUpdate) + }, +} + var listIfacesCommand = cli.Command{ Name: "list-ifaces", Usage: "list network interfaces in a container", @@ -262,6 +291,12 @@ func networkModifyCommand(ctx context.Context, containerID, input string, opType kataLog.WithField("resulting-interface", fmt.Sprintf("%+v", resultingInf)). WithError(err).Error("delete interface failed") } + case vcTypes.NetworkOpUpdate: + resultingInf, err = vci.UpdateInterface(ctx, sandboxID, inf) + if err != nil { + kataLog.WithField("resulting-interface", fmt.Sprintf("%+v", resultingInf)). + WithError(err).Error("update interface failed") + } } json.NewEncoder(output).Encode(resultingInf) diff --git a/virtcontainers/api.go b/virtcontainers/api.go index 7036df8c..ca5412a9 100644 --- a/virtcontainers/api.go +++ b/virtcontainers/api.go @@ -889,7 +889,7 @@ func AddDevice(ctx context.Context, sandboxID string, info deviceConfig.DeviceIn return s.AddDevice(info) } -func toggleInterface(ctx context.Context, sandboxID string, inf *vcTypes.Interface, add bool) (*vcTypes.Interface, error) { +func toggleInterface(ctx context.Context, sandboxID string, inf *vcTypes.Interface, op vcTypes.NetworkOp) (*vcTypes.Interface, error) { if sandboxID == "" { return nil, vcTypes.ErrNeedSandboxID } @@ -906,11 +906,16 @@ func toggleInterface(ctx context.Context, sandboxID string, inf *vcTypes.Interfa } defer s.releaseStatelessSandbox() - if add { + switch op { + case vcTypes.NetworkOpAdd: return s.AddInterface(inf) + case vcTypes.NetworkOpRemove: + return s.RemoveInterface(inf) + case vcTypes.NetworkOpUpdate: + return s.UpdateInterface(inf) + default: + return nil, fmt.Errorf("operation is not found") } - - return s.RemoveInterface(inf) } // AddInterface is the virtcontainers add interface entry point. @@ -918,7 +923,7 @@ func AddInterface(ctx context.Context, sandboxID string, inf *vcTypes.Interface) span, ctx := trace(ctx, "AddInterface") defer span.Finish() - return toggleInterface(ctx, sandboxID, inf, true) + return toggleInterface(ctx, sandboxID, inf, vcTypes.NetworkOpAdd) } // RemoveInterface is the virtcontainers remove interface entry point. @@ -926,7 +931,15 @@ func RemoveInterface(ctx context.Context, sandboxID string, inf *vcTypes.Interfa span, ctx := trace(ctx, "RemoveInterface") defer span.Finish() - return toggleInterface(ctx, sandboxID, inf, false) + return toggleInterface(ctx, sandboxID, inf, vcTypes.NetworkOpRemove) +} + +// UpdateInterface updates interface entry point in the virtcontainers. +func UpdateInterface(ctx context.Context, sandboxID string, inf *vcTypes.Interface) (*vcTypes.Interface, error) { + span, ctx := trace(ctx, "UpdateInterface") + defer span.Finish() + + return toggleInterface(ctx, sandboxID, inf, vcTypes.NetworkOpUpdate) } // ListInterfaces is the virtcontainers list interfaces entry point. diff --git a/virtcontainers/implementation.go b/virtcontainers/implementation.go index 0265d1ed..e4bc4ae6 100644 --- a/virtcontainers/implementation.go +++ b/virtcontainers/implementation.go @@ -163,6 +163,11 @@ func (impl *VCImpl) ListInterfaces(ctx context.Context, sandboxID string) ([]*vc return ListInterfaces(ctx, sandboxID) } +// ListInterfaces implements the VC function of the same name. +func (impl *VCImpl) UpdateInterface(ctx context.Context, sandboxID string, inf *vcTypes.Interface) (*vcTypes.Interface, error) { + return UpdateInterface(ctx, sandboxID, inf) +} + // UpdateRoutes implements the VC function of the same name. func (impl *VCImpl) UpdateRoutes(ctx context.Context, sandboxID string, routes []*vcTypes.Route, op vcTypes.NetworkOp) ([]*vcTypes.Route, error) { return UpdateRoutes(ctx, sandboxID, routes, op) diff --git a/virtcontainers/interfaces.go b/virtcontainers/interfaces.go index d8f0be69..0fd12d84 100644 --- a/virtcontainers/interfaces.go +++ b/virtcontainers/interfaces.go @@ -51,6 +51,7 @@ type VC interface { AddInterface(ctx context.Context, sandboxID string, inf *vcTypes.Interface) (*vcTypes.Interface, error) RemoveInterface(ctx context.Context, sandboxID string, inf *vcTypes.Interface) (*vcTypes.Interface, error) + UpdateInterface(ctx context.Context, sandboxID string, inf *vcTypes.Interface) (*vcTypes.Interface, error) ListInterfaces(ctx context.Context, sandboxID string) ([]*vcTypes.Interface, error) UpdateRoutes(ctx context.Context, sandboxID string, routes []*vcTypes.Route, op vcTypes.NetworkOp) ([]*vcTypes.Route, error) ListRoutes(ctx context.Context, sandboxID string) ([]*vcTypes.Route, error) diff --git a/virtcontainers/pkg/vcmock/mock.go b/virtcontainers/pkg/vcmock/mock.go index aa9bae9a..d3bf201f 100644 --- a/virtcontainers/pkg/vcmock/mock.go +++ b/virtcontainers/pkg/vcmock/mock.go @@ -273,6 +273,14 @@ func (m *VCMock) ListInterfaces(ctx context.Context, sandboxID string) ([]*vcTyp return nil, fmt.Errorf("%s: %s (%+v): sandboxID: %v", mockErrorPrefix, getSelf(), m, sandboxID) } +// UpdateInterface implements the VC function of the same name +func (m *VCMock) UpdateInterface(ctx context.Context, sandboxID string, inf *vcTypes.Interface) (*vcTypes.Interface, error) { + if m.UpdateRoutesFunc != nil { + return m.UpdateInterfaceFunc(ctx, sandboxID, inf) + } + return nil, fmt.Errorf("%s: %s (%+v): sandboxID: %v", mockErrorPrefix, getSelf(), m, sandboxID) +} + // UpdateRoutes implements the VC function of the same name. func (m *VCMock) UpdateRoutes(ctx context.Context, sandboxID string, routes []*vcTypes.Route, op vcTypes.NetworkOp) ([]*vcTypes.Route, error) { if m.UpdateRoutesFunc != nil { diff --git a/virtcontainers/pkg/vcmock/types.go b/virtcontainers/pkg/vcmock/types.go index 610b4602..152e66b7 100644 --- a/virtcontainers/pkg/vcmock/types.go +++ b/virtcontainers/pkg/vcmock/types.go @@ -73,6 +73,7 @@ type VCMock struct { AddInterfaceFunc func(ctx context.Context, sandboxID string, inf *vcTypes.Interface) (*vcTypes.Interface, error) RemoveInterfaceFunc func(ctx context.Context, sandboxID string, inf *vcTypes.Interface) (*vcTypes.Interface, error) ListInterfacesFunc func(ctx context.Context, sandboxID string) ([]*vcTypes.Interface, error) + UpdateInterfaceFunc func(ctx context.Context, sandboxID string, inf *vcTypes.Interface) (*vcTypes.Interface, error) UpdateRoutesFunc func(ctx context.Context, sandboxID string, routes []*vcTypes.Route) ([]*vcTypes.Route, error) ListRoutesFunc func(ctx context.Context, sandboxID string) ([]*vcTypes.Route, error) CleanupContainerFunc func(ctx context.Context, sandboxID, containerID string, force bool) error diff --git a/virtcontainers/sandbox.go b/virtcontainers/sandbox.go index d8ab6c1a..174e6cb6 100644 --- a/virtcontainers/sandbox.go +++ b/virtcontainers/sandbox.go @@ -1031,6 +1031,54 @@ func (s *Sandbox) RemoveInterface(inf *vcTypes.Interface) (*vcTypes.Interface, e return nil, nil } +// UpdateInterface updates the nic. +func (s *Sandbox) UpdateInterface(inf *vcTypes.Interface) (*vcTypes.Interface, error) { + err := checkUpdateInterfaceInfo(inf) + if err != nil { + return nil, err + } + + nicInGuest := false + + endpoint := s.getEndpointByName(inf.Name) + // nic is not in local endpoints + if endpoint == nil { + interfaceInGuestInf := s.getInterfaceInfByName(inf.Name) + if interfaceInGuestInf == nil { + return nil, fmt.Errorf("can not find the network interface") + } + + nicInGuest = true + endpoint, err = s.generateEndpointForStore(interfaceInGuestInf) + if err != nil { + return nil, err + } + } + + // update endpoint ip + err = s.updateEndpointIP(endpoint, inf) + if err != nil { + return nil, err + } + + s.Logger().WithField("endpoint-type", endpoint.Type()).Info("Update endpoint") + grpcIf, err := s.agent.updateInterface(inf) + if err != nil { + return nil, err + } + + if nicInGuest { + s.networkNS.Endpoints = append(s.networkNS.Endpoints, endpoint) + } + + if err = s.Save(); err != nil { + s.Logger().WithError(err).Error("failed to store the network information") + return nil, err + } + + return grpcIf, nil +} + // ListInterfaces lists all nics and their configurations in the sandbox. func (s *Sandbox) ListInterfaces() ([]*vcTypes.Interface, error) { return s.agent.listInterfaces() @@ -2431,6 +2479,95 @@ func (s *Sandbox) IsCompatOldCNI() bool { return s.config.NetworkConfig.EnableCompatOldCNI } +func checkUpdateInterfaceInfo(inf *vcTypes.Interface) error { + if inf.Mtu > 0 || inf.Queues > 0 || inf.Device != "" || inf.VhostUserSocket != "" || inf.LinkType != "" || inf.HwAddr != "" { + return fmt.Errorf("device,mtu,hwAddr,linkType,queues and vhostUserSocket should be 0 or empty") + } + + return nil +} + +// getEndpointByName returns the endpoint by name. +func (s *Sandbox) getEndpointByName(name string) Endpoint { + if name == "" { + return nil + } + + for i, endpoint := range s.networkNS.Endpoints { + if endpoint.Name() == name { + return s.networkNS.Endpoints[i] + } + } + + return nil +} + +// getInterfaceInfByName returns the interface information. +func (s *Sandbox) getInterfaceInfByName(name string) *vcTypes.Interface { + if name == "" { + return nil + } + + nics, err := s.agent.listInterfaces() + if err != nil { + return nil + } + + for _, i := range nics { + if i.Name == name { + return i + } + } + + return nil +} + +// generateEndpointForStore only generates endpoint information for store,it does not create a endpoint +func (s *Sandbox) generateEndpointForStore(inf *vcTypes.Interface) (*TapEndpoint, error) { + netInfo, err := s.generateNetInfo(inf) + if err != nil { + return nil, err + } + + endpoint := &TapEndpoint{ + TapInterface: TapInterface{ + Name: inf.Name, + TAPIface: NetworkInterface{ + HardAddr: inf.HwAddr, + }, + }, + EndpointType: TapEndpointType, + } + + endpoint.SetProperties(netInfo) + + return endpoint, nil +} + +func (s *Sandbox) updateEndpointIP(endpoint Endpoint, inf *vcTypes.Interface) error { + if endpoint == nil { + return fmt.Errorf("endpoint is nil") + } + + netInfo := endpoint.Properties() + + var addrs []netlink.Addr + for _, addr := range inf.IPAddresses { + netlinkAddrStr := fmt.Sprintf("%s/%s", addr.Address, addr.Mask) + netlinkAddr, err := netlink.ParseAddr(netlinkAddrStr) + if err != nil { + return fmt.Errorf("could not parse %q: %v", netlinkAddrStr, err) + } + + addrs = append(addrs, *netlinkAddr) + } + + netInfo.Addrs = addrs + endpoint.SetProperties(netInfo) + + return nil +} + // updateStaticSandboxResources update sandbox's cpu and memory resource passed by // sandbox_cpu and sandbox_mem annotations func updateStaticSandboxResources(sandboxConfig *SandboxConfig) error { -- 2.14.3 (Apple Git-98)