diff --git a/gso/services/netbox_client.py b/gso/services/netbox_client.py
index 02f5313a94d88e48447335c7945da5e14ea0aabb..aac06eea66fcd21281e030486c30e3c647fbbf5e 100644
--- a/gso/services/netbox_client.py
+++ b/gso/services/netbox_client.py
@@ -53,6 +53,14 @@ class NetboxClient:
     def get_all_devices(self) -> list[Devices]:
         return list(self.netbox.dcim.devices.all())
 
+    def get_allocated_interfaces_by_gso_subscription(self, device_name: str, subscription_id: UUID) -> list[Interfaces]:
+        """Return all allocated interfaces of a device by name."""
+
+        device = self.get_device_by_name(device_name)
+        return self.netbox.dcim.interfaces.filter(
+            device_id=device.id, enabled=True, mark_connected=True, description=subscription_id
+        )
+
     def get_device_by_name(self, device_name: str) -> Devices:
         """Return the device object by name from netbox, or ``None`` if not found."""
         return self.netbox.dcim.devices.get(name=device_name)
@@ -84,6 +92,13 @@ class NetboxClient:
             description=description,
         )
 
+    def delete_interface(self, device_name: str, iface_name: str) -> None:
+        """Delete an interface from a device by name."""
+
+        device = self.get_device_by_name(device_name)
+        interface = self.netbox.dcim.interfaces.get(device_id=device.id, name=iface_name)
+        return interface.delete()
+
     def create_device_type(self, manufacturer: str, model: str, slug: str) -> DeviceTypes:
         """Create a new device type in Netbox."""
 
@@ -224,6 +239,43 @@ class NetboxClient:
 
         return interface
 
+    def free_interface(self, device_name: str, iface_name: str) -> Interfaces:
+        """Free interface by marking disconnect and disable it."""
+
+        device = self.get_device_by_name(device_name)
+        interface = self.netbox.dcim.interfaces.get(device_id=device.id, name=iface_name)
+
+        # Check if interface is available
+        if interface is None:
+            raise NotFoundError(f"Interface: {iface_name} on device: {device_name} not found.")
+
+        interface.mark_connected = False
+        interface.enabled = False
+        interface.description = ""
+        interface.save()
+
+        return interface
+
+    def deallocate_interface(self, device_name: str, iface_name: str) -> Interfaces:
+        """Allocate an interface by marking it as connected."""
+
+        device = self.get_device_by_name(device_name)
+        interface = self.netbox.dcim.interfaces.get(device_id=device.id, name=iface_name)
+
+        # Check if interface is available
+        if interface is None:
+            raise NotFoundError(f"Interface: {iface_name} on device: {device_name} not found.")
+
+        # Check if interface is reserved
+        if interface.mark_connected:
+            raise WorkflowStateError(f"The interface: {iface_name} on device: {device_name} is already allocated.")
+
+        # allocate interface by mark as connected
+        interface.mark_connected = False
+        interface.save()
+
+        return interface
+
     def get_available_lags(self, router_id: UUID) -> list[str]:
         """Return all available :term:`LAG`s not assigned to a device."""
 
diff --git a/gso/workflows/iptrunk/migrate_iptrunk.py b/gso/workflows/iptrunk/migrate_iptrunk.py
index 4b918d00326114ed1da4f1b87a2a055f406bfe52..b1e48b57091f0f0ca971b8eab07e94401b064dd0 100644
--- a/gso/workflows/iptrunk/migrate_iptrunk.py
+++ b/gso/workflows/iptrunk/migrate_iptrunk.py
@@ -4,7 +4,6 @@ from typing import NoReturn
 
 from orchestrator import step, workflow
 from orchestrator.config.assignee import Assignee
-from orchestrator.db import ProductTable, SubscriptionTable
 from orchestrator.forms import FormPage
 from orchestrator.forms.validators import Choice, Label, UniqueConstrainedList
 from orchestrator.targets import Target
@@ -13,108 +12,118 @@ from orchestrator.workflow import StepList, done, init, inputstep
 from orchestrator.workflows.steps import resync, store_process_subscription, unsync
 from orchestrator.workflows.utils import wrap_modify_initial_input_form
 from pydantic import validator
