Homelab - Kubernetes & GitOps - VCF - VCF Automation

VMware Cloud Foundation 9.1: Migrating a Running VM into vSphere Supervisor Without Reboot

Introduction

Can we take a running virtual machine from a classic NSX segment, hand it over to vSphere Supervisor and VM Service, and do it without changing its IP address or shutting it down?

That was the question I wanted to answer in my VCF 9.1 lab.

The answer is yes, but it is not a single wizard. Getting from “a VM on an old Tier-1 segment” to “a VM Operator object in a Namespace, routed through a VPC and Transit Gateway” requires careful work on the provider side, the tenant side, the NSX Edge, and the Mobility Operator.

In this article, we will build the whole procedure step by step. We will prepare an External IP Block and a Public VPC subnet with exactly the same CIDR as the source segment, temporarily stretch L2 with an NSX Edge Bridge, import the VM with Mobility Operator in preserve mode, and finally move L3 routing from the source Tier-1 to the Transit Gateway in a controlled cutover.

This is written as a validated, click-by-click proof of concept. I will show not only what to configure, but also why each step matters and what to verify before moving on.

What makes this lab interesting?

The VM keeps its IP, its MAC, its default gateway and its uptime. During the whole migration a continuous ping is running, and the only visible interruption is a short gap during the routing cutover.

The Lab Configuration

Before copying values from the steps below, here is the complete working configuration, so that the names used later make sense.

ComponentWorking lab value
PlatformVCF 9.1.x / NSX / VCF Automation / vSphere Supervisor
Source Tier-1vworld-t1-gw01
Tier-0vworld-t0-gw01
Source segmentvcf-migration-test-public
Migration CIDR192.168.107.0/24
Default gateway192.168.107.1
VMtest-0006 / vm-4039
VM IP / MAC192.168.107.20 / 00:50:56:9c:6e:cc
Organization / NSX Projecttest-org-auto / a85bcc0c-ad2f-45bb-9593-b7640713f0dc
Transit Gatewaymigration-poc-tgw
Connectivity Profilemigration-poc-tgw-cp-5gn8
External Connectiontest-centralized-connection
External IP Blockmigration-poc-public-107-block (192.168.107.0/24)
Target VPCvpc-migration-poc-public-107
Target subnetsubnet-c5mk (Public, 192.168.107.0/24)
Namespacemigration-poc-public-107-ns-2c7tm
Edge cluster/nodesvworld-edge-cl01 / vcf-edge-01, vcf-edge-02
Bridge Profilemigration-poc-bridge-profile
Bridge VLAN TZmigration-bridge-vlan-tz
Parent segmentmigration-parent-seg
Bridge VLAN102

Do not treat these values as universal.

These are the names and addresses from my lab. What is reusable is the architecture, the order of operations and the dependency chain.

Prerequisites

I assume that the basic platform already exists. Before we begin, verify that you have:

  • a healthy VCF 9.1 deployment with VCF Automation,
  • a vSphere Supervisor enabled with NSX VPC networking,
  • an operational NSX Edge Cluster and Provider Tier-0,
  • a Centralized External Connection and a Transit Gateway used by the organization,
  • Mobility Operator available in the Supervisor,
  • an external host from which you can run a continuous ping to the VM.

If all of those are in place, we can start.

Part 1 – Understand the Design Before Opening Any Wizard

If this is your first migration of this kind, it helps to understand the moving parts first. The procedure has four phases:

  1. Prepare the target – a Public VPC subnet with exactly the same CIDR as the source segment, with VPC Gateway Connectivity switched off.
  2. Stretch L2 – an NSX Edge Bridge connects the target subnet and the source segment into one broadcast domain.
  3. Import the VM – Mobility Operator changes the network backing and hands the VM over to VM Service in preserve mode.
  4. Move L3 – routing for the prefix is transferred from the source Tier-1 to the Transit Gateway and the External Connection.

The VCF Automation objects involved form a clear hierarchy:

VCF Automation Organization (test-org-auto)
 |
 v
