XFRM SA Migrate State¶
Overview¶
XFRM_MSG_MIGRATE_STATE migrates a single SA, looked up using SPI and
mark, without involving policies. Unlike XFRM_MSG_MIGRATE, which couples
SA and policy migration and allows migrating multiple SAs in one call, this
interface identifies the SA unambiguously via SPI and supports changing
the reqid, addresses, encapsulation, selector, and offload.
Because IKE daemons can manage policies independently of
the kernel, this interface allows precise per-SA migration without
requiring policy involvement. Optional netlink attributes follow an
omit-to-inherit model: omitting an attribute preserves the value from
the old SA. The flags field controls two exceptions: hardware offload
is inherited by default and can be suppressed with
XFRM_MIGRATE_STATE_CLEAR_OFFLOAD or overridden with XFRMA_OFFLOAD_DEV;
the new selector is taken from new_sel by default and can instead be
derived from the new addresses with XFRM_MIGRATE_STATE_UPDATE_H2H_SEL.
SA Identification¶
The struct is defined in include/uapi/linux/xfrm.h. The SA is looked
up using xfrm_state_lookup() with id.spi,
id.daddr, id.proto, id.family, and
old_mark.v & old_mark.m as the mark key:
struct xfrm_user_migrate_state {
struct xfrm_usersa_id id; /* spi, daddr, proto, family */
xfrm_address_t new_daddr;
xfrm_address_t new_saddr;
struct xfrm_mark old_mark; /* SA lookup: key = v & m */
struct xfrm_selector new_sel; /* new selector (see Flags) */
__u32 new_reqid;
__u32 flags; /* XFRM_MIGRATE_STATE_* */
__u16 new_family;
__u16 reserved; /* must be zero */
};
The reserved field must be set to zero; the kernel rejects any
other value with -EINVAL.
Supported Attributes¶
The following fields in xfrm_user_migrate_state are always explicit
and are not inherited from the existing SA. Passing zero is not equivalent
to “keep unchanged” — zero is used as-is:
new_daddr- new destination addressnew_saddr- new source addressnew_family- new address familynew_reqid- new reqid (0 = no reqid)new_sel- new selector; used whenXFRM_MIGRATE_STATE_UPDATE_H2H_SELis not set (see Flags below)flags- bitmask ofXFRM_MIGRATE_STATE_*flags (see Flags below)
The following netlink attributes are also accepted. Omitting an attribute inherits the value from the existing SA (omit-to-inherit).
Attribute |
Description |
|---|---|
|
Mark on the migrated SA ( |
|
UDP encapsulation template; only |
|
Hardware offload configuration ( |
|
Output mark on the migrated SA; pair with |
|
NAT keepalive interval in seconds. Requires encap. Send 0 to clear.
Automatically cleared when encap is removed; setting a non-zero
value without encap returns |
|
Mapping maxage threshold. Only valid on input SAs; setting on an
output SA returns |
The following SA properties are immutable and cannot be changed via
XFRM_MSG_MIGRATE_STATE: algorithms (XFRMA_ALG_*), replay state,
direction (XFRMA_SA_DIR), and security context (XFRMA_SEC_CTX).
Flags¶
The flags field in xfrm_user_migrate_state controls optional
migration behaviour. Unknown flag bits are rejected with -EINVAL; the
extended ACK message identifies the unrecognised bits (e.g. "Unknown flags:
0x4"). Userspace can use XFRM_MIGRATE_STATE_KNOWN_FLAGS (defined in
<linux/xfrm.h>) to validate flags before sending; note that this constant
reflects the flags known to the header version userspace was compiled against,
which may differ from what the running kernel accepts.
Flag |
Description |
|---|---|
|
When set, the new SA has no hardware offload even when
|
|
When set, the kernel validates that the existing SA selector is a
single-host entry matching the SA addresses ( |
Migration Steps¶
Outgoing SA¶
To prevent cleartext traffic leaks, install a block policy before migrating:
Install a block policy to drop traffic on the affected selector.
Remove the old policy.
Call
XFRM_MSG_MIGRATE_STATEfor each SA.Reinstall the policies.
Remove the block policy.
If AES-GCM is in use, the block policy also prevents IV reuse during the migration window. For other AEADs this step is not required for IV safety, but skipping it allows a brief cleartext window.
Incoming SA¶
No block policy is needed. XFRM_MSG_MIGRATE_STATE atomically
transfers the sequence number and replay window from the old SA to
the new SA, so the new SA continues replay protection without a gap.
Call XFRM_MSG_MIGRATE_STATE for each SA directly.
When accepting incoming traffic, be liberal during the migration window: packets sent by the remote peer before it completed its own migration may arrive out of order or slightly late. Dropping them unnecessarily causes packet loss. A generous replay window reduces the impact of reordering during migration.
Block Policy and IV Safety¶
AES-GCM IV uniqueness is critical: reusing a (key, IV) pair allows an attacker to recover the authentication subkey and forge authentication tags, breaking both confidentiality and integrity. This concern applies to outgoing SAs only — the remote peer controls IV generation on incoming traffic.
XFRM_MSG_MIGRATE_STATE atomically copies the sequence number and
replay window from the old SA to the new SA and deletes the old SA.
The block policy serves two purposes: it prevents cleartext traffic
leaks during the migration window, and for AES-GCM it prevents IV
reuse by ensuring no outgoing packets are sent under the same key.
The atomic copy of the sequence number and replay window complements
this — together they eliminate both risks during migration.
The atomic copy also serves incoming SAs, ensuring replay protection
continues without a gap across the migration.
Feature Detection¶
Userspace can probe for kernel support by sending a minimal
XFRM_MSG_MIGRATE_STATE message with a non-zero non-existent SPI:
-EINVAL: kernel predatesXFRM_MSG_MIGRATE_STATE; message type is out of range-ENOPROTOOPT: message type is known butCONFIG_XFRM_MIGRATEis not enabled-ESRCH: supported (SPI not found)
Userspace Notification on Success¶
On successful migration the kernel multicasts an
XFRM_MSG_MIGRATE_STATE message to the XFRMNLGRP_MIGRATE group.
The fixed header is struct xfrm_user_migrate_state copied from the
request, followed by the same set of netlink attributes that are
accepted as input, with the differences noted below.
Differences from the request¶
Field / Attribute |
Difference |
|---|---|
|
Contains the actual selector of the newly installed SA, not the
|
|
Present in the notification (set from the direction of the new SA) but not accepted as input — direction is immutable. |
|
Echoed back as-is. |
Attributes in the notification¶
Attribute |
Description |
|---|---|
|
UDP encapsulation template, if configured on the new SA. |
|
Hardware offload configuration, if active on the new SA. |
|
Mark on the new SA, if set. |
|
Output mark on the new SA, if set. |
|
Output mark mask, present together with |
|
Mapping maxage threshold, if non-zero. |
|
NAT keepalive interval, if non-zero. |
|
Direction of the new SA. |
Error Handling¶
If the target SA tuple (new daddr, SPI, proto, new family) is already
occupied, the operation returns -EEXIST before the migration begins.
The old SA remains intact and the operation is safe to retry after
resolving the conflict.
If the target SA is deleted before the migration completes, the operation
returns -ESRCH. No new SA is installed. Userspace should verify the
current SA state before retrying.
If the multicast notification (XFRMNLGRP_MIGRATE) fails to send,
the migration itself has already completed successfully and the new SA
is installed. The operation returns success, 0, with an extack warning,
but listeners will not receive the migration event.