Skip to content

Commit 803859f

Browse files
committed
optimize vm migrate
Signed-off-by: bobz965 <zhangbingbing2_yewu@cmss.chinamobile.com>
1 parent 8f8e596 commit 803859f

File tree

5 files changed

+248
-3
lines changed

5 files changed

+248
-3
lines changed

mocks/pkg/ovs/interface.go

+56
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/controller/pod.go

+102-3
Original file line numberDiff line numberDiff line change
@@ -641,6 +641,16 @@ func (c *Controller) reconcileAllocateSubnets(cachedPod, pod *v1.Pod, needAlloca
641641
podName := c.getNameByPod(pod)
642642
// todo: isVmPod, getPodType, getNameByPod has duplicated logic
643643

644+
var err error
645+
var isMigrating bool
646+
var vmKey, srcNodeName, targetNodeName string
647+
if isVMPod && c.config.EnableKeepVMIP {
648+
vmKey = fmt.Sprintf("%s/%s", namespace, vmName)
649+
if isMigrating, srcNodeName, targetNodeName, err = c.migrateVM(pod, vmKey); err != nil {
650+
klog.Error(err)
651+
return nil, err
652+
}
653+
}
644654
// Avoid create lsp for already running pod in ovn-nb when controller restart
645655
for _, podNet := range needAllocatePodNets {
646656
// the subnet may changed when alloc static ip from the latter subnet after ns supports multi subnets
@@ -669,10 +679,11 @@ func (c *Controller) reconcileAllocateSubnets(cachedPod, pod *v1.Pod, needAlloca
669679
delete(pod.Annotations, fmt.Sprintf(util.PodNicAnnotationTemplate, podNet.ProviderName))
670680
}
671681
pod.Annotations[fmt.Sprintf(util.AllocatedAnnotationTemplate, podNet.ProviderName)] = "true"
672-
if isVMPod && c.config.EnableKeepVMIP {
682+
683+
if vmKey != "" {
673684
pod.Annotations[fmt.Sprintf(util.VMTemplate, podNet.ProviderName)] = vmName
674685
if err := c.changeVMSubnet(vmName, namespace, podNet.ProviderName, subnet.Name); err != nil {
675-
klog.Errorf("change subnet of pod %s/%s to %s failed: %v", namespace, name, subnet.Name, err)
686+
klog.Errorf("vm %s change subnet to %s failed: %v", vmKey, subnet.Name, err)
676687
return nil, err
677688
}
678689
}
@@ -720,12 +731,31 @@ func (c *Controller) reconcileAllocateSubnets(cachedPod, pod *v1.Pod, needAlloca
720731
DHCPv6OptionsUUID: subnet.Status.DHCPv6OptionsUUID,
721732
}
722733

723-
if err := c.OVNNbClient.CreateLogicalSwitchPort(subnet.Name, portName, ipStr, mac, podName, pod.Namespace, portSecurity, securityGroupAnnotation, vips, podNet.Subnet.Spec.EnableDHCP, dhcpOptions, subnet.Spec.Vpc); err != nil {
734+
if err := c.OVNNbClient.CreateLogicalSwitchPort(subnet.Name, portName, ipStr, mac, podName, pod.Namespace,
735+
portSecurity, securityGroupAnnotation, vips, podNet.Subnet.Spec.EnableDHCP, dhcpOptions, subnet.Spec.Vpc); err != nil {
724736
c.recorder.Eventf(pod, v1.EventTypeWarning, "CreateOVNPortFailed", err.Error())
725737
klog.Errorf("%v", err)
726738
return nil, err
727739
}
728740

741+
if vmKey != "" {
742+
if isMigrating {
743+
if err = c.setVMLSPMigrationOptions(portName, srcNodeName, targetNodeName); err != nil {
744+
klog.Error(err)
745+
return nil, err
746+
}
747+
pod.Annotations[util.OVNMigrationAnnotation] = "true"
748+
} else {
749+
if migrate, ok := pod.Annotations[util.OVNMigrationAnnotation]; ok && migrate == "true" {
750+
if err = c.cleanVMLSPMigrationOptions(portName); err != nil {
751+
klog.Error(err)
752+
return nil, err
753+
}
754+
pod.Annotations[util.OVNMigratedAnnotation] = "true"
755+
}
756+
}
757+
}
758+
729759
if pod.Annotations[fmt.Sprintf(util.Layer2ForwardAnnotationTemplate, podNet.ProviderName)] == "true" {
730760
if err := c.OVNNbClient.EnablePortLayer2forward(portName); err != nil {
731761
c.recorder.Eventf(pod, v1.EventTypeWarning, "SetOVNPortL2ForwardFailed", err.Error())
@@ -2089,3 +2119,72 @@ func (c *Controller) getVirtualIPs(pod *v1.Pod, podNets []*kubeovnNet) map[strin
20892119
}
20902120
return vipsMap
20912121
}
2122+
2123+
// migrate vm return migrate, src node, target node, err
2124+
func (c *Controller) migrateVM(pod *v1.Pod, vmKey string) (bool, string, string, error) {
2125+
if migrated, ok := pod.Annotations[util.OVNMigratedAnnotation]; ok && migrated == "true" {
2126+
klog.Infof("vm %s is migrated", vmKey)
2127+
return false, "", "", nil
2128+
}
2129+
2130+
migratePhase, ok := pod.Annotations[util.MigrationPhaseAnnotation]
2131+
if !ok {
2132+
// not migrate vm
2133+
return false, "", "", nil
2134+
}
2135+
// check migrate phase
2136+
if migratePhase == "" {
2137+
err := fmt.Errorf("vm %s migration phase is empty", vmKey)
2138+
klog.Error(err)
2139+
return false, "", "", err
2140+
}
2141+
if migratePhase == util.MigrationStateSucceeded {
2142+
klog.Infof("vm %s migration is succeeded", vmKey)
2143+
return false, "", "", nil
2144+
}
2145+
if migratePhase == util.MigrationStateFailed {
2146+
klog.Warningf("vm %s migration is failed", vmKey)
2147+
return false, "", "", nil
2148+
}
2149+
if migratePhase == util.MigrationStateStarted {
2150+
if isTarget, ok := pod.Annotations[util.MigrationTargetAnnotation]; ok && isTarget == "true" {
2151+
klog.Infof("start to migrate target vm %s", vmKey)
2152+
// this pod is target vm pod
2153+
srcNode, ok := pod.Annotations[util.MigrationSourceNodeAnnotation]
2154+
if !ok || srcNode == "" {
2155+
err := fmt.Errorf("vm %s migration source node is not set", vmKey)
2156+
klog.Error(err)
2157+
return false, "", "", err
2158+
}
2159+
targetNode := pod.Spec.NodeName
2160+
if targetNode == "" {
2161+
err := fmt.Errorf("vm %s migration target node is not set", vmKey)
2162+
klog.Error(err)
2163+
return false, "", "", err
2164+
}
2165+
return true, srcNode, targetNode, nil
2166+
}
2167+
klog.Infof("start to migrate src vm %s", vmKey)
2168+
}
2169+
return false, "", "", nil
2170+
}
2171+
2172+
func (c *Controller) setVMLSPMigrationOptions(portName, srcNodeName, targetNodeName string) error {
2173+
klog.Infof("set migrate options for lsp %s", portName)
2174+
if err := c.OVNNbClient.SetLogicalSwitchPortMigrateOptions(portName, srcNodeName, targetNodeName); err != nil {
2175+
err = fmt.Errorf("failed to set migrate options for lsp %s, %v", portName, err)
2176+
klog.Error(err)
2177+
return err
2178+
}
2179+
return nil
2180+
}
2181+
2182+
func (c *Controller) cleanVMLSPMigrationOptions(portName string) error {
2183+
klog.Infof("clean migrate options for lsp %s", portName)
2184+
if err := c.OVNNbClient.CleanLogicalSwitchPortMigrateOptions(portName); err != nil {
2185+
err = fmt.Errorf("failed to clean migrate options for lsp %s, %v", portName, err)
2186+
klog.Error(err)
2187+
return err
2188+
}
2189+
return nil
2190+
}

pkg/ovs/interface.go

+3
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,9 @@ type LogicalSwitchPort interface {
9191
ListLogicalSwitchPortsWithLegacyExternalIDs() ([]ovnnb.LogicalSwitchPort, error)
9292
GetLogicalSwitchPort(lspName string, ignoreNotFound bool) (*ovnnb.LogicalSwitchPort, error)
9393
LogicalSwitchPortExists(name string) (bool, error)
94+
// vm live migrate
95+
SetLogicalSwitchPortMigrateOptions(lspName, srcNodeName, targetNodeName string) error
96+
CleanLogicalSwitchPortMigrateOptions(lspName string) error
9497
}
9598

9699
type LoadBalancer interface {

pkg/ovs/ovn-nb-logical_switch_port.go

+82
Original file line numberDiff line numberDiff line change
@@ -795,3 +795,85 @@ func getLogicalSwitchPortSgs(lsp *ovnnb.LogicalSwitchPort) *strset.Set {
795795

796796
return sgs
797797
}
798+
799+
// SetLogicalSwitchPortMigrateOptions set logical switch port options of migrate
800+
func (c *OVNNbClient) SetLogicalSwitchPortMigrateOptions(lspName, srcNodeName, targetNodeName string) error {
801+
// to facilitate the migration of the VM: ovn-nbctl lsp-set-options migrator requested-chassis=src,target activation-strategy=rarp
802+
// the options will be removed after the migration is completed
803+
if srcNodeName == targetNodeName {
804+
err := fmt.Errorf("src and target node can not be the same on migrator port %s", lspName)
805+
klog.Error(err)
806+
return err
807+
}
808+
if srcNodeName == "" || targetNodeName == "" {
809+
err := fmt.Errorf("src and target node can not be empty on migrator port %s", lspName)
810+
klog.Error(err)
811+
return err
812+
}
813+
814+
lsp, src, target, err := c.GetLogicalSwitchPortMigrateOptions(lspName)
815+
if err != nil {
816+
klog.Error(err)
817+
return err
818+
}
819+
if src == srcNodeName && target == targetNodeName {
820+
// already set
821+
return nil
822+
}
823+
824+
requestedChassis := fmt.Sprintf("%s,%s", srcNodeName, targetNodeName)
825+
klog.Infof("set logical switch port %s options requested-chassis=%s", lspName, requestedChassis)
826+
if lsp.Options == nil {
827+
lsp.Options = make(map[string]string)
828+
}
829+
lsp.Options["requested-chassis"] = requestedChassis
830+
lsp.Options["activation-strategy"] = "rarp"
831+
if err := c.UpdateLogicalSwitchPort(lsp, &lsp.Options); err != nil {
832+
err = fmt.Errorf("failed to set logical switch port %s options requested chassis %s: %v", lspName, requestedChassis, err)
833+
klog.Error(err)
834+
return err
835+
}
836+
return nil
837+
}
838+
839+
// GetLogicalSwitchPortMigrateOptions get logical switch port src and target node name options of migrate
840+
func (c *OVNNbClient) GetLogicalSwitchPortMigrateOptions(lspName string) (*ovnnb.LogicalSwitchPort, string, string, error) {
841+
lsp, err := c.GetLogicalSwitchPort(lspName, true)
842+
if err != nil {
843+
err = fmt.Errorf("failed to get logical switch port %s: %v", lspName, err)
844+
klog.Error(err)
845+
return nil, "", "", err
846+
}
847+
if lsp == nil || lsp.Options == nil {
848+
return nil, "", "", nil
849+
}
850+
851+
requestedChassis, ok := lsp.Options["requested-chassis"]
852+
if ok {
853+
splits := strings.Split(requestedChassis, ",")
854+
if len(splits) == 2 {
855+
return lsp, splits[0], splits[1], nil
856+
}
857+
}
858+
return nil, "", "", nil
859+
}
860+
861+
// CleanLogicalSwitchPortMigrateOptions clean logical switch port options of migration
862+
func (c *OVNNbClient) CleanLogicalSwitchPortMigrateOptions(lspName string) error {
863+
lsp, src, target, err := c.GetLogicalSwitchPortMigrateOptions(lspName)
864+
if err != nil {
865+
klog.Error(err)
866+
return err
867+
}
868+
if src != "" && target != "" {
869+
lsp.Options = make(map[string]string)
870+
lsp.Options["requested-chassis"] = target
871+
klog.Infof("clean logical switch port %s options", lspName)
872+
if err := c.UpdateLogicalSwitchPort(lsp, &lsp.Options); err != nil {
873+
err = fmt.Errorf("failed to clean options for logical switch port %s : %v", lspName, err)
874+
klog.Error(err)
875+
return err
876+
}
877+
}
878+
return nil
879+
}

pkg/util/const.go

+5
Original file line numberDiff line numberDiff line change
@@ -292,8 +292,13 @@ const (
292292
ConsumptionKubevirt = "kubevirt"
293293
VhostUserSocketVolumeName = "vhostuser-sockets"
294294

295+
OVNMigrationAnnotation = "ovn.kubernetes.io/migrate" // to control if ovn set lsp migrate options
296+
OVNMigratedAnnotation = "ovn.kubernetes.io/migrated" // to control if ovn clean lsp migrate options
295297
MigrationSourceNodeAnnotation = "kubevirt.io/migration-source-node" // target pod has source node name
296298
MigrationSourceAnnotation = "kubevirt.io/migration-source" // migration source vm: true or false
297299
MigrationTargetAnnotation = "kubevirt.io/migration-target" // migration target vm: true or false
298300
MigrationPhaseAnnotation = "kubevirt.io/migration-phase" // migration vm phase: started/succeeded/failed
301+
MigrationStateStarted = "started"
302+
MigrationStateSucceeded = "succeeded"
303+
MigrationStateFailed = "failed"
299304
)

0 commit comments

Comments
 (0)