Project (default-project / NSX Project UUID)
 |
 v
Namespace (VM Service boundary)
 |
 v
Dedicated VPC  <-- VPC Subnet (Private / Private_TGW / Public / L2_Only)
 |                       ^
 v                       |
Connectivity Profile --- IP Blocks (External / Private-VPC / Private-TGW)
 |
 v
Transit Gateway
 |
 v
External Connection (provider / Tier-0 side)

Public does not mean “Internet” here.

In this design, Public is the address-scope classification of a subnet backed by an External IP Block. That is what allows the existing Centralized External Connection to advertise the prefix towards Tier-0 as a TGW route.

The components you will touch

ComponentRole in the migration
Source Tier-1Owns gateway 192.168.107.1/24 before migration. During cutover we suppress only the migrated prefix.
Tier-0Our routing observation point: the prefix is t1c before cutover and tgws after.
Centralized External ConnectionNorthbound path from the TGW to Tier-0. It advertises External IP Blocks, so allow_private is not needed.
Transit GatewayConnects the VPC to the External Connection. The Public subnet enters TGW routing once Gateway Connectivity is on.
Connectivity ProfileTies Region, TGW and IP blocks together. Without the block here, the tenant cannot select it for a Public subnet.
External IP BlockMakes 192.168.107.0/24 a valid source for a Public subnet.
Public VPC subnetTarget network with the same CIDR; Gateway Connectivity stays off until cutover.
NamespaceMust share the subnet so it appears as a Subnet CR for the Mobility Operator.
Bridge Profile, VLAN TZ, parent segmentShared bridge infrastructure on the Edge; each migrated L2 domain gets a unique VLAN tag.
Mobility OperatorImportOperationBatch / ImportOperation: precheck, network backing change, relocation and commit.

How the traffic flows

This is the most important picture in the whole article:

BEFORE
VM 192.168.107.20 -> Source Segment -> T1 192.168.107.1 -> T0 -> upstream

DURING IMPORT
VM -> Target SubnetPort -> L2 Bridge (VLAN 102) -> Source Segment -> Source T1 gateway

AFTER CUTOVER
VM -> Public VPC Subnet -> TGW -> Centralized External Connection -> T0 -> upstream

The target subnet exists from the very beginning, but its gateway is disabled. This prevents two active gateways for the same IP.

The golden rule of this procedure

Build the bridge before the import and remove it only after the L3 cutover has been validated. During the import, the source Tier-1 still owns the gateway and routing.

Part 2 – Provider-Side Preparation

Step 1 – Check the Centralized External Connection

  1. Open Provider Management > Networking > External Connections / Centralized Connections.
  2. Select the connection the organization uses. In my lab, it was test-centralized-connection.
  3. Verify that it is healthy and connected to the Transit Gateway migration-poc-tgw.

Figure 1. The Centralized External Connection used by migration-poc-tgw.

Do not enable Advertise Private TGW.

The working design uses an External IP Block and a Public subnet. As you will see in the “What did not work” section, the Private-TGW path was blocked in my lab anyway.

Step 2 – Create an External IP Block for the Migrated Prefix

  1. Open Provider Management > Networking > External IP Blocks.
  2. Click NEW.
  3. Name: a unique name, for example migration-poc-public-107-block.
  4. Region: the organization region.
  5. CIDR: the exact source prefix, 192.168.107.0/24.
  6. Save.

Checkpoint: the block must show Status = Normal.

Step 3 – Associate the Block with the Centralized External Connection

  1. Open Provider Management > Networking > Centralized Connections.
  2. Open the connection the organization uses.
  3. Open IP Blocks.
  4. Under Associated External IP Blocks, click NEW.
  5. Select the new block and save.

Checkpoint: The block shows Status = Normal on the connection.

Step 4 – Assign the Block to the Organization

  1. Open Provider Management > Organizations and select the organization.
  2. Go to Networking > External IP Block.
  3. Assign the new block.
  4. Set the IP and CIDR quota. My lab needed exactly one /24 CIDR.
  5. If the tenant does not see the change, click SYNC on the organization Networking page.

