You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Site to Site VPN Connections shows disconnected if there are no running vm's #13687
Name (vpc1-gateway) > Gateway ( publicip address (source nat) > CIDR list (172.30.21.0/28 ) > IPsec preshared-key ( from step 3 for each vpc)
Name (vpc2-gateway) > Gateway ( publicip address (source nat) > CIDR list (172.30.21.0/28 ) > IPsec preshared-key ( from step 3 for each vpc)
The site to site vpn tunnel should get established even if there are no vm's present in the initial deployment
IKE/IPsec negotiation happens VR-to-VR over the public IPs that negotiation doesn't inherently need a guest VM to exist.
Currently, the IKE initiation on the active side is contingent on some triggering event , that trigger generally comes from a config re-push tied to VM deployment (which touches routing/network state across the VRs),
Same symptom on 4.22.1.1 (VPC, VpcVirtualRouter, non-persistent tier offering). Traced it to the state poller's router selection rather than to the tunnel.
Symptom
A site-to-site VPN connection on a VPC with no running VM never changes state. After createVpnConnection it reads Connecting (or Disconnected when passive) indefinitely, even while the peer has completed IKE and reports its tunnel up; resetVpnConnection only rewrites the same word. Deploying one VM in a tier moves it to Connected within a minute. Destroying every VM and waiting out network GC freezes it at its last value, so a tunnel that later drops still reads Connected. listRouters shows the VPC router's guest NIC appearing and disappearing with the tier; the router itself stays Running.
Cause (branch 4.22, head 2e63c60; the cited files are byte-identical on tag 4.22.1.1 and on main)
The only writer of Connected/Disconnected from live router state is CheckRouterTask → updateSite2SiteVpnConnectionState (VirtualNetworkApplianceManagerImpl.java:1077-1080, body :784-870), fed by _routerDao.listIsolatedByHostId(null).
That query is an INNER JOIN on router_network_ref with guest_type = Isolated (DomainRouterDaoImpl.java:110-118, :253-265). A router with no such row is never polled.
A VPC router has no such row at deploy. It gets one when a tier is implemented (VpcVirtualRouterElement.java:227-234 → VpcVirtualNetworkApplianceManagerImpl.java:151-166) and loses it when the tier is shut down (removeVpcRouterFromGuestNetwork).
A tier is implemented by the first VM start and shut down by NetworkGarbageCollector once no running VM holds a NIC in it (NetworkOrchestrator.java:3602-3662, NetworkDaoImpl.findNetworksToGarbageCollect:540-547).
So until a VM runs, and again after the last one is gone, the task never looks at the router, and the connection keeps whatever startVpnConnection last wrote (Site2SiteVpnManagerImpl.java:417-421).
Fix
updateSite2SiteVpnConnectionState only does work for VPC routers: getConnectionsForRouter returns an empty list when vpcId is null (Site2SiteVpnManagerImpl.java:887-896). Selecting routers by isolated-tier membership is the wrong join for this step. CheckRouterTask already iterates _vpcDao.listAll() for its redundant-state half (:1083-1088); passing _routerDao.listByVpcId(vpcId) (DomainRouterDaoImpl.java:415-420) for each VPC that owns site-to-site connections into the VPN check, keeping its existing Running / redundant-PRIMARY / INTERNAL_LB_VM filters, polls the router for as long as it exists. A DAO method listing routers with vpc_id IS NOT NULL would do the same.
Reproduced on a 4.22.1.1 lab with the management DB and router shells open, which confirms the mechanism above and adds the garbage-collection variant.
Setup. Three VPCs on one KVM host: vpca and vpcb with one tier and one running VM each; vpcd with one tier and no VM. Site-to-site VPN between vpcd and vpcb, both sides passive=false.
Observed
router_network_ref held one Isolated row for vpca's router and one for vpcb's. Nothing for vpcd's router, which had only its public NIC.
CheckRouterTask logged Found 2 routers to update status every 30 s before and after vpcd existed.
vpcb's connection toward vpcd read Connected. vpcd's connection toward vpcb read Connecting for as long as it was left, while ipsec statusall on both routers showed the SA ESTABLISHED and the CHILD_SA INSTALLED. vpcb's router had initiated.
On vpcd's router, ip route get <peer tier address> sourced from the public IP, so its own trigger ping in configure.py never matches the leftsubnet trap policy; a VM-less VPC router can respond to IKE but never initiate it.
The reverse direction, after garbage collection (network.gc.interval and network.gc.wait lowered to 60 s to make it quick): stopping the only VM in vpcb's tier (not destroying it) moved the tier Implemented → Shutdown → Allocated, removed the router's tier NIC and its router_network_ref row, and the poller dropped to Found 3 routers. vpcb's connections kept reading Connected. Deleting the far side's connection then removed the SA from vpcb's router while the API still read Connected 40 s later. Starting the VM re-implemented the tier and the state corrected to Disconnected within one poll.
Workaround that holds. A tier on a network offering with ispersistent=true (a clone of DefaultIsolatedNetworkOfferingForVpcNetworks with the same services and providers; createNetworkOffering accepts the flag with forvpc=true) is implemented at creation and never garbage-collected, so its router carries the row from the start. A VPC built on it reached Connected within 10 s with no VM, and moving an existing Allocated tier onto it with updateNetwork networkofferingid= implemented the tier immediately and unfroze its connection. Whether the poller should depend on tier implementation at all is still the question for the fix in the comment above.
Activity
skorchir commentedon Oct 1, 2026
Same symptom on 4.22.1.1 (VPC, VpcVirtualRouter, non-persistent tier offering). Traced it to the state poller's router selection rather than to the tunnel.
Symptom
A site-to-site VPN connection on a VPC with no running VM never changes state. After
createVpnConnectionit readsConnecting(orDisconnectedwhen passive) indefinitely, even while the peer has completed IKE and reports its tunnel up;resetVpnConnectiononly rewrites the same word. Deploying one VM in a tier moves it toConnectedwithin a minute. Destroying every VM and waiting out network GC freezes it at its last value, so a tunnel that later drops still readsConnected.listRoutersshows the VPC router's guest NIC appearing and disappearing with the tier; the router itself stays Running.Cause (branch 4.22, head 2e63c60; the cited files are byte-identical on tag 4.22.1.1 and on main)
Connected/Disconnectedfrom live router state isCheckRouterTask→updateSite2SiteVpnConnectionState(VirtualNetworkApplianceManagerImpl.java:1077-1080, body:784-870), fed by_routerDao.listIsolatedByHostId(null).router_network_refwithguest_type = Isolated(DomainRouterDaoImpl.java:110-118,:253-265). A router with no such row is never polled.VpcVirtualRouterElement.java:227-234→VpcVirtualNetworkApplianceManagerImpl.java:151-166) and loses it when the tier is shut down (removeVpcRouterFromGuestNetwork).NetworkGarbageCollectoronce no running VM holds a NIC in it (NetworkOrchestrator.java:3602-3662,NetworkDaoImpl.findNetworksToGarbageCollect:540-547).So until a VM runs, and again after the last one is gone, the task never looks at the router, and the connection keeps whatever
startVpnConnectionlast wrote (Site2SiteVpnManagerImpl.java:417-421).Fix
updateSite2SiteVpnConnectionStateonly does work for VPC routers:getConnectionsForRouterreturns an empty list whenvpcIdis null (Site2SiteVpnManagerImpl.java:887-896). Selecting routers by isolated-tier membership is the wrong join for this step.CheckRouterTaskalready iterates_vpcDao.listAll()for its redundant-state half (:1083-1088); passing_routerDao.listByVpcId(vpcId)(DomainRouterDaoImpl.java:415-420) for each VPC that owns site-to-site connections into the VPN check, keeping its existing Running / redundant-PRIMARY / INTERNAL_LB_VM filters, polls the router for as long as it exists. A DAO method listing routers withvpc_id IS NOT NULLwould do the same.skorchir commentedon Oct 1, 2026
Reproduced on a 4.22.1.1 lab with the management DB and router shells open, which confirms the mechanism above and adds the garbage-collection variant.
Setup. Three VPCs on one KVM host:
vpcaandvpcbwith one tier and one running VM each;vpcdwith one tier and no VM. Site-to-site VPN betweenvpcdandvpcb, both sidespassive=false.Observed
router_network_refheld oneIsolatedrow forvpca's router and one forvpcb's. Nothing forvpcd's router, which had only its public NIC.CheckRouterTaskloggedFound 2 routers to update statusevery 30 s before and aftervpcdexisted.vpcb's connection towardvpcdreadConnected.vpcd's connection towardvpcbreadConnectingfor as long as it was left, whileipsec statusallon both routers showed the SAESTABLISHEDand the CHILD_SAINSTALLED.vpcb's router had initiated.vpcd's router,ip route get <peer tier address>sourced from the public IP, so its own trigger ping inconfigure.pynever matches theleftsubnettrap policy; a VM-less VPC router can respond to IKE but never initiate it.The reverse direction, after garbage collection (
network.gc.intervalandnetwork.gc.waitlowered to 60 s to make it quick): stopping the only VM invpcb's tier (not destroying it) moved the tierImplemented → Shutdown → Allocated, removed the router's tier NIC and itsrouter_network_refrow, and the poller dropped toFound 3 routers.vpcb's connections kept readingConnected. Deleting the far side's connection then removed the SA fromvpcb's router while the API still readConnected40 s later. Starting the VM re-implemented the tier and the state corrected toDisconnectedwithin one poll.Workaround that holds. A tier on a network offering with
ispersistent=true(a clone ofDefaultIsolatedNetworkOfferingForVpcNetworkswith the same services and providers;createNetworkOfferingaccepts the flag withforvpc=true) is implemented at creation and never garbage-collected, so its router carries the row from the start. A VPC built on it reachedConnectedwithin 10 s with no VM, and moving an existing Allocated tier onto it withupdateNetwork networkofferingid=implemented the tier immediately and unfroze its connection. Whether the poller should depend on tier implementation at all is still the question for the fix in the comment above.