@@ -105,6 +105,59 @@ struct ct_tmpl {
static struct ct_tmpl *cur_tmpl;
+
+struct ct_ctx {
+ struct nfct_handle *cth;
+ struct nfct_handle *ith;
+ uint8_t cur_subsys_id;
+ unsigned cur_subscriptions;
+} ct_ctx;
+
+static void ct_ctx_term(void)
+{
+ if (ct_ctx.cth)
+ nfct_close(ct_ctx.cth);
+ if (ct_ctx.ith)
+ nfct_close(ct_ctx.ith);
+ memset(&ct_ctx, 0, sizeof(ct_ctx));
+}
+
+static inline struct nfct_handle* _ct_ctx_get(struct nfct_handle **ph,
+ uint8_t subsys_id, unsigned subscriptions)
+{
+ struct nfct_handle *h = *ph;
+
+ if (!ct_ctx.cur_subsys_id) {
+ ct_ctx.cur_subsys_id = subsys_id;
+ ct_ctx.cur_subscriptions = subscriptions;
+ } else if (ct_ctx.cur_subsys_id != subsys_id
+ || ct_ctx.cur_subscriptions != subscriptions) {
+ exit_error(OTHER_PROBLEM, "handler parameters mismatch!");
+ }
+
+ if (!h) {
+ h = nfct_open(subsys_id, subscriptions);
+ if (!h)
+ exit_error(OTHER_PROBLEM, "Can't open handler");
+ *ph = h;
+ }
+
+ return h;
+}
+
+static struct nfct_handle* ct_ctx_get_cth(
+ uint8_t subsys_id, unsigned subscriptions)
+{
+ return _ct_ctx_get(&ct_ctx.cth, subsys_id, subscriptions);
+}
+
+static struct nfct_handle* ct_ctx_get_ith(
+ uint8_t subsys_id, unsigned subscriptions)
+{
+ return _ct_ctx_get(&ct_ctx.ith, subsys_id, subscriptions);
+}
+
+
struct ct_cmd {
struct list_head list;
unsigned int command;
@@ -605,7 +658,6 @@ static const char usage_parameters[] =
#define OPTION_OFFSET 256
-static struct nfct_handle *cth, *ith;
static struct option *opts = original_opts;
static unsigned int global_option_offset = 0;
@@ -1739,7 +1791,7 @@ exp_event_sighandler(int s)
fprintf(stderr, "%s v%s (conntrack-tools): ", PROGNAME, VERSION);
fprintf(stderr, "%d expectation events have been shown.\n", counter);
- nfct_close(cth);
+ ct_ctx_term();
exit(0);
}
@@ -2046,7 +2098,7 @@ static int delete_cb(enum nf_conntrack_msg_type type,
if (nfct_filter(cmd, ct, cur_tmpl))
return NFCT_CB_CONTINUE;
- res = nfct_query(ith, NFCT_Q_DESTROY, ct);
+ res = nfct_query(ct_ctx.ith, NFCT_Q_DESTROY, ct);
if (res < 0)
exit_error(OTHER_PROBLEM,
"Operation failed: %s",
@@ -2230,19 +2282,19 @@ static int update_cb(enum nf_conntrack_msg_type type,
return NFCT_CB_CONTINUE;
}
- res = nfct_query(ith, NFCT_Q_UPDATE, tmp);
+ res = nfct_query(ct_ctx.ith, NFCT_Q_UPDATE, tmp);
if (res < 0)
fprintf(stderr,
"Operation failed: %s\n",
err2str(errno, CT_UPDATE));
- nfct_callback_register(ith, NFCT_T_ALL, print_cb, NULL);
+ nfct_callback_register(ct_ctx.ith, NFCT_T_ALL, print_cb, NULL);
- res = nfct_query(ith, NFCT_Q_GET, tmp);
+ res = nfct_query(ct_ctx.ith, NFCT_Q_GET, tmp);
if (res < 0) {
nfct_destroy(tmp);
/* the entry has vanish in middle of the update */
if (errno == ENOENT) {
- nfct_callback_unregister(ith);
+ nfct_callback_unregister(ct_ctx.ith);
return NFCT_CB_CONTINUE;
}
exit_error(OTHER_PROBLEM,
@@ -2250,7 +2302,7 @@ static int update_cb(enum nf_conntrack_msg_type type,
err2str(errno, CT_UPDATE));
}
nfct_destroy(tmp);
- nfct_callback_unregister(ith);
+ nfct_callback_unregister(ct_ctx.ith);
counter++;
@@ -3178,6 +3230,7 @@ static void do_parse(struct ct_cmd *ct_cmd, int argc, char *argv[])
static int do_command_ct(const char *progname, struct ct_cmd *cmd)
{
+ struct nfct_handle *cth;
struct nfct_filter_dump *filter_dump;
int res = 0;
@@ -3205,9 +3258,7 @@ static int do_command_ct(const char *progname, struct ct_cmd *cmd)
break;
}
- cth = nfct_open(CONNTRACK, 0);
- if (!cth)
- exit_error(OTHER_PROBLEM, "Can't open handler");
+ cth = ct_ctx_get_cth(CONNTRACK, 0);
if (cmd->options & CT_COMPARISON &&
cmd->options & CT_OPT_ZERO)
@@ -3248,17 +3299,15 @@ static int do_command_ct(const char *progname, struct ct_cmd *cmd)
fflush(stdout);
}
- nfct_close(cth);
break;
case EXP_LIST:
- cth = nfct_open(EXPECT, 0);
+ cth = ct_ctx_get_cth(EXPECT, 0);
if (!cth)
exit_error(OTHER_PROBLEM, "Can't open handler");
nfexp_callback_register(cth, NFCT_T_ALL, dump_exp_cb, NULL);
res = nfexp_query(cth, NFCT_Q_DUMP, &cmd->family);
- nfct_close(cth);
if (dump_xml_header_done == 0) {
printf("</expect>\n");
@@ -3279,14 +3328,11 @@ static int do_command_ct(const char *progname, struct ct_cmd *cmd)
nfct_set_attr(cmd->tmpl.ct, ATTR_CONNLABELS,
xnfct_bitmask_clone(cmd->tmpl.label_modify));
- cth = nfct_open(CONNTRACK, 0);
- if (!cth)
- exit_error(OTHER_PROBLEM, "Can't open handler");
+ cth = ct_ctx_get_cth(CONNTRACK, 0);
res = nfct_query(cth, NFCT_Q_CREATE, cmd->tmpl.ct);
if (res != -1)
counter++;
- nfct_close(cth);
break;
case EXP_CREATE:
@@ -3294,35 +3340,41 @@ static int do_command_ct(const char *progname, struct ct_cmd *cmd)
nfexp_set_attr(cmd->tmpl.exp, ATTR_EXP_EXPECTED, cmd->tmpl.exptuple);
nfexp_set_attr(cmd->tmpl.exp, ATTR_EXP_MASK, cmd->tmpl.mask);
- cth = nfct_open(EXPECT, 0);
- if (!cth)
- exit_error(OTHER_PROBLEM, "Can't open handler");
+ cth = ct_ctx_get_cth(EXPECT, 0);
res = nfexp_query(cth, NFCT_Q_CREATE, cmd->tmpl.exp);
- nfct_close(cth);
break;
case CT_UPDATE:
- cth = nfct_open(CONNTRACK, 0);
- /* internal handler for delete_cb, otherwise we hit EILSEQ */
- ith = nfct_open(CONNTRACK, 0);
- if (!cth || !ith)
- exit_error(OTHER_PROBLEM, "Can't open handler");
+ cth = ct_ctx_get_cth(CONNTRACK, 0);
+ /*
+ * Internal handler for update_cb, otherwise we hit EILSEQ.
+ *
+ * Don't need a return value here, just need it to be initialized
+ * to be used in the update_cb.
+ * In case the ith handle creation fails, the ct_ctx_get_ith will do
+ * exit_error internally.
+ */
+ ct_ctx_get_ith(CONNTRACK, 0);
nfct_filter_init(cmd);
nfct_callback_register(cth, NFCT_T_ALL, update_cb, cmd);
res = nfct_query(cth, NFCT_Q_DUMP, &cmd->family);
- nfct_close(ith);
- nfct_close(cth);
break;
case CT_DELETE:
- cth = nfct_open(CONNTRACK, 0);
- ith = nfct_open(CONNTRACK, 0);
- if (!cth || !ith)
- exit_error(OTHER_PROBLEM, "Can't open handler");
+ cth = ct_ctx_get_cth(CONNTRACK, 0);
+ /*
+ * Internal handler for delete_cb, otherwise we hit EILSEQ.
+ *
+ * Don't need a return value here, just need it to be initialized
+ * to be used in the delete_cb.
+ * In case the ith handle creation fails, the ct_ctx_get_ith will do
+ * exit_error internally.
+ */
+ ct_ctx_get_ith(CONNTRACK, 0);
nfct_filter_init(cmd);
@@ -3345,59 +3397,42 @@ static int do_command_ct(const char *progname, struct ct_cmd *cmd)
nfct_filter_dump_destroy(filter_dump);
- nfct_close(ith);
- nfct_close(cth);
break;
case EXP_DELETE:
nfexp_set_attr(cmd->tmpl.exp, ATTR_EXP_EXPECTED, cmd->tmpl.ct);
- cth = nfct_open(EXPECT, 0);
- if (!cth)
- exit_error(OTHER_PROBLEM, "Can't open handler");
+ cth = ct_ctx_get_cth(EXPECT, 0);
res = nfexp_query(cth, NFCT_Q_DESTROY, cmd->tmpl.exp);
- nfct_close(cth);
break;
case CT_GET:
- cth = nfct_open(CONNTRACK, 0);
- if (!cth)
- exit_error(OTHER_PROBLEM, "Can't open handler");
+ cth = ct_ctx_get_cth(CONNTRACK, 0);
nfct_callback_register(cth, NFCT_T_ALL, dump_cb, cmd);
res = nfct_query(cth, NFCT_Q_GET, cmd->tmpl.ct);
- nfct_close(cth);
break;
case EXP_GET:
nfexp_set_attr(cmd->tmpl.exp, ATTR_EXP_MASTER, cmd->tmpl.ct);
- cth = nfct_open(EXPECT, 0);
- if (!cth)
- exit_error(OTHER_PROBLEM, "Can't open handler");
+ cth = ct_ctx_get_cth(EXPECT, 0);
nfexp_callback_register(cth, NFCT_T_ALL, dump_exp_cb, NULL);
res = nfexp_query(cth, NFCT_Q_GET, cmd->tmpl.exp);
- nfct_close(cth);
break;
case CT_FLUSH:
- cth = nfct_open(CONNTRACK, 0);
- if (!cth)
- exit_error(OTHER_PROBLEM, "Can't open handler");
+ cth = ct_ctx_get_cth(CONNTRACK, 0);
res = nfct_query(cth, NFCT_Q_FLUSH_FILTER, &cmd->family);
- nfct_close(cth);
fprintf(stderr, "%s v%s (conntrack-tools): ",PROGNAME,VERSION);
fprintf(stderr,"connection tracking table has been emptied.\n");
break;
case EXP_FLUSH:
- cth = nfct_open(EXPECT, 0);
- if (!cth)
- exit_error(OTHER_PROBLEM, "Can't open handler");
+ cth = ct_ctx_get_cth(EXPECT, 0);
res = nfexp_query(cth, NFCT_Q_FLUSH, &cmd->family);
- nfct_close(cth);
fprintf(stderr, "%s v%s (conntrack-tools): ",PROGNAME,VERSION);
fprintf(stderr,"expectation table has been emptied.\n");
break;
@@ -3486,21 +3521,18 @@ static int do_command_ct(const char *progname, struct ct_cmd *cmd)
if (cmd->event_mask & CT_EVENT_F_DEL)
nl_events |= NF_NETLINK_CONNTRACK_EXP_DESTROY;
- cth = nfct_open(CONNTRACK, nl_events);
+ cth = ct_ctx_get_cth(CONNTRACK, nl_events);
} else {
- cth = nfct_open(EXPECT,
+ cth = ct_ctx_get_cth(EXPECT,
NF_NETLINK_CONNTRACK_EXP_NEW |
NF_NETLINK_CONNTRACK_EXP_UPDATE |
NF_NETLINK_CONNTRACK_EXP_DESTROY);
}
- if (!cth)
- exit_error(OTHER_PROBLEM, "Can't open handler");
signal(SIGINT, exp_event_sighandler);
signal(SIGTERM, exp_event_sighandler);
nfexp_callback_register(cth, NFCT_T_ALL, event_exp_cb, NULL);
res = nfexp_catch(cth);
- nfct_close(cth);
break;
case CT_COUNT:
/* If we fail with netlink, fall back to /proc to ensure
@@ -3538,13 +3570,9 @@ try_proc_count:
break;
}
case EXP_COUNT:
- cth = nfct_open(EXPECT, 0);
- if (!cth)
- exit_error(OTHER_PROBLEM, "Can't open handler");
-
+ cth = ct_ctx_get_cth(EXPECT, 0);
nfexp_callback_register(cth, NFCT_T_ALL, count_exp_cb, NULL);
res = nfexp_query(cth, NFCT_Q_DUMP, &cmd->family);
- nfct_close(cth);
printf("%d\n", counter);
break;
case CT_STATS:
@@ -3840,5 +3868,7 @@ int main(int argc, char *argv[])
free(cmd);
}
+ ct_ctx_term();
+
return res < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
For bulk ct entry loads (with -R option) reusing the same nftc handle for all entries results in ~two-time reduction of entries creation time. This becomes signifficant when loading tens of thouthand of entries. E.g. in the tests performed with the tests/conntrack/bulk-load-stress.sh the time used for loading of 131070 ct entries (2 * 0xffff) was 1.05s when this single nfct handle adjustment and 1.88s w/o it . Signed-off-by: Mikhail Sennikovsky <mikhail.sennikovskii@ionos.com> --- src/conntrack.c | 160 ++++++++++++++++++++++++++++-------------------- 1 file changed, 95 insertions(+), 65 deletions(-)