Figure 2. The External IP Block assigned to the organization with enough quota for the /24.

Step 5 – Add the Block to the Connectivity Profile

This is one of the easiest steps to miss. The External Connection association and the organization quota are not enough. The Connectivity Profile must also list the block under External IPv4 blocks.

  1. As Tenant / Service Administrator, open Manage & Govern > Networking > Connectivity Profiles.
  2. Edit migration-poc-tgw-cp-5gn8.
  3. Transit gateway: migration-poc-tgw.
  4. External IPv4 blocks: add migration-poc-public-107-block.
  5. Private – TGW IPv4 blocks: leave unchanged.
  6. Save.

Figure 3. Connectivity Profile with the External IPv4 blocks. The screenshot comes from an earlier 192.168.106.0/24 test; in production, select the actual migrated block.

Why is this step critical?

If the block is not in the Connectivity Profile, it simply will not appear in the IP Block list when the tenant creates a Public subnet. Everything else looks correct, which makes this mistake hard to spot.

Part 3 – Build the Target VPC, Public Subnet and Namespace

Step 6 – Create the VPC

  1. Open Manage & Govern > VPCs > NEW VPC.
  2. Use the following values:
FieldValue
Namevpc-migration-poc-public-107
RegionThe same region as the Connectivity Profile
Connectivity profilemigration-poc-tgw-cp-5gn8
Private – VPC IPv4 CIDRsEmpty for this POC
  1. Click CREATE and wait for Success.

Figure 4. Create VPC.

Note that Public is not a VPC mode. You choose Public later, on the subnet.

Step 7 – Create the Public Subnet with Gateway Connectivity Off

  1. Open Manage & Govern > Subnets > NEW SUBNET.
  2. Configure:
FieldValue
Regiontest-region-auto
VPCvpc-migration-poc-public-107
Access ModePublic
IP Blockmigration-poc-public-107-block (do not use Any in production)
Auto-allocate from IP BlockOff, because we need the exact prefix
IP Address CIDR192.168.107.0/24
VPC Gateway ConnectivityNo / Off
Static IP AllocationYes
DHCPNone
  1. Click CREATE and wait for Success.

Figure 5. Public subnet with VPC Gateway Connectivity Off. The screenshot comes from an earlier 192.168.106.0/24 test; the settings are identical for 192.168.107.0/24.

Do not enable VPC Gateway Connectivity at this stage.

The source Tier-1 still owns 192.168.107.1. The target gateway is enabled only during the controlled L3 cutover in Part 6.

Step 8 – Create the Namespace and Share the Subnet

  1. Open Manage & Govern > Namespaces > NEW NAMESPACE.
  2. Select the project and the target VPC.
  3. Create the namespace in my lab migration-poc-public-107-ns-2c7tm.
  4. Edit the namespace and add subnet-c5mk / 192.168.107.0/24 under Subnets.
  5. Save and wait until the namespace becomes Active.

Now verify it from the Supervisor Control Plane:

kubectl get subnets.crd.nsx.vmware.com \
  -n migration-poc-public-107-ns-2c7tm

Expected result:

NAME          ACCESSMODE   NETWORKADDRESSES
subnet-c5mk   Public       192.168.107.0/24

Checkpoint: if you get No resources found, do not start the import. Mobility Operator would create a SubnetPort referencing a missing Subnet CR and stop at NetworkBackingReady=False.

Part 4 – Prepare the Source Network and Build the L2 Bridge

Step 9 – Prepare the Source Segment and the Test VM

In my lab I built the source side from scratch, so that I could test it end to end. In production, this is your existing segment.

  1. In NSX Manager, open Networking > Segments > Add Segment.
  2. Name: vcf-migration-test-public.
  3. Transport Zone: overlay-tz-mgmt-nsxt.
  4. Connected Gateway: vworld-t1-gw01.
  5. Subnet/Gateway: 192.168.107.1/24.
  6. Attach the MAC Discovery profile migration-mac-learning (Step 10).
  7. Run test-0006 on the segment with IP 192.168.107.20/24 and gateway 192.168.107.1.
  8. From an external host, start a continuous ping to 192.168.107.20 and keep it running for the whole migration.

