From patchwork Wed Jan 23 22:38:18 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Westphal X-Patchwork-Id: 215062 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 499312C0089 for ; Thu, 24 Jan 2013 09:42:50 +1100 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752267Ab3AWWmt (ORCPT ); Wed, 23 Jan 2013 17:42:49 -0500 Received: from Chamillionaire.breakpoint.cc ([80.244.247.6]:34226 "EHLO Chamillionaire.breakpoint.cc" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752217Ab3AWWms (ORCPT ); Wed, 23 Jan 2013 17:42:48 -0500 Received: from fw by Chamillionaire.breakpoint.cc with local (Exim 4.72) (envelope-from ) id 1Ty91r-0005X7-L4; Wed, 23 Jan 2013 23:42:47 +0100 From: Florian Westphal To: Cc: Florian Westphal Subject: [PATCH 1/4] api: add nfct_bitmask object Date: Wed, 23 Jan 2013 23:38:18 +0100 Message-Id: <1358980701-3747-2-git-send-email-fw@strlen.de> X-Mailer: git-send-email 1.7.8.6 In-Reply-To: <1358980701-3747-1-git-send-email-fw@strlen.de> References: <1358980701-3747-1-git-send-email-fw@strlen.de> Sender: netfilter-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org In order to use generic getter/setter API with upcoming conntrack label extension, add helper functions to set/test/unset bits in a vector of arbitrary size. Conntrack labels will then be encoded via nfct_bitmask object. Original idea from Pablo Neira Ayuso. Signed-off-by: Florian Westphal --- include/internal/bitops.h | 2 + include/internal/object.h | 8 ++ .../libnetfilter_conntrack.h | 12 ++ qa/test_api.c | 54 +++++++++ src/conntrack/api.c | 119 ++++++++++++++++++++ 5 files changed, 195 insertions(+), 0 deletions(-) diff --git a/include/internal/bitops.h b/include/internal/bitops.h index 7ae566b..aefff0e 100644 --- a/include/internal/bitops.h +++ b/include/internal/bitops.h @@ -73,4 +73,6 @@ test_bitmask_u32_or(const uint32_t *buf1, const uint32_t *buf2, int len) return 0; } +#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) + #endif diff --git a/include/internal/object.h b/include/internal/object.h index 443e800..609265d 100644 --- a/include/internal/object.h +++ b/include/internal/object.h @@ -297,4 +297,12 @@ struct nf_expect { u_int32_t set[1]; }; +/* + * bitmask object + */ +struct nfct_bitmask { + unsigned int words; + uint32_t bits[]; +}; + #endif diff --git a/include/libnetfilter_conntrack/libnetfilter_conntrack.h b/include/libnetfilter_conntrack/libnetfilter_conntrack.h index 12f61d1..90290b8 100644 --- a/include/libnetfilter_conntrack/libnetfilter_conntrack.h +++ b/include/libnetfilter_conntrack/libnetfilter_conntrack.h @@ -273,6 +273,18 @@ enum { NFCT_CB_STOLEN = 2, /* like continue, but ct is not freed */ }; +/* bitmask setter/getter */ +struct nfct_bitmask; + +struct nfct_bitmask *nfct_bitmask_new(unsigned int maxbit); +struct nfct_bitmask *nfct_bitmask_clone(const struct nfct_bitmask *); +unsigned int nfct_bitmask_maxbit(const struct nfct_bitmask *); + +void nfct_bitmask_set_bit(struct nfct_bitmask *, unsigned int bit); +int nfct_bitmask_test_bit(const struct nfct_bitmask *, unsigned int bit); +void nfct_bitmask_unset_bit(struct nfct_bitmask *, unsigned int bit); +void nfct_bitmask_destroy(struct nfct_bitmask *); + /* setter */ extern void nfct_set_attr(struct nf_conntrack *ct, const enum nf_conntrack_attr type, diff --git a/qa/test_api.c b/qa/test_api.c index cdd128a..37bc140 100644 --- a/qa/test_api.c +++ b/qa/test_api.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -31,6 +32,54 @@ static void eval_sigterm(int status) } } +static void test_nfct_bitmask(void) +{ + struct nfct_bitmask *a, *b; + unsigned short int maxb, i; + + maxb = rand() & 0xffff; + + a = nfct_bitmask_new(maxb); + + assert(!nfct_bitmask_test_bit(a, maxb + 32)); + nfct_bitmask_set_bit(a, maxb + 32); + assert(!nfct_bitmask_test_bit(a, maxb + 32)); + + for (i = 0; i <= maxb; i++) + assert(!nfct_bitmask_test_bit(a, i)); + + for (i = 0; i <= maxb; i++) { + if (rand() & 1) { + assert(!nfct_bitmask_test_bit(a, i)); + continue; + } + nfct_bitmask_set_bit(a, i); + assert(nfct_bitmask_test_bit(a, i)); + } + + b = nfct_bitmask_clone(a); + assert(b); + + for (i = 0; i <= maxb; i++) { + if (nfct_bitmask_test_bit(a, i)) + assert(nfct_bitmask_test_bit(b, i)); + else + assert(!nfct_bitmask_test_bit(b, i)); + } + + nfct_bitmask_destroy(a); + + for (i = 0; i <= maxb; i++) { + if (rand() & 1) + continue; + nfct_bitmask_unset_bit(b, i); + assert(!nfct_bitmask_test_bit(b, i)); + } + + nfct_bitmask_destroy(b); +} + + int main(void) { int ret, i; @@ -40,6 +89,8 @@ int main(void) const char *val; int status; + srand(time(NULL)); + /* initialize fake data for testing purposes */ for (i=0; i 0xffff) + return NULL; + + words = DIV_ROUND_UP(max+1, 32); + bytes = words * sizeof(b->bits[0]); + + b = malloc(sizeof(*b) + bytes); + if (b) { + memset(b->bits, 0, bytes); + b->words = words; + } + return b; +} + +/* + * nfct_bitmask_clone - duplicate a bitmask object + * + * \param b pointer to the bitmask object to duplicate + * + * returns an identical copy of the bitmask. + */ +struct nfct_bitmask *nfct_bitmask_clone(const struct nfct_bitmask *b) +{ + unsigned int bytes = b->words * sizeof(b->bits[0]); + struct nfct_bitmask *copy; + + bytes += sizeof(*b); + + copy = malloc(bytes); + if (copy) + memcpy(copy, b, bytes); + return copy; +} + +/* + * nfct_bitmask_set_bit - set bit in the bitmask + * + * \param b pointer to the bitmask object + * \param bit the bit to set + */ +void nfct_bitmask_set_bit(struct nfct_bitmask *b, unsigned int bit) +{ + unsigned int bits = b->words * 32; + if (bit < bits) + set_bit(bit, b->bits); +} + +/* + * nfct_bitmask_test_bit - test if a bit in the bitmask is set + * + * \param b pointer to the bitmask object + * \param bit the bit to test + * + * returns 0 if the bit is not set. + */ +int nfct_bitmask_test_bit(const struct nfct_bitmask *b, unsigned int bit) +{ + unsigned int bits = b->words * 32; + return bit < bits && test_bit(bit, b->bits); +} + +/* + * nfct_bitmask_unset_bit - unset bit in the bitmask + * + * \param b pointer to the bitmask object + * \param bit the bit to clear + */ +void nfct_bitmask_unset_bit(struct nfct_bitmask *b, unsigned int bit) +{ + unsigned int bits = b->words * 32; + if (bit < bits) + unset_bit(bit, b->bits); +} + +/* + * nfct_bitmask_maxbit - return highest bit that may be set/unset + * + * \param b pointer to the bitmask object + */ +unsigned int nfct_bitmask_maxbit(const struct nfct_bitmask *b) +{ + return (b->words * 32) - 1; +} + +/* + * nfct_bitmask_destroy - destroy bitmask object + * + * \param b pointer to the bitmask object + * + * This function releases the memory that is used by the bitmask object. + */ +void nfct_bitmask_destroy(struct nfct_bitmask *b) +{ + free(b); +} + +/** + * @} + */