mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-04-29 12:14:48 +00:00
runtime: run prestart hooks before starting VM for FC
Add a new hypervisor capability to tell if it supports device hotplug. If not, we should run prestart hooks before starting new VMs as nerdctl is using the prestart hooks to set up netns. To make nerdctl + FC to work, we need to run the prestart hooks before starting new VMs. Fixes: #6384 Signed-off-by: Peng Tao <bergwolf@hyper.sh>
This commit is contained in:
parent
b8990c0490
commit
32fd013716
@ -366,6 +366,7 @@ func (a *acrnArchBase) capabilities(config HypervisorConfig) types.Capabilities
|
|||||||
|
|
||||||
caps.SetBlockDeviceSupport()
|
caps.SetBlockDeviceSupport()
|
||||||
caps.SetBlockDeviceHotplugSupport()
|
caps.SetBlockDeviceHotplugSupport()
|
||||||
|
caps.SetNetworkDeviceHotplugSupported()
|
||||||
|
|
||||||
return caps
|
return caps
|
||||||
}
|
}
|
||||||
|
@ -89,6 +89,7 @@ func TestAcrnArchBaseCapabilities(t *testing.T) {
|
|||||||
assert.True(c.IsBlockDeviceSupported())
|
assert.True(c.IsBlockDeviceSupported())
|
||||||
assert.True(c.IsBlockDeviceHotplugSupported())
|
assert.True(c.IsBlockDeviceHotplugSupported())
|
||||||
assert.False(c.IsFsSharingSupported())
|
assert.False(c.IsFsSharingSupported())
|
||||||
|
assert.True(c.IsNetworkDeviceHotplugSupported())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAcrnArchBaseMemoryTopology(t *testing.T) {
|
func TestAcrnArchBaseMemoryTopology(t *testing.T) {
|
||||||
|
@ -82,6 +82,7 @@ func TestAcrnCapabilities(t *testing.T) {
|
|||||||
caps := a.Capabilities(a.ctx)
|
caps := a.Capabilities(a.ctx)
|
||||||
assert.True(caps.IsBlockDeviceSupported())
|
assert.True(caps.IsBlockDeviceSupported())
|
||||||
assert.True(caps.IsBlockDeviceHotplugSupported())
|
assert.True(caps.IsBlockDeviceHotplugSupported())
|
||||||
|
assert.True(caps.IsNetworkDeviceHotplugSupported())
|
||||||
}
|
}
|
||||||
|
|
||||||
func testAcrnAddDevice(t *testing.T, devInfo interface{}, devType DeviceType, expected []Device) {
|
func testAcrnAddDevice(t *testing.T, devInfo interface{}, devType DeviceType, expected []Device) {
|
||||||
|
@ -1210,6 +1210,7 @@ func (clh *cloudHypervisor) Capabilities(ctx context.Context) types.Capabilities
|
|||||||
caps.SetFsSharingSupport()
|
caps.SetFsSharingSupport()
|
||||||
}
|
}
|
||||||
caps.SetBlockDeviceHotplugSupport()
|
caps.SetBlockDeviceHotplugSupport()
|
||||||
|
caps.SetNetworkDeviceHotplugSupported()
|
||||||
return caps
|
return caps
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -752,4 +752,7 @@ func TestClhCapabilities(t *testing.T) {
|
|||||||
|
|
||||||
c = clh.Capabilities(ctx)
|
c = clh.Capabilities(ctx)
|
||||||
assert.False(c.IsFsSharingSupported())
|
assert.False(c.IsFsSharingSupported())
|
||||||
|
|
||||||
|
assert.True(c.IsNetworkDeviceHotplugSupported())
|
||||||
|
assert.True(c.IsBlockDeviceHotplugSupported())
|
||||||
}
|
}
|
||||||
|
@ -162,6 +162,7 @@ func (q *qemuAmd64) capabilities(hConfig HypervisorConfig) types.Capabilities {
|
|||||||
if q.qemuMachine.Type == QemuQ35 ||
|
if q.qemuMachine.Type == QemuQ35 ||
|
||||||
q.qemuMachine.Type == QemuVirt {
|
q.qemuMachine.Type == QemuVirt {
|
||||||
caps.SetBlockDeviceHotplugSupport()
|
caps.SetBlockDeviceHotplugSupport()
|
||||||
|
caps.SetNetworkDeviceHotplugSupported()
|
||||||
}
|
}
|
||||||
|
|
||||||
caps.SetMultiQueueSupport()
|
caps.SetMultiQueueSupport()
|
||||||
|
@ -47,10 +47,12 @@ func TestQemuAmd64Capabilities(t *testing.T) {
|
|||||||
amd64 := newTestQemu(assert, QemuQ35)
|
amd64 := newTestQemu(assert, QemuQ35)
|
||||||
caps := amd64.capabilities(config)
|
caps := amd64.capabilities(config)
|
||||||
assert.True(caps.IsBlockDeviceHotplugSupported())
|
assert.True(caps.IsBlockDeviceHotplugSupported())
|
||||||
|
assert.True(caps.IsNetworkDeviceHotplugSupported())
|
||||||
|
|
||||||
amd64 = newTestQemu(assert, QemuMicrovm)
|
amd64 = newTestQemu(assert, QemuMicrovm)
|
||||||
caps = amd64.capabilities(config)
|
caps = amd64.capabilities(config)
|
||||||
assert.False(caps.IsBlockDeviceHotplugSupported())
|
assert.False(caps.IsBlockDeviceHotplugSupported())
|
||||||
|
assert.False(caps.IsNetworkDeviceHotplugSupported())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestQemuAmd64Bridges(t *testing.T) {
|
func TestQemuAmd64Bridges(t *testing.T) {
|
||||||
|
@ -300,6 +300,7 @@ func (q *qemuArchBase) capabilities(hConfig HypervisorConfig) types.Capabilities
|
|||||||
var caps types.Capabilities
|
var caps types.Capabilities
|
||||||
caps.SetBlockDeviceHotplugSupport()
|
caps.SetBlockDeviceHotplugSupport()
|
||||||
caps.SetMultiQueueSupport()
|
caps.SetMultiQueueSupport()
|
||||||
|
caps.SetNetworkDeviceHotplugSupported()
|
||||||
if hConfig.SharedFS != config.NoSharedFS {
|
if hConfig.SharedFS != config.NoSharedFS {
|
||||||
caps.SetFsSharingSupport()
|
caps.SetFsSharingSupport()
|
||||||
}
|
}
|
||||||
|
@ -123,6 +123,7 @@ func TestQemuArchBaseCapabilities(t *testing.T) {
|
|||||||
c := qemuArchBase.capabilities(hConfig)
|
c := qemuArchBase.capabilities(hConfig)
|
||||||
assert.True(c.IsBlockDeviceHotplugSupported())
|
assert.True(c.IsBlockDeviceHotplugSupported())
|
||||||
assert.True(c.IsFsSharingSupported())
|
assert.True(c.IsFsSharingSupported())
|
||||||
|
assert.True(c.IsNetworkDeviceHotplugSupported())
|
||||||
|
|
||||||
hConfig.SharedFS = config.NoSharedFS
|
hConfig.SharedFS = config.NoSharedFS
|
||||||
c = qemuArchBase.capabilities(hConfig)
|
c = qemuArchBase.capabilities(hConfig)
|
||||||
|
@ -104,6 +104,7 @@ func (q *qemuPPC64le) capabilities(hConfig HypervisorConfig) types.Capabilities
|
|||||||
// pseries machine type supports hotplugging drives
|
// pseries machine type supports hotplugging drives
|
||||||
if q.qemuMachine.Type == QemuPseries {
|
if q.qemuMachine.Type == QemuPseries {
|
||||||
caps.SetBlockDeviceHotplugSupport()
|
caps.SetBlockDeviceHotplugSupport()
|
||||||
|
caps.SetNetworkDeviceHotplugSupported()
|
||||||
}
|
}
|
||||||
|
|
||||||
caps.SetMultiQueueSupport()
|
caps.SetMultiQueueSupport()
|
||||||
|
@ -475,6 +475,7 @@ func TestQemuCapabilities(t *testing.T) {
|
|||||||
|
|
||||||
caps := q.Capabilities(q.ctx)
|
caps := q.Capabilities(q.ctx)
|
||||||
assert.True(caps.IsBlockDeviceHotplugSupported())
|
assert.True(caps.IsBlockDeviceHotplugSupported())
|
||||||
|
assert.True(caps.IsNetworkDeviceHotplugSupported())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestQemuQemuPath(t *testing.T) {
|
func TestQemuQemuPath(t *testing.T) {
|
||||||
|
@ -1310,6 +1310,23 @@ func (s *Sandbox) cleanSwap(ctx context.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Sandbox) runPrestartHooks(ctx context.Context, prestartHookFunc func(context.Context) error) error {
|
||||||
|
hid, err := s.GetHypervisorPid()
|
||||||
|
if err != nil {
|
||||||
|
s.Logger().Errorf("fail to get hypervisor pid for sandbox %s", s.id)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
s.Logger().Infof("sandbox %s hypervisor pid is %v", s.id, hid)
|
||||||
|
ctx = context.WithValue(ctx, HypervisorPidKey{}, hid)
|
||||||
|
|
||||||
|
if err := prestartHookFunc(ctx); err != nil {
|
||||||
|
s.Logger().Errorf("fail to run prestartHook for sandbox %s: %s", s.id, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// startVM starts the VM.
|
// startVM starts the VM.
|
||||||
func (s *Sandbox) startVM(ctx context.Context, prestartHookFunc func(context.Context) error) (err error) {
|
func (s *Sandbox) startVM(ctx context.Context, prestartHookFunc func(context.Context) error) (err error) {
|
||||||
span, ctx := katatrace.Trace(ctx, s.Logger(), "startVM", sandboxTracingTags, map[string]string{"sandbox_id": s.id})
|
span, ctx := katatrace.Trace(ctx, s.Logger(), "startVM", sandboxTracingTags, map[string]string{"sandbox_id": s.id})
|
||||||
@ -1332,6 +1349,17 @@ func (s *Sandbox) startVM(ctx context.Context, prestartHookFunc func(context.Con
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
caps := s.hypervisor.Capabilities(ctx)
|
||||||
|
// If the hypervisor does not support device hotplug, run prestart hooks
|
||||||
|
// before spawning the VM so that it is possible to let the hooks set up
|
||||||
|
// netns and thus network devices are set up statically.
|
||||||
|
if !caps.IsNetworkDeviceHotplugSupported() && prestartHookFunc != nil {
|
||||||
|
err = s.runPrestartHooks(ctx, prestartHookFunc)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if err := s.network.Run(ctx, func() error {
|
if err := s.network.Run(ctx, func() error {
|
||||||
if s.factory != nil {
|
if s.factory != nil {
|
||||||
vm, err := s.factory.GetVM(ctx, VMConfig{
|
vm, err := s.factory.GetVM(ctx, VMConfig{
|
||||||
@ -1351,24 +1379,22 @@ func (s *Sandbox) startVM(ctx context.Context, prestartHookFunc func(context.Con
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if prestartHookFunc != nil {
|
if caps.IsNetworkDeviceHotplugSupported() && prestartHookFunc != nil {
|
||||||
hid, err := s.GetHypervisorPid()
|
err = s.runPrestartHooks(ctx, prestartHookFunc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
s.Logger().Infof("hypervisor pid is %v", hid)
|
|
||||||
ctx = context.WithValue(ctx, HypervisorPidKey{}, hid)
|
|
||||||
|
|
||||||
if err := prestartHookFunc(ctx); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1. Do not scan the netns if we want no network for the vmm.
|
// 1. Do not scan the netns if we want no network for the vmm
|
||||||
// 2. In case of vm factory, scan the netns to hotplug interfaces after vm is started.
|
// 2. Do not scan the netns if the vmm does not support device hotplug, in which case
|
||||||
// 3. In case of prestartHookFunc, network config might have been changed. We need to
|
// the network is already set up statically
|
||||||
|
// 3. In case of vm factory, scan the netns to hotplug interfaces after vm is started.
|
||||||
|
// 4. In case of prestartHookFunc, network config might have been changed. We need to
|
||||||
// rescan and handle the change.
|
// rescan and handle the change.
|
||||||
if !s.config.NetworkConfig.DisableNewNetwork && (s.factory != nil || prestartHookFunc != nil) {
|
if !s.config.NetworkConfig.DisableNewNetwork &&
|
||||||
|
caps.IsNetworkDeviceHotplugSupported() &&
|
||||||
|
(s.factory != nil || prestartHookFunc != nil) {
|
||||||
if _, err := s.network.AddEndpoints(ctx, s, nil, true); err != nil {
|
if _, err := s.network.AddEndpoints(ctx, s, nil, true); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ const (
|
|||||||
blockDeviceHotplugSupport
|
blockDeviceHotplugSupport
|
||||||
multiQueueSupport
|
multiQueueSupport
|
||||||
fsSharingSupported
|
fsSharingSupported
|
||||||
|
networkDeviceHotplugSupport
|
||||||
)
|
)
|
||||||
|
|
||||||
// Capabilities describe a virtcontainers hypervisor capabilities
|
// Capabilities describe a virtcontainers hypervisor capabilities
|
||||||
@ -57,3 +58,13 @@ func (caps *Capabilities) IsFsSharingSupported() bool {
|
|||||||
func (caps *Capabilities) SetFsSharingSupport() {
|
func (caps *Capabilities) SetFsSharingSupport() {
|
||||||
caps.flags |= fsSharingSupported
|
caps.flags |= fsSharingSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsDeviceHotplugSupported tells if an hypervisor supports device hotplug.
|
||||||
|
func (caps *Capabilities) IsNetworkDeviceHotplugSupported() bool {
|
||||||
|
return caps.flags&networkDeviceHotplugSupport != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetDeviceHotplugSupported sets the host filesystem sharing capability to true.
|
||||||
|
func (caps *Capabilities) SetNetworkDeviceHotplugSupported() {
|
||||||
|
caps.flags |= networkDeviceHotplugSupport
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user