Now verify the source route on Tier-0:

curl -sk -u "${NSX_USER}:${NSX_PASS}" \
  "${NSX}/policy/api/v1/infra/tier-0s/${T0_ID}/routing-table" \
  | jq '.results[]?.route_entries[]? | select(.network=="192.168.107.0/24")'

Checkpoint: before migration, expect route_type=t1c, admin_distance=3, next_hop=100.64.0.1.

Shared bridge infrastructure

Steps 10 to 14 are done once per environment, not once per VM. Future migrations reuse the Bridge Profile, VLAN Transport Zone, and parent segment; each new L2 domain only gets a new bridge VLAN.

Step 10 – Create the MAC Discovery Profile

Open Networking > Profiles > Segment Profiles > MAC Discovery > Add. My lab name was migration-mac-learning.

SettingValueWhy
MAC ChangeYesRequired when traffic crosses the bridge
MAC LearningYesLearns the guest MAC behind the bridge
Unknown Unicast FloodingNoAvoids unnecessary flooding
MAC Limit4096Lab value; size it for production

Step 11 – Create a Dedicated VLAN Transport Zone and Edge Switch

My first idea was to reuse the existing VLAN TZ on a second Edge host switch. NSX refused it, because a Transport Zone must be unique across host switches. So I created a dedicated one.

  1. Open System > Fabric > Transport Zones > Add Transport Zone.
  2. Name: migration-bridge-vlan-tz, Traffic Type: VLAN. Save.
  3. Open System > Fabric > Nodes > Edge Transport Nodes and edit each Edge used by the bridge.
  4. Add an additional VLAN switch with uplink profile nsx-edge-single-nic-uplink-profile.
  5. Attach migration-bridge-vlan-tz to the switch.
  6. Uplink/interface: fp-eth2.
  7. Repeat for the primary and backup Edge.

Step 12 – Create the Parent Overlay Segment and Connect the Edge vNIC

  1. In NSX Manager, open Networking > Segments > Add Segment.
  2. Name: migration-parent-seg, Transport Zone: overlay-tz-mgmt-nsxt, Gateway: None, Subnet: empty.
  3. In the vSphere Client, edit the Edge VM and connect the extra adapter (in my lab, Network Adapter 4 / fp-eth2) to migration-parent-seg.
  4. Repeat for both Edges.

Checkpoint: the parent segment shows two Edge ports.

Step 13 – Create the Edge Bridge Profile

  1. Open Networking > Segments > Edge Bridge Profiles.
  2. Create migration-poc-bridge-profile with Edge Cluster vworld-edge-cl01, primary Edge vcf-edge-01 and backup Edge vcf-edge-02.
  3. Save.

Checkpoint: the profile is Success / Realized.

Step 14 – Share the Bridge Profile and VLAN TZ with the NSX Project

The BridgeConnection lives under the VPC project path, while the Bridge Profile and VLAN TZ are infra resources. They must be visible to the project. In my lab, I shared both into test-org-auto (a85bcc0c-ad2f-45bb-9593-b7640713f0dc) using NSX resource sharing:

/infra/sites/default/enforcement-points/default/edge-bridge-profiles/migration-poc-bridge-profile
/infra/sites/default/enforcement-points/default/transport-zones/migration-bridge-vlan-tz

Per-migration bridge

Now we build the bridge for this specific subnet. The VLAN is only an internal bridge mapping tag, but it must be unique for the L2 domain. I used VLAN 102.

