diff options
author | Martin Willi <martin@revosec.ch> | 2014-07-14 16:50:07 +0200 |
---|---|---|
committer | Martin Willi <martin@revosec.ch> | 2014-11-21 10:55:45 +0100 |
commit | 84f6853c42e4d9658c17f2a76e8586f1f7f8929b (patch) | |
tree | 88b6b562c3d149138961bae4548853dbb934dbc1 /src/libhydra/plugins/kernel_netlink/kernel_netlink_shared.c | |
parent | 3c7193f114e9dbb4f725aaf9e050fb132d9f2600 (diff) | |
download | strongswan-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.c | 40 |
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) { |