aboutsummaryrefslogtreecommitdiffstats
path: root/src/libhydra/plugins/kernel_netlink/kernel_netlink_shared.c
diff options
context:
space:
mode:
authorMartin Willi <martin@revosec.ch>2014-07-14 16:50:07 +0200
committerMartin Willi <martin@revosec.ch>2014-11-21 10:55:45 +0100
commit84f6853c42e4d9658c17f2a76e8586f1f7f8929b (patch)
tree88b6b562c3d149138961bae4548853dbb934dbc1 /src/libhydra/plugins/kernel_netlink/kernel_netlink_shared.c
parent3c7193f114e9dbb4f725aaf9e050fb132d9f2600 (diff)
downloadstrongswan-84f6853c42e4d9658c17f2a76e8586f1f7f8929b.tar.bz2
strongswan-84f6853c42e4d9658c17f2a76e8586f1f7f8929b.tar.xz
kernel-netlink: Retry netlink query while kernel returns EBUSY
If the kernel can't execute a Netlink query because a different query is already active, it returns EBUSY. As this can happen now as we support parallel queries, retry on this error condition.
Diffstat (limited to 'src/libhydra/plugins/kernel_netlink/kernel_netlink_shared.c')
-rw-r--r--src/libhydra/plugins/kernel_netlink/kernel_netlink_shared.c40
1 files changed, 37 insertions, 3 deletions
diff --git a/src/libhydra/plugins/kernel_netlink/kernel_netlink_shared.c b/src/libhydra/plugins/kernel_netlink/kernel_netlink_shared.c
index 6e1dd8cf0..9c2e34f82 100644
--- a/src/libhydra/plugins/kernel_netlink/kernel_netlink_shared.c
+++ b/src/libhydra/plugins/kernel_netlink/kernel_netlink_shared.c
@@ -211,9 +211,11 @@ CALLBACK(watch, bool,
return TRUE;
}
-METHOD(netlink_socket_t, netlink_send, status_t,
- private_netlink_socket_t *this, struct nlmsghdr *in, struct nlmsghdr **out,
- size_t *out_len)
+/**
+ * Send a netlink request, try once
+ */
+static status_t send_once(private_netlink_socket_t *this, struct nlmsghdr *in,
+ struct nlmsghdr **out, size_t *out_len)
{
struct nlmsghdr *hdr;
chunk_t result = {};
@@ -277,6 +279,38 @@ METHOD(netlink_socket_t, netlink_send, status_t,
return SUCCESS;
}
+METHOD(netlink_socket_t, netlink_send, status_t,
+ private_netlink_socket_t *this, struct nlmsghdr *in, struct nlmsghdr **out,
+ size_t *out_len)
+{
+ while (TRUE)
+ {
+ struct nlmsghdr *hdr;
+ status_t status;
+ size_t len;
+
+ status = send_once(this, in, &hdr, &len);
+ if (status != SUCCESS)
+ {
+ return status;
+ }
+ if (hdr->nlmsg_type == NLMSG_ERROR)
+ {
+ struct nlmsgerr* err;
+
+ err = NLMSG_DATA(hdr);
+ if (err->error == -EBUSY)
+ {
+ free(hdr);
+ continue;
+ }
+ }
+ *out = hdr;
+ *out_len = len;
+ return SUCCESS;
+ }
+}
+
METHOD(netlink_socket_t, netlink_send_ack, status_t,
private_netlink_socket_t *this, struct nlmsghdr *in)
{