export PROJECT_ID="a85bcc0c-ad2f-45bb-9593-b7640713f0dc"
export SOURCE_SEGMENT_ID="vcf-migration-test-public"
export VPC_ID="vpc-migration-poc-public-107"
export SUBNET_ID="subnet-c5mk"
export PARENT_SEGMENT_PATH="/infra/segments/migration-parent-seg"
export BRIDGE_PROFILE_PATH="/infra/sites/default/enforcement-points/default/edge-bridge-profiles/migration-poc-bridge-profile"
export VLAN_TZ_PATH="/infra/sites/default/enforcement-points/default/transport-zones/migration-bridge-vlan-tz"
export BRIDGE_VLAN="102"
export BINDING_ID="migration-bind-102"

Step 15 – Do Not Guess VPC_ID and SUBNET_ID

curl -sk -u "${NSX_USER}:${NSX_PASS}" \
  "${NSX}/policy/api/v1/orgs/default/projects/${PROJECT_ID}/vpcs" \
  | jq '.results[] | {id,display_name,path}'

curl -sk -u "${NSX_USER}:${NSX_PASS}" \
  "${NSX}/policy/api/v1/orgs/default/projects/${PROJECT_ID}/vpcs/${VPC_ID}/subnets" \
  | jq '.results[] | {id,display_name,access_mode,ip_addresses,connectivity_state}'

Watch out for look-alike VPCs.

In my lab there was also a namespace-generated VPC with a similar name, containing only an _services subnet. The BridgeConnection must point to the VPC that actually holds the Public subnet.

Step 16 – Create the Target BridgeConnection

curl -sk -u "${NSX_USER}:${NSX_PASS}" -X PUT \
  "${NSX}/policy/api/v1/orgs/default/projects/${PROJECT_ID}/vpcs/${VPC_ID}/subnets/${SUBNET_ID}/bridge-connections/migration-bridge-102" \
  -H 'Content-Type: application/json' \
  -d "{
    \"display_name\": \"migration-bridge-102\",
    \"bridge_profile_path\": \"${BRIDGE_PROFILE_PATH}\",
    \"vlan_ids\": [\"${BRIDGE_VLAN}\"],
    \"vlan_transport_zone_path\": \"${VLAN_TZ_PATH}\"
  }" | jq .

The property name must be vlan_transport_zone_path. With transport_zone_path the API returns BAD_REQUEST: property unrecognized.

Step 17 – Create the Source SegmentConnectionBindingMap

curl -sk -u "${NSX_USER}:${NSX_PASS}" -X PUT \
  "${NSX}/policy/api/v1/infra/segments/${SOURCE_SEGMENT_ID}/segment-connection-binding-maps/${BINDING_ID}" \
  -H 'Content-Type: application/json' \
  -d "{
    \"display_name\": \"${BINDING_ID}\",
    \"segment_path\": \"${PARENT_SEGMENT_PATH}\",
    \"vlan_traffic_tag\": ${BRIDGE_VLAN}
  }" | jq .

Step 18 – Verify the Realized State

curl -sk -u "${NSX_USER}:${NSX_PASS}" \
  "${NSX}/policy/api/v1/infra/realized-state/realized-entities?intent_path=/orgs/default/projects/${PROJECT_ID}/vpcs/${VPC_ID}/subnets/${SUBNET_ID}/bridge-connections/migration-bridge-102" \
  | jq .

Checkpoint: expect at least RealizedLogicalPort and RealizedBridgeEndpoint with state=REALIZED. The SegmentConnectionBindingMap may not expose its own realized-state record; a successful PUT and a working dataplane are what matter.

Part 5 – Import the Running VM with Mobility Operator

Step 19 – Find the VM MoRef and the NIC Device Key

export VC="https://vcf-vcsa.vcf.vworld.lab"
export VC_USER="administrator@vsphere.local"
export VC_PASS="<PASSWORD>"
export VC_SESSION=$(curl -sk -u "${VC_USER}:${VC_PASS}" -X POST "${VC}/api/session" | tr -d '"')

curl -sk -H "vmware-api-session-id: ${VC_SESSION}" "${VC}/api/vcenter/vm" \
  | jq '.[] | select(.name=="test-0006")'

The filter.names query parameter was not supported in my lab, so I listed all VMs and filtered locally with jq. The result was vm-4039. Now the NIC:

