summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFlorian Westphal <fw@strlen.de>2012-11-13 12:21:08 +0100
committerFlorian Westphal <fw@strlen.de>2013-05-06 20:57:52 +0200
commit013a5284c901a6ce80320f499685b89d15eeed9e (patch)
tree003a0a7606823ecd6f2a97d782aca5263a2005a1
parent706064d8b9423df0d22e9ebba092ec2fb14b38aa (diff)
api: add nfct_bitmask object
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 <fw@strlen.de>
-rw-r--r--include/internal/bitops.h2
-rw-r--r--include/internal/object.h8
-rw-r--r--include/libnetfilter_conntrack/libnetfilter_conntrack.h12
-rw-r--r--qa/test_api.c55
-rw-r--r--src/conntrack/api.c119
5 files changed, 196 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 e1f1750..911b160 100644
--- a/qa/test_api.c
+++ b/qa/test_api.c
@@ -8,6 +8,7 @@
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
+#include <time.h>
#include <errno.h>
#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
@@ -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<sizeof(data); i++)
data[i] = 0x01;
@@ -281,6 +332,10 @@ int main(void)
nfct_destroy(tmp);
nfexp_destroy(exp);
nfexp_destroy(tmp_exp);
+
+ printf("== test nfct_bitmask_* API ==\n");
+ test_nfct_bitmask();
+
printf("OK\n");
return EXIT_SUCCESS;
diff --git a/src/conntrack/api.c b/src/conntrack/api.c
index 0bc2091..7b79e05 100644
--- a/src/conntrack/api.c
+++ b/src/conntrack/api.c
@@ -1483,3 +1483,122 @@ void nfct_filter_dump_set_attr_u8(struct nfct_filter_dump *filter_dump,
/**
* @}
*/
+
+/**
+ * \defgroup bitmask bitmask object
+ *
+ * @{
+ */
+
+/**
+ * nfct_bitmask_new - allocate a new bitmask
+ *
+ * \param max highest valid bit that can be set/unset.
+ *
+ * In case of success, this function returns a valid pointer to a memory blob,
+ * otherwise NULL is returned and errno is set appropiately.
+ */
+struct nfct_bitmask *nfct_bitmask_new(unsigned int max)
+{
+ struct nfct_bitmask *b;
+ unsigned int bytes, words;
+
+ if (max > 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);
+}
+
+/**
+ * @}
+ */