+from pynetbox.models.dcim import Interfaces
 
+from gso.products.product_blocks.router import RouterVendor
 from gso.products.product_types.iptrunk import Iptrunk
 from gso.products.product_types.router import Router
 from gso.services import provisioning_proxy
+from gso.services.netbox_client import NetboxClient
 from gso.services.provisioning_proxy import pp_interaction
-from gso.utils.helpers import set_isis_to_90000
+from gso.services.subscriptions import get_active_router_subscriptions
+from gso.utils.helpers import available_interfaces_choices, available_lags_choices, get_router_vendor, set_isis_to_90000
 
 logger = getLogger(__name__)
 
 
 def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator:
     subscription = Iptrunk.from_subscription(subscription_id)
+    form_title = (
+        f"Subscription {subscription.iptrunk.geant_s_sid} "
+        f" from {subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_fqdn}"
+        f" to {subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.router_fqdn}"
+    )
     sides_dict = {
         str(side.iptrunk_side_node.subscription.subscription_id): side.iptrunk_side_node.subscription.description
         for side in subscription.iptrunk.iptrunk_sides
     }
 
-    ReplacedSide = Choice(
+    replaced_side_enum = Choice(
         "Select the side of the IP trunk to be replaced",
         zip(sides_dict.keys(), sides_dict.items()),  # type: ignore[arg-type]
     )
 
-    class OldSideIptrunkForm(FormPage):
+    class IPTrunkMigrateForm(FormPage):
         class Config:
-            title = (
-                f"Subscription {subscription.iptrunk.geant_s_sid} from "
-                f"{subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_fqdn}"
-                f" to "
-                f"{subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.router_fqdn}"
-            )
+            title = form_title
 
         tt_number: str
-        replace_side: ReplacedSide  # type: ignore[valid-type]
+        replace_side: replaced_side_enum  # type: ignore[valid-type]
         warning_label: Label = "Are we moving to a different Site?"  # type: ignore[assignment]
-        migrate_to_different_site: bool | None = False
+        migrate_to_different_site: bool = False
 
-    old_side_input = yield OldSideIptrunkForm
+    migrate_form_input = yield IPTrunkMigrateForm
 
+    current_routers = [
+        subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.subscription.subscription_id,
+        subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.subscription.subscription_id,
+    ]
     routers = {}
-    for router_id, router_description in (
-        SubscriptionTable.query.join(ProductTable)
-        .filter(
-            ProductTable.product_type == "Router",
-            SubscriptionTable.status == "active",
-        )
-        .with_entities(SubscriptionTable.subscription_id, SubscriptionTable.description)
-        .all()
-    ):
-        if router_id not in [
-            subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.subscription.subscription_id,
-            subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.subscription.subscription_id,
-        ]:
-            current_router = Router.from_subscription(router_id)
-            old_side_site_id = Router.from_subscription(old_side_input.replace_side).router.router_site
+    for router_id, router_description in get_active_router_subscriptions(fields=["subscription_id", "description"]):
+        if router_id not in current_routers:
+            current_router_site = Router.from_subscription(router_id).router.router_site.subscription
+            old_side_site = Router.from_subscription(migrate_form_input.replace_side).router.router_site
             if (
-                not old_side_input.migrate_to_different_site
-                and current_router.router.router_site.subscription.subscription_id != old_side_site_id
+                migrate_form_input.migrate_to_different_site
+                and current_router_site.subscription_id == old_side_site.owner_subscription_id
             ):
                 continue
             routers[str(router_id)] = router_description
 
-    NewRouterEnum = Choice("Select a new router", zip(routers.keys(), routers.items()))  # type: ignore[arg-type]
+    new_router_enum = Choice("Select a new router", zip(routers.keys(), routers.items()))  # type: ignore[arg-type]
+
+    class NewSideIPTrunkRouterForm(FormPage):
+        class Config:
+            title = form_title
+
+        new_node: new_router_enum  # type: ignore[valid-type]
+
+    new_side_iptrunk_router_input = yield NewSideIPTrunkRouterForm
+    new_router = new_side_iptrunk_router_input.new_node
+    side_a_ae_iface = available_lags_choices(new_router) or str
 
     class LagMemberList(UniqueConstrainedList[str]):
         min_items = len(subscription.iptrunk.iptrunk_sides[0].iptrunk_side_ae_members)
         max_items = len(subscription.iptrunk.iptrunk_sides[1].iptrunk_side_ae_members)
+        item_type = available_interfaces_choices(new_router, subscription.iptrunk.iptrunk_speed)  # type: ignore
+        unique_items = True
 
-    class NewSideIptrunkForm(FormPage):
-        class Config:
-            title = (
-                f"Subscription {subscription.iptrunk.geant_s_sid} from "
-                f"{subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_fqdn} to "
-                f"{subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.router_fqdn}"
-            )
+    class JuniperLagMemberList(UniqueConstrainedList[str]):
+        min_items = len(subscription.iptrunk.iptrunk_sides[0].iptrunk_side_ae_members)
+        max_items = len(subscription.iptrunk.iptrunk_sides[1].iptrunk_side_ae_members)
+        unique_items = True
 
-        new_node: NewRouterEnum  # type: ignore[valid-type]
-        new_lag_interface: str
-        new_lag_member_interfaces: LagMemberList
+    ae_members_side_a = LagMemberList if get_router_vendor(new_router) == RouterVendor.NOKIA else JuniperLagMemberList
 
-        @validator("new_lag_interface", allow_reuse=True, pre=True, always=True)
-        def lag_interface_proper_name(cls, new_lag_name: str) -> str | NoReturn:
-            nokia_lag_re = re.compile("^lag-\\d+$")
-            juniper_lag_re = re.compile("^ae\\d{1,2}$")
+    class NewSideIPTrunkForm(FormPage):
+        class Config:
+            title = form_title
 
-            if nokia_lag_re.match(new_lag_name) or juniper_lag_re.match(new_lag_name):
-                return new_lag_name
+        new_lag_interface: side_a_ae_iface  # type: ignore[valid-type]
+        new_lag_member_interfaces: ae_members_side_a  # type: ignore[valid-type]
 
-            raise ValueError("Invalid LAG name, please try again.")
+        @validator("new_lag_interface", allow_reuse=True, pre=True, always=True)
+        def lag_interface_proper_name(cls, new_lag_interface: str) -> str | NoReturn:
+            if get_router_vendor(new_router) == RouterVendor.JUNIPER:
+                juniper_lag_re = re.compile("^ae\\d{1,2}$")
+                if not juniper_lag_re.match(new_lag_interface):
+                    raise ValueError("Invalid LAG name, please try again.")
+            return new_lag_interface
 
-    new_side_input = yield NewSideIptrunkForm
+    new_side_input = yield NewSideIPTrunkForm
 
     def _find_updated_side_of_trunk(trunk: Iptrunk, new_side: str) -> int:
-        sides = trunk.iptrunk.iptrunk_sides
-        if str(sides[0].iptrunk_side_node.subscription.subscription_id) == new_side:
-            return 0
-        elif str(sides[1].iptrunk_side_node.subscription.subscription_id) == new_side:  # noqa: RET505
-            return 1
+        for side in trunk.iptrunk.iptrunk_sides:
+            if str(side.iptrunk_side_node.subscription.subscription_id) == new_side:
+                return trunk.iptrunk.iptrunk_sides.index(side)
         raise ValueError("Invalid Router id provided to be replaced!")
 
-    replace_index = _find_updated_side_of_trunk(subscription, old_side_input.replace_side)
-
-    return old_side_input.dict() | new_side_input.dict() | {"replace_index": replace_index}
+    return (
+        migrate_form_input.dict()
+        | new_side_iptrunk_router_input.dict()
+        | new_side_input.dict()
+        | {"replace_index": _find_updated_side_of_trunk(subscription, migrate_form_input.replace_side)}
+    )
 
 
 @step("[DRY RUN] Disable configuration on old router")
@@ -385,10 +394,76 @@ def update_subscription_model(
     new_lag_interface: str,
     new_lag_member_interfaces: list[str],
 ) -> State:
+    old_side_data = {
+        "iptrunk_side_node": subscription.iptrunk.iptrunk_sides[replace_index].iptrunk_side_node,
+        "iptrunk_side_ae_iface": subscription.iptrunk.iptrunk_sides[replace_index].iptrunk_side_ae_iface,
+        "iptrunk_side_ae_members": subscription.iptrunk.iptrunk_sides[replace_index].iptrunk_side_ae_members,
+    }
     subscription.iptrunk.iptrunk_sides[replace_index].iptrunk_side_node = Router.from_subscription(new_node).router
     subscription.iptrunk.iptrunk_sides[replace_index].iptrunk_side_ae_iface = new_lag_interface
     subscription.iptrunk.iptrunk_sides[replace_index].iptrunk_side_ae_members = new_lag_member_interfaces
 
+    return {"subscription": subscription, "old_side_data": old_side_data}
+
+
+@step("Reserve interfaces in Netbox")
+def reserve_interfaces_in_netbox(
+    subscription: Iptrunk,
+    new_node: UUIDstr,
+    new_lag_interface: str,
+    new_lag_member_interfaces: list[str],
+) -> State:
+    new_side = Router.from_subscription(new_node).router
+
+    nbclient = NetboxClient()
+    if new_side.router_vendor == RouterVendor.NOKIA:
+        # Create LAG interfaces
+        lag_interface: Interfaces = nbclient.create_interface(
+            iface_name=new_lag_interface,
+            type="lag",
+            device_name=new_side.router_fqdn,
+            description=str(subscription.subscription_id),
+            enabled=True,
+        )
+        # Attach physical interfaces to LAG
+        # Reserve interfaces
+        for interface in new_lag_member_interfaces:
+            nbclient.attach_interface_to_lag(
+                device_name=new_side.router_fqdn,
+                lag_name=lag_interface.name,
+                iface_name=interface,
+                description=str(subscription.subscription_id),
+            )
+            nbclient.reserve_interface(
+                device_name=new_side.router_fqdn,
+                iface_name=interface,
+            )
+    return {"subscription": subscription}
+
+
+@step("Update Netbox.")
+def update_netbox(
+    subscription: Iptrunk,
+    replace_index: int,
+    old_side_data: dict,
+) -> State:
+    new_side = subscription.iptrunk.iptrunk_sides[replace_index]
+    nbclient = NetboxClient()
+    if new_side.iptrunk_side_node.router_vendor == RouterVendor.NOKIA:
+        for interface in new_side.iptrunk_side_ae_members:
+            nbclient.allocate_interface(
+                device_name=new_side.iptrunk_side_node.router_fqdn,
+                iface_name=interface,
+            )
+    if old_side_data["iptrunk_side_node"]["router_vendor"] == RouterVendor.NOKIA:
+        # Set interfaces to free
+        for iface in old_side_data["iptrunk_side_ae_members"]:
+            nbclient.free_interface(old_side_data["iptrunk_side_node"]["router_fqdn"], iface)
+
+        # Delete LAG interfaces
+        nbclient.delete_interface(
+            old_side_data["iptrunk_side_node"]["router_fqdn"], old_side_data["iptrunk_side_ae_iface"]
+        )
     return {"subscription": subscription}
 
 
@@ -402,6 +477,7 @@ def migrate_iptrunk() -> StepList:
         init
         >> store_process_subscription(Target.MODIFY)
         >> unsync
+        >> reserve_interfaces_in_netbox
         >> pp_interaction(set_isis_to_90000, 3)
         >> pp_interaction(disable_old_config_dry, 3)
         >> pp_interaction(disable_old_config_real, 3)
@@ -415,6 +491,7 @@ def migrate_iptrunk() -> StepList:
         >> pp_interaction(delete_old_config_real, 3)
         >> update_ipam
         >> update_subscription_model
+        >> update_netbox
         >> resync
         >> done
     )