export VM_MOID="vm-4039"

curl -sk -H "vmware-api-session-id: ${VC_SESSION}" \
  "${VC}/api/vcenter/vm/${VM_MOID}/hardware/ethernet" | jq .

The NIC device key was 4000.

Step 20 – Create the ImportOperationBatch in Precheck Mode

We start with a dry run. precheckOnly: true validates everything without touching the VM, and commitAction: Wait makes sure nothing is committed automatically.

apiVersion: mobility-operator.vmware.com/v1alpha3
kind: ImportOperationBatch
metadata:
  name: import-test-0006
  namespace: migration-poc-public-107-ns-2c7tm
spec:
  defaultSpec:
    mode: preserve
    controlAction:
      precheckOnly: true
      commitAction: Wait
  operations:
    - name: test-0006
      spec:
        virtualMachineID: vm-4039
        networkInterfaces:
          - deviceKey: 4000
            subnetInfo:
              apiGroup: crd.nsx.vmware.com
              kind: Subnet
              name: subnet-c5mk
kubectl apply -f import-test-0006.yaml

kubectl get importoperationbatch import-test-0006 \
  -n migration-poc-public-107-ns-2c7tm -o yaml

kubectl get importoperation test-0006 \
  -n migration-poc-public-107-ns-2c7tm -o yaml

Checkpoint: the precheck must show PrecheckSucceeded=True and the preserved addressing: 192.168.107.20/24, gateway 192.168.107.1 and MAC 00:50:56:9c:6e:cc.

Step 21 – Execute the Import Without Committing

  1. Make sure the continuous ping to 192.168.107.20 is still running.
  2. Edit the batch:
kubectl edit importoperationbatch import-test-0006 \
  -n migration-poc-public-107-ns-2c7tm
  1. Change only precheckOnly: true to false. Keep commitAction: Wait and mode: preserve.
  2. Save and watch the operation:
kubectl get importoperation test-0006 \
  -n migration-poc-public-107-ns-2c7tm -w

Wait for all of these conditions:

NetworkBackingReady=True
ReadyForCommit=True
VirtualMachineCreated=True
VirtualMachineReady=True
VirtualMachineReadyForImport=True
VirtualMachineSetManagedBySucceeded=True

The key evidence

stateTransitions should still show source.powerState=poweredOn. This is the proof that the import happens without a planned power-off.

At this point, the VM NIC is already on the target SubnetPort, but its traffic still goes over the bridge to the source Tier-1.

Step 22 – Commit the Import

  1. Inside the guest, verify ping, uptime, ip addr and ip route.
  2. Edit the batch again and change commitAction: Wait to Auto. Keep precheckOnly: false and mode: preserve.
  3. Watch the ImportOperation until Completed=True.

After commit, the VM is represented as a vmoperator.vmware.com/v1alpha5 VirtualMachine in the namespace. Routing, however, still returns to the source Tier-1 over the bridge. That is what we change next.

Part 6 – The L3 Cutover

This is the moment where the target VPC takes over routing for the prefix. Keep the ping window visible.

Step 23 – Confirm the Source t1c Route

curl -sk -u "${NSX_USER}:${NSX_PASS}" \
  "${NSX}/policy/api/v1/infra/tier-0s/${T0_ID}/routing-table" \
  | jq '.results[]?.route_entries[]? | select(.network=="192.168.107.0/24")'

Checkpoint: route_type=t1c, next_hop=100.64.0.1.

Step 24 – Deny Source Advertisement for the Migrated Prefix Only

  1. In NSX Manager, open Networking > Tier-1 Gateways > vworld-t1-gw01 > Edit.
  2. Open Route Advertisement > Set Route Advertisement Rules.
  3. Add a rule:
FieldValue
Namemigration-107-cutover-deny
Network192.168.107.0/24
Prefix OperatorEQ
ActionDeny
Route TypeConnected Segments & Service Ports
  1. Save.

Do not disable connected routes globally.

The source Tier-1 may serve many other networks. The deny rule must hit only the migrated prefix.

After saving, t1c disappears from Tier-0, and the external ping may stop for a moment.

Step 25 – Enable VPC Gateway Connectivity on the Target Subnet

  1. In VCF Automation, open Manage & Govern > Subnets.
  2. Open the target Public subnet 192.168.107.0/24.
  3. Edit and switch VPC Gateway Connectivity to On.
  4. Save and wait a few seconds.
  5. Check the Tier-0 routing table again.

The prefix should now appear as:

route_type: tgws
network: 192.168.107.0/24
admin_distance: 5
next_hop: 169.254.64.15
black_hole: false

Figure 6. The final cutover: t1c first, a short ping interruption, then tgws via 169.254.64.15 and a stable ping to 192.168.107.20.

In my lab, the ping showed only a few Request timed out lines before replies came back through the TGW. Keep the bridge active for now; it is your safety net.

Part 7 – Validate and Remove the Bridge

Step 26 – Post-Cutover Validation

  • External ping to the VM is stable.
  • Tier-0 shows only tgws for the migrated /24, not t1c.
  • The VM still has 192.168.107.20/24.
  • The guest default gateway is still 192.168.107.1.
  • The MAC is still 00:50:56:9c:6e:cc.
  • uptime was not reset.
  • ImportOperation reports Completed=True.
  • vSphere shows Managed By / WCP Service, and the VM is in the target resource pool and network backing.
  • The application on the VM responds, not only ICMP.

Step 27 – Remove the Per-Network Bridge Objects

Once target routing is proven independent, remove the objects created for this subnet. The shared bridge infrastructure can stay for future migrations.

curl -sk -u "${NSX_USER}:${NSX_PASS}" -X DELETE \
  "${NSX}/policy/api/v1/infra/segments/${SOURCE_SEGMENT_ID}/segment-connection-binding-maps/${BINDING_ID}"

curl -sk -u "${NSX_USER}:${NSX_PASS}" -X DELETE \
  "${NSX}/policy/api/v1/orgs/default/projects/${PROJECT_ID}/vpcs/${VPC_ID}/subnets/${SUBNET_ID}/bridge-connections/migration-bridge-102"

Checkpoint: after bridge removal, ping and the application must keep working. This is the final proof that the VM uses only the target dataplane.

L3 Rollback Before Bridge Removal

If traffic does not recover after enabling Gateway Connectivity, do not reverse the VM import. As long as the bridge exists, L3 can simply go back to the source:

  1. Disable VPC Gateway Connectivity on the target Public subnet.
  2. Confirm that tgws for 192.168.107.0/24 disappears from Tier-0.
  3. Remove migration-107-cutover-deny from vworld-t1-gw01.
  4. Confirm that t1c returns via 100.64.0.1.
  5. Ping recovers via target NIC -> L2 bridge -> source segment -> source Tier-1.
  6. Troubleshoot, then repeat the cutover.

Conclusion

We started with a running VM on a classic NSX segment behind an old Tier-1. We ended with the same VM, with the same IP, MAC, gateway, and uptime, managed by vSphere Supervisor and VM Service, and routed through a VPC, a Transit Gateway, and a Centralized External Connection.

Three elements make it work: a correctly built L2 bridge, Mobility Operator in mode: preserve, and a target Public subnet backed by an External IP Block that the existing External Connection can advertise. Everything else is about doing things in the right order.

The most interesting part, at least for me, is the moment on Tier-0 when route_type=t1c disappears and route_type=tgws shows up. That single line in the routing table is where the old world hands over to the new one.

From an infrastructure perspective, this is a precise, multi-layer change touching the provider, the tenant, the Edge, and Kubernetes.

From the application perspective, it is a few missed pings.

In production, treat every migration like this as a controlled network and application change: establish prefix ownership, monitor both dataplanes, keep the bridge until validation is complete, and always have the L3 rollback ready.

Share with:


Leave a Reply

Your email address will not be published. Required fields are marked *