summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Graf <tgraf@suug.ch>2011-07-14 10:51:49 +0200
committerThomas Graf <tgraf@suug.ch>2011-07-14 10:51:49 +0200
commit21d52eabba00089e3319575616a429fb75309cb7 (patch)
tree90a89e99e2d631d2e6ad3ada665d9f16cd6d5361
parentdba0e91a09dcd928ebc4e8ce4db8cc6cd471d8f9 (diff)
downloadlibnl-21d52eabba00089e3319575616a429fb75309cb7.tar.gz
Support for NLM_F_INTR
Check if a dump was interrupted and needs to be redone
-rw-r--r--include/linux/netlink.h1
-rw-r--r--include/netlink/errno.h3
-rw-r--r--include/netlink/handlers.h2
-rw-r--r--lib/cache.c14
-rw-r--r--lib/error.c1
-rw-r--r--lib/nl.c18
6 files changed, 35 insertions, 4 deletions
diff --git a/include/linux/netlink.h b/include/linux/netlink.h
index 0abcdaf..3925254 100644
--- a/include/linux/netlink.h
+++ b/include/linux/netlink.h
@@ -49,6 +49,7 @@ struct nlmsghdr {
#define NLM_F_MULTI 2 /* Multipart message, terminated by NLMSG_DONE */
#define NLM_F_ACK 4 /* Reply with ack, with zero or error code */
#define NLM_F_ECHO 8 /* Echo this request */
+#define NLM_F_DUMP_INTR 16 /* Dump was inconsistent due to sequence change */
/* Modifiers to GET request */
#define NLM_F_ROOT 0x100 /* specify tree root */
diff --git a/include/netlink/errno.h b/include/netlink/errno.h
index 267a745..f8b5130 100644
--- a/include/netlink/errno.h
+++ b/include/netlink/errno.h
@@ -49,8 +49,9 @@ extern "C" {
#define NLE_PARSE_ERR 30
#define NLE_NODEV 31
#define NLE_IMMUTABLE 32
+#define NLE_DUMP_INTR 33
-#define NLE_MAX NLE_IMMUTABLE
+#define NLE_MAX NLE_DUMP_INTR
extern const char * nl_geterror(int);
extern void nl_perror(int, const char *);
diff --git a/include/netlink/handlers.h b/include/netlink/handlers.h
index f373f58..dfa2809 100644
--- a/include/netlink/handlers.h
+++ b/include/netlink/handlers.h
@@ -108,6 +108,8 @@ enum nl_cb_type {
NL_CB_SEQ_CHECK,
/** Sending of an acknowledge message has been requested */
NL_CB_SEND_ACK,
+ /** Flag NLM_F_DUMP_INTR is set in message */
+ NL_CB_DUMP_INTR,
__NL_CB_TYPE_MAX,
};
diff --git a/lib/cache.c b/lib/cache.c
index 7afa42e..3b453a9 100644
--- a/lib/cache.c
+++ b/lib/cache.c
@@ -677,6 +677,7 @@ int nl_cache_resync(struct nl_sock *sk, struct nl_cache *cache,
NL_DBG(1, "Resyncing cache %p <%s>...\n", cache, nl_cache_name(cache));
+restart:
/* Mark all objects so we can see if some of them are obsolete */
nl_cache_mark_all(cache);
@@ -685,7 +686,9 @@ int nl_cache_resync(struct nl_sock *sk, struct nl_cache *cache,
goto errout;
err = __cache_pickup(sk, cache, &p);
- if (err < 0)
+ if (err == -NLE_DUMP_INTR)
+ goto restart;
+ else if (err < 0)
goto errout;
nl_list_for_each_entry_safe(obj, next, &cache->c_items, ce_list) {
@@ -770,6 +773,7 @@ int nl_cache_refill(struct nl_sock *sk, struct nl_cache *cache)
{
int err;
+restart:
err = nl_cache_request_full_dump(sk, cache);
if (err < 0)
return err;
@@ -778,7 +782,13 @@ int nl_cache_refill(struct nl_sock *sk, struct nl_cache *cache)
cache, nl_cache_name(cache));
nl_cache_clear(cache);
- return nl_cache_pickup(sk, cache);
+ err = nl_cache_pickup(sk, cache);
+ if (err == -NLE_DUMP_INTR) {
+ fprintf(stderr, "dump interrupted, restarting!\n");
+ goto restart;
+ }
+
+ return err;
}
/** @} */
diff --git a/lib/error.c b/lib/error.c
index 8934020..e8ee474 100644
--- a/lib/error.c
+++ b/lib/error.c
@@ -46,6 +46,7 @@ static const char *errmsg[NLE_MAX+1] = {
[NLE_PARSE_ERR] = "Unable to parse object",
[NLE_NODEV] = "No such device",
[NLE_IMMUTABLE] = "Immutable attribute",
+[NLE_DUMP_INTR] = "Dump inconsistency detected, interrupted",
};
/**
diff --git a/lib/nl.c b/lib/nl.c
index fc70374..cc450c7 100644
--- a/lib/nl.c
+++ b/lib/nl.c
@@ -559,7 +559,7 @@ do { \
static int recvmsgs(struct nl_sock *sk, struct nl_cb *cb)
{
- int n, err = 0, multipart = 0;
+ int n, err = 0, multipart = 0, interrupted = 0;
unsigned char *buf = NULL;
struct nlmsghdr *hdr;
struct sockaddr_nl nla = {0};
@@ -631,6 +631,19 @@ continue_reading:
if (hdr->nlmsg_flags & NLM_F_MULTI)
multipart = 1;
+
+ if (hdr->nlmsg_flags & NLM_F_DUMP_INTR) {
+ if (cb->cb_set[NL_CB_DUMP_INTR])
+ NL_CB_CALL(cb, NL_CB_DUMP_INTR, msg);
+ else {
+ /*
+ * We have to continue reading to clear
+ * all messages until a NLMSG_DONE is
+ * received and report the inconsistency.
+ */
+ interrupted = 1;
+ }
+ }
/* Other side wishes to see an ack for this message */
if (hdr->nlmsg_flags & NLM_F_ACK) {
@@ -738,6 +751,9 @@ out:
free(buf);
free(creds);
+ if (interrupted)
+ err = -NLE_DUMP_INTR;
+
return err;
}