From: Laine Stump <laine@redhat.com> This API provides a way for a libvirt client to force a guest to inject a "Gratuuitous ARP" packet into the outgoing stream of one, or all, network devices of the guest; this will be used to update the forwarding tables of any network switches in the local broadcast domain so that they will begin forarding traffic correctly in a more timely manner after network topology changes. Signed-off-by: Laine Stump <laine@redhat.com> --- include/libvirt/libvirt-domain.h | 46 ++++++++++++++++++++++ src/driver-hypervisor.h | 8 ++++ src/libvirt-domain.c | 65 ++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 5 +++ src/remote/remote_driver.c | 1 + src/remote/remote_protocol.x | 19 +++++++++- src/remote_protocol-structs | 10 +++++ 7 files changed, 153 insertions(+), 1 deletion(-) diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h index 8f07ef2156..ccc74ad6a4 100644 --- a/include/libvirt/libvirt-domain.h +++ b/include/libvirt/libvirt-domain.h @@ -9049,5 +9049,51 @@ virDomainDelThrottleGroup(virDomainPtr dom, const char *group, unsigned int flags); +/** + * VIR_DOMAIN_ANNOUNCE_INTERFACE_INITIAL: + * + * Initial delay in milliseonds before the first announce packet is + * sent. If unspecified or 0, a default value of 50 will be used. + * + * Since: 12.5.0 + */ +# define VIR_DOMAIN_ANNOUNCE_INTERFACE_INITIAL "initial" + +/** + * VIR_DOMAIN_ANNOUNCE_INTERFACE_MAX: + * + * Maximum delay in milliseonds between packets. If unspecified or 0, + * a default value of 550 will be used. + * + * Since: 12.5.0 + */ +# define VIR_DOMAIN_ANNOUNCE_INTERFACE_MAX "max" + +/** + * VIR_DOMAIN_ANNOUNCE_INTERFACE_ROUNDS: + * + * The number of packets to send. If unspecified or 0, a default value + * of 5 will be used. + * + * Since: 12.5.0 + */ +# define VIR_DOMAIN_ANNOUNCE_INTERFACE_ROUNDS "rounds" + +/** + * VIR_DOMAIN_ANNOUNCE_INTERFACE_STEP: + * + * Increment added to the delay (in milliseconds) after each packet is + * sent. If unspecified or 0, a default value of 50 will be used. + * + * Since: 12.5.0 + */ +# define VIR_DOMAIN_ANNOUNCE_INTERFACE_STEP "step" + +int +virDomainAnnounceInterface(virDomainPtr dom, + const char *device, + virTypedParameterPtr params, + int nparams, + unsigned int flags); #endif /* LIBVIRT_DOMAIN_H */ diff --git a/src/driver-hypervisor.h b/src/driver-hypervisor.h index 6a43688b0c..0add95de96 100644 --- a/src/driver-hypervisor.h +++ b/src/driver-hypervisor.h @@ -1473,6 +1473,13 @@ typedef int const char *groupname, unsigned int flags); +typedef int +(*virDrvDomainAnnounceInterface)(virDomainPtr dom, + const char *device, + virTypedParameterPtr params, + int nparams, + unsigned int flags); + typedef struct _virHypervisorDriver virHypervisorDriver; /** @@ -1750,4 +1757,5 @@ struct _virHypervisorDriver { virDrvDomainGraphicsReload domainGraphicsReload; virDrvDomainSetThrottleGroup domainSetThrottleGroup; virDrvDomainDelThrottleGroup domainDelThrottleGroup; + virDrvDomainAnnounceInterface domainAnnounceInterface; }; diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c index a4cbeb8ad4..f9ee416fe7 100644 --- a/src/libvirt-domain.c +++ b/src/libvirt-domain.c @@ -14308,3 +14308,68 @@ virDomainDelThrottleGroup(virDomainPtr dom, virDispatchError(dom->conn); return -1; } + + +/** + * virDomainAnnounceInterface: + * @dom: pointer to domain object + * @device: the interface name or mac address, or NULL to announce all interfaces + * @params: pointer to typed parameters object + * @nparams: number of parameters in @params + * @flags: currently unused, pass 0 + * + * Cause this domain to "announce" its network interfaces by injecting + * a series of "gratuitous ARP" packets into the outgoing data stream + * for the interface matching @device (or all interfaces). This should + * cause local switches to direct traffic for that MAC address + * correctly after a topology change. + * + * See VIR_DOMAIN_ANNOUNCE_INTERFACE_* for detailed descriptions of + * accepted parameters. + * + * Returns: 0 on success, + * -1 otherwise. + * + * Since: 12.5.0 + */ +int +virDomainAnnounceInterface(virDomainPtr dom, + const char *device, + virTypedParameterPtr params, + int nparams, + unsigned int flags) +{ + virConnectPtr conn; + + VIR_DEBUG("dom=%p, device='%s' params=%p nparams=%d flags=0x%x", + dom, NULLSTR(device), params, nparams, flags); + VIR_TYPED_PARAMS_DEBUG(params, nparams); + + virResetLastError(); + + virCheckDomainReturn(dom, -1); + + conn = dom->conn; + + virCheckReadOnlyGoto(conn->flags, error); + if (nparams != 0) + virCheckNonNullArgGoto(params, error); + else + virCheckNullArgGoto(params, error); + + if (virTypedParameterValidateSet(conn, params, nparams) < 0) + goto error; + + if (conn->driver->domainAnnounceInterface) { + int ret = conn->driver->domainAnnounceInterface(dom, device, params, nparams, flags); + if (ret < 0) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(conn); + return -1; +} diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index c506acd2ed..64ed641b7f 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -956,4 +956,9 @@ LIBVIRT_11.2.0 { virDomainDelThrottleGroup; } LIBVIRT_10.2.0; +LIBVIRT_12.5.0 { + global: + virDomainAnnounceInterface; +} LIBVIRT_11.2.0; + # .... define new API here using predicted next version number .... diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 873e3d173c..16e82031e9 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -8004,6 +8004,7 @@ static virHypervisorDriver hypervisor_driver = { .domainGraphicsReload = remoteDomainGraphicsReload, /* 10.2.0 */ .domainSetThrottleGroup = remoteDomainSetThrottleGroup, /* 11.2.0 */ .domainDelThrottleGroup = remoteDomainDelThrottleGroup, /* 11.2.0 */ + .domainAnnounceInterface = remoteDomainAnnounceInterface, /* 12.5.0 */ }; static virNetworkDriver network_driver = { diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 4adba82f6d..32185fde2f 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -293,6 +293,10 @@ const REMOTE_DOMAIN_AUTHORIZED_SSH_KEYS_MAX = 2048; /* Upper limit on number of messages */ const REMOTE_DOMAIN_MESSAGES_MAX = 2048; +/* + * Upper limit on number of domain announce interface parameters + */ +const REMOTE_DOMAIN_ANNOUNCE_INTERFACE_PARAMS_MAX = 16; /* UUID. VIR_UUID_BUFLEN definition comes from libvirt.h */ typedef opaque remote_uuid[VIR_UUID_BUFLEN]; @@ -4023,6 +4027,13 @@ struct remote_domain_event_callback_channel_lifecycle_msg { int reason; }; +struct remote_domain_announce_interface_args { + remote_nonnull_domain dom; + remote_string device; + remote_typed_param params<REMOTE_DOMAIN_ANNOUNCE_INTERFACE_PARAMS_MAX>; + unsigned int flags; +}; + /*----- Protocol. -----*/ /* Define the program number, protocol version and procedure numbers here. */ @@ -7146,5 +7157,11 @@ enum remote_procedure { * @generate: both * @acl: none */ - REMOTE_PROC_DOMAIN_EVENT_CALLBACK_CHANNEL_LIFECYCLE = 455 + REMOTE_PROC_DOMAIN_EVENT_CALLBACK_CHANNEL_LIFECYCLE = 455, + + /** + * @generate: both + * @acl: domain:write + */ + REMOTE_PROC_DOMAIN_ANNOUNCE_INTERFACE = 456 }; diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index dd297bffff..6093a85c98 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -3349,6 +3349,15 @@ struct remote_domain_event_callback_channel_lifecycle_msg { int state; int reason; }; +struct remote_domain_announce_interface_args { + remote_nonnull_domain dom; + remote_string device; + struct { + u_int params_len; + remote_typed_param * params_val; + } params; + u_int flags; +}; enum remote_procedure { REMOTE_PROC_CONNECT_OPEN = 1, REMOTE_PROC_CONNECT_CLOSE = 2, @@ -3805,4 +3814,5 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_EVENT_NIC_MAC_CHANGE = 453, REMOTE_PROC_DOMAIN_EVENT_VCPU_REMOVED = 454, REMOTE_PROC_DOMAIN_EVENT_CALLBACK_CHANNEL_LIFECYCLE = 455, + REMOTE_PROC_DOMAIN_ANNOUNCE_INTERFACE = 456, }; -- 2.54.0