diff --git a/include/cache.h b/include/cache.h index 934c3a74fa95..c5c585bacaf7 100644 --- a/include/cache.h +++ b/include/cache.h @@ -136,6 +136,7 @@ struct nft_cache { struct cache table_cache; uint32_t seqnum; uint32_t flags; + bool eintr; }; void nft_chain_cache_update(struct netlink_ctx *ctx, struct table *table, diff --git a/include/netlink.h b/include/netlink.h index d52434c72bc2..d3e828f270e1 100644 --- a/include/netlink.h +++ b/include/netlink.h @@ -85,6 +85,7 @@ struct netlink_ctx { uint32_t seqnum; struct nftnl_batch *batch; int maybe_emsgsize; + bool ignore_eintr; }; extern struct nftnl_expr *alloc_nft_expr(const char *name); diff --git a/src/cache.c b/src/cache.c index 95adee7f8ac1..9237397d2d3e 100644 --- a/src/cache.c +++ b/src/cache.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -1175,10 +1176,14 @@ bool nft_cache_needs_update(struct nft_cache *cache) return cache->flags & NFT_CACHE_UPDATE; } +/* display inconsistent ruleset after 5 seconds of retries. */ +#define MAX_RETRY_TIME 5 + int nft_cache_update(struct nft_ctx *nft, unsigned int flags, struct list_head *msgs, const struct nft_cache_filter *filter) { + struct timeval tv_start, tv_last, tv_diff; struct netlink_ctx ctx = { .list = LIST_HEAD_INIT(ctx.list), .nft = nft, @@ -1187,7 +1192,14 @@ int nft_cache_update(struct nft_ctx *nft, unsigned int flags, struct nft_cache *cache = &nft->cache; uint32_t genid, genid_stop, oldflags; int ret; + + gettimeofday(&tv_start, NULL); replay: + gettimeofday(&tv_last, NULL); + timersub(&tv_diff, &tv_last, &tv_start); + if (tv_diff.tv_sec > MAX_RETRY_TIME) + ctx.ignore_eintr = true; + ctx.seqnum = cache->seqnum++; genid = mnl_genid_get(&ctx); if (!nft_cache_needs_refresh(cache) && @@ -1223,12 +1235,16 @@ replay: genid_stop = mnl_genid_get(&ctx); if (genid != genid_stop) { - nft_cache_release(cache); - goto replay; + if (!ctx.ignore_eintr) { + nft_cache_release(cache); + goto replay; + } + cache->eintr = true; } skip: cache->genid = genid; cache->flags = flags; + return 0; } diff --git a/src/mnl.c b/src/mnl.c index 91775c41b246..f985e90c5926 100644 --- a/src/mnl.c +++ b/src/mnl.c @@ -706,8 +706,13 @@ struct nftnl_rule_list *mnl_nft_rule_dump(struct netlink_ctx *ctx, int family, } ret = nft_mnl_talk(ctx, nlh, nlh->nlmsg_len, rule_cb, nlr_list); - if (ret < 0) - goto err; + if (ret < 0) { + if (errno != EINTR) + goto err; + + if (!ctx->ignore_eintr) + goto err; + } return nlr_list; err: @@ -1029,8 +1034,13 @@ struct nftnl_chain_list *mnl_nft_chain_dump(struct netlink_ctx *ctx, } ret = nft_mnl_talk(ctx, nlh, nlh->nlmsg_len, chain_cb, nlc_list); - if (ret < 0 && errno != ENOENT) - goto err; + if (ret < 0 && errno != ENOENT) { + if (errno != EINTR) + goto err; + + if (!ctx->ignore_eintr) + goto err; + } return nlc_list; err: @@ -1174,8 +1184,13 @@ struct nftnl_table_list *mnl_nft_table_dump(struct netlink_ctx *ctx, } ret = nft_mnl_talk(ctx, nlh, nlh->nlmsg_len, table_cb, nlt_list); - if (ret < 0 && errno != ENOENT) - goto err; + if (ret < 0 && errno != ENOENT) { + if (errno != EINTR) + goto err; + + if (!ctx->ignore_eintr) + goto err; + } return nlt_list; err: @@ -1428,8 +1443,13 @@ mnl_nft_set_dump(struct netlink_ctx *ctx, int family, memory_allocation_error(); ret = nft_mnl_talk(ctx, nlh, nlh->nlmsg_len, set_cb, nls_list); - if (ret < 0 && errno != ENOENT) - goto err; + if (ret < 0 && errno != ENOENT) { + if (errno != EINTR) + goto err; + + if (!ctx->ignore_eintr) + goto err; + } return nls_list; err: @@ -1653,8 +1673,13 @@ mnl_nft_obj_dump(struct netlink_ctx *ctx, int family, memory_allocation_error(); ret = nft_mnl_talk(ctx, nlh, nlh->nlmsg_len, obj_cb, nln_list); - if (ret < 0) - goto err; + if (ret < 0) { + if (errno != EINTR) + goto err; + + if (!ctx->ignore_eintr) + goto err; + } return nln_list; err: @@ -1967,8 +1992,13 @@ mnl_nft_flowtable_dump(struct netlink_ctx *ctx, int family, memory_allocation_error(); ret = nft_mnl_talk(ctx, nlh, nlh->nlmsg_len, flowtable_cb, nln_list); - if (ret < 0 && errno != ENOENT) - goto err; + if (ret < 0 && errno != ENOENT) { + if (errno != EINTR) + goto err; + + if (!ctx->ignore_eintr) + goto err; + } return nln_list; err: diff --git a/src/rule.c b/src/rule.c index 633a5a12486d..3f984ea1fec5 100644 --- a/src/rule.c +++ b/src/rule.c @@ -2192,6 +2192,9 @@ static int do_list_ruleset(struct netlink_ctx *ctx, struct cmd *cmd) unsigned int family = cmd->handle.family; struct table *table; + if (ctx->nft->cache.eintr) + nft_print(&ctx->nft->output, "# Warning: ruleset has been updated while listing\n"); + list_for_each_entry(table, &ctx->nft->cache.table_cache.list, cache.list) { if (family != NFPROTO_UNSPEC && table->handle.family != family)