From 22c8af6991eab12a87fec4f06559e1d7ea3826f1 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Fri, 14 Dec 2012 12:42:48 +0100 Subject: api: add CTA_LABEL_MASK attribute handling allows to set/clear only a subset of the in-kernel label set, e.g. "set bit 1 and do not change any others". Signed-off-by: Florian Westphal --- examples/nfct-mnl-set-label.c | 8 +++++++ include/internal/object.h | 1 + .../libnetfilter_conntrack.h | 1 + .../linux_nfnetlink_conntrack.h | 1 + qa/test_api.c | 25 ++++++++++++++++------ src/conntrack/api.c | 2 ++ src/conntrack/build_mnl.c | 6 ++++++ src/conntrack/copy.c | 9 ++++++++ src/conntrack/getter.c | 6 ++++++ src/conntrack/parse_mnl.c | 1 + src/conntrack/setter.c | 21 +++++++++++++----- 11 files changed, 70 insertions(+), 11 deletions(-) diff --git a/examples/nfct-mnl-set-label.c b/examples/nfct-mnl-set-label.c index 9e7fbf6..c52b267 100644 --- a/examples/nfct-mnl-set-label.c +++ b/examples/nfct-mnl-set-label.c @@ -35,6 +35,14 @@ static void set_label(struct nf_conntrack *ct, struct callback_args *cbargs) nfct_bitmask_set_bit(b, bit); nfct_set_attr(ct, ATTR_CONNLABELS, b); + if (bit >= 0) { + b = nfct_bitmask_new(bit); + if (b) { + nfct_bitmask_set_bit(b, bit); + nfct_set_attr(ct, ATTR_CONNLABELS_MASK, b); + } + } + cbargs->seq++; nlh = mnl_nlmsg_put_header(buf); diff --git a/include/internal/object.h b/include/internal/object.h index bbb038a..540ad0d 100644 --- a/include/internal/object.h +++ b/include/internal/object.h @@ -191,6 +191,7 @@ struct nf_conntrack { size_t helper_info_len; struct nfct_bitmask *connlabels; + struct nfct_bitmask *connlabels_mask; }; /* diff --git a/include/libnetfilter_conntrack/libnetfilter_conntrack.h b/include/libnetfilter_conntrack/libnetfilter_conntrack.h index c209184..39dc24c 100644 --- a/include/libnetfilter_conntrack/libnetfilter_conntrack.h +++ b/include/libnetfilter_conntrack/libnetfilter_conntrack.h @@ -134,6 +134,7 @@ enum nf_conntrack_attr { ATTR_TIMESTAMP_STOP = 64, /* u64 bits, linux >= 2.6.38 */ ATTR_HELPER_INFO, /* variable length */ ATTR_CONNLABELS, /* variable length */ + ATTR_CONNLABELS_MASK, /* variable length */ ATTR_MAX }; diff --git a/include/libnetfilter_conntrack/linux_nfnetlink_conntrack.h b/include/libnetfilter_conntrack/linux_nfnetlink_conntrack.h index 3c69ba9..5812595 100644 --- a/include/libnetfilter_conntrack/linux_nfnetlink_conntrack.h +++ b/include/libnetfilter_conntrack/linux_nfnetlink_conntrack.h @@ -54,6 +54,7 @@ enum ctattr_type { CTA_TIMESTAMP, CTA_MARK_MASK, CTA_LABELS, + CTA_LABELS_MASK, __CTA_MAX }; #define CTA_MAX (__CTA_MAX - 1) diff --git a/qa/test_api.c b/qa/test_api.c index 399afdc..499d01f 100644 --- a/qa/test_api.c +++ b/qa/test_api.c @@ -91,7 +91,7 @@ int main(void) char data[256]; const char *val; int status; - struct nfct_bitmask *b; + struct nfct_bitmask *b, *b2; srand(time(NULL)); @@ -121,14 +121,23 @@ int main(void) eval_sigterm(status); } + b = nfct_bitmask_new(rand() & 0xffff); + assert(b); + b2 = nfct_bitmask_new(rand() & 0xffff); + assert(b2); + for (i=0; ihelper_info); if (ct->connlabels) nfct_bitmask_destroy(ct->connlabels); + if (ct->connlabels_mask) + nfct_bitmask_destroy(ct->connlabels_mask); free(ct); ct = NULL; /* bugtrap */ } diff --git a/src/conntrack/build_mnl.c b/src/conntrack/build_mnl.c index a666e01..a37bd73 100644 --- a/src/conntrack/build_mnl.c +++ b/src/conntrack/build_mnl.c @@ -386,6 +386,12 @@ nfct_build_labels(struct nlmsghdr *nlh, const struct nf_conntrack *ct) struct nfct_bitmask *b = ct->connlabels; unsigned int size = b->words * sizeof(b->bits[0]); mnl_attr_put(nlh, CTA_LABELS, size, b->bits); + + if (test_bit(ATTR_CONNLABELS_MASK, ct->head.set)) { + b = ct->connlabels_mask; + if (size == (b->words * sizeof(b->bits[0]))) + mnl_attr_put(nlh, CTA_LABELS_MASK, size, b->bits); + } } int diff --git a/src/conntrack/copy.c b/src/conntrack/copy.c index 9cb567c..5915c16 100644 --- a/src/conntrack/copy.c +++ b/src/conntrack/copy.c @@ -466,6 +466,12 @@ static void copy_attr_connlabels(struct nf_conntrack *dest, dest->connlabels = do_copy_attr_connlabels(dest->connlabels, orig->connlabels); } +static void copy_attr_connlabels_mask(struct nf_conntrack *dest, + const struct nf_conntrack *orig) +{ + dest->connlabels_mask = do_copy_attr_connlabels(dest->connlabels_mask, orig->connlabels_mask); +} + const copy_attr copy_attr_array[ATTR_MAX] = { [ATTR_ORIG_IPV4_SRC] = copy_attr_orig_ipv4_src, [ATTR_ORIG_IPV4_DST] = copy_attr_orig_ipv4_dst, @@ -534,6 +540,7 @@ const copy_attr copy_attr_array[ATTR_MAX] = { [ATTR_TIMESTAMP_STOP] = copy_attr_timestamp_stop, [ATTR_HELPER_INFO] = copy_attr_help_info, [ATTR_CONNLABELS] = copy_attr_connlabels, + [ATTR_CONNLABELS_MASK] = copy_attr_connlabels_mask, }; /* this is used by nfct_copy() with the NFCT_CP_OVERRIDE flag set. */ @@ -544,8 +551,10 @@ void __copy_fast(struct nf_conntrack *ct1, const struct nf_conntrack *ct2) ct1->secctx = NULL; ct1->helper_info = NULL; ct1->connlabels = NULL; + ct1->connlabels_mask = NULL; copy_attr_secctx(ct1, ct2); copy_attr_help_info(ct1, ct2); copy_attr_connlabels(ct1, ct2); + copy_attr_connlabels_mask(ct1, ct2); } diff --git a/src/conntrack/getter.c b/src/conntrack/getter.c index 53c9e0e..ae546ee 100644 --- a/src/conntrack/getter.c +++ b/src/conntrack/getter.c @@ -344,6 +344,11 @@ static const void *get_attr_connlabels(const struct nf_conntrack *ct) return ct->connlabels; } +static const void *get_attr_connlabels_mask(const struct nf_conntrack *ct) +{ + return ct->connlabels_mask; +} + const get_attr get_attr_array[ATTR_MAX] = { [ATTR_ORIG_IPV4_SRC] = get_attr_orig_ipv4_src, [ATTR_ORIG_IPV4_DST] = get_attr_orig_ipv4_dst, @@ -412,4 +417,5 @@ const get_attr get_attr_array[ATTR_MAX] = { [ATTR_TIMESTAMP_STOP] = get_attr_timestamp_stop, [ATTR_HELPER_INFO] = get_attr_helper_info, [ATTR_CONNLABELS] = get_attr_connlabels, + [ATTR_CONNLABELS_MASK] = get_attr_connlabels_mask, }; diff --git a/src/conntrack/parse_mnl.c b/src/conntrack/parse_mnl.c index a4272f9..6984e78 100644 --- a/src/conntrack/parse_mnl.c +++ b/src/conntrack/parse_mnl.c @@ -958,6 +958,7 @@ nfct_payload_parse(const void *payload, size_t payload_len, if (nfct_parse_labels(tb[CTA_LABELS], ct) < 0) return -1; } + /* CTA_LABELS_MASK: never sent by kernel */ return 0; } diff --git a/src/conntrack/setter.c b/src/conntrack/setter.c index 8879f02..4dda6c9 100644 --- a/src/conntrack/setter.c +++ b/src/conntrack/setter.c @@ -421,16 +421,26 @@ retry: } static void -set_attr_connlabels(struct nf_conntrack *ct, const void *value, size_t len) +do_set_attr_connlabels(struct nfct_bitmask *current, const void *value) { - if (ct->connlabels == value) - return; + if (current && current != value) + nfct_bitmask_destroy(current); +} - if (ct->connlabels) - nfct_bitmask_destroy(ct->connlabels); +static void +set_attr_connlabels(struct nf_conntrack *ct, const void *value, size_t len) +{ + do_set_attr_connlabels(ct->connlabels, value); ct->connlabels = (void *) value; } +static void +set_attr_connlabels_mask(struct nf_conntrack *ct, const void *value, size_t len) +{ + do_set_attr_connlabels(ct->connlabels_mask, value); + ct->connlabels_mask = (void *) value; +} + static void set_attr_do_nothing(struct nf_conntrack *ct, const void *value, size_t len) {} @@ -502,4 +512,5 @@ const set_attr set_attr_array[ATTR_MAX] = { [ATTR_TIMESTAMP_STOP] = set_attr_do_nothing, [ATTR_HELPER_INFO] = set_attr_helper_info, [ATTR_CONNLABELS] = set_attr_connlabels, + [ATTR_CONNLABELS_MASK] = set_attr_connlabels_mask, }; -- cgit v1.2.3