summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJozsef Kadlecsik <kadlec@blackhole.kfki.hu>2013-04-09 17:17:00 +0200
committerJozsef Kadlecsik <kadlec@blackhole.kfki.hu>2013-04-09 21:42:16 +0200
commit5a6021823aa0da24b83f8d03f46ad4202f149fa3 (patch)
tree6ff41aa8262f2bcbd4c9bdc33d4aadc1b01d678f
parent488c1e17e6fb7b6924b9d31372b05dc457d54cf4 (diff)
Support counters in the ipset library
Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
-rw-r--r--Make_global.am2
-rw-r--r--include/libipset/data.h3
-rw-r--r--include/libipset/linux_ip_set.h38
-rw-r--r--include/libipset/parse.h2
-rw-r--r--lib/data.c23
-rw-r--r--lib/errcode.c2
-rw-r--r--lib/libipset.map5
-rw-r--r--lib/parse.c28
-rw-r--r--lib/print.c3
-rw-r--r--lib/session.c30
10 files changed, 128 insertions, 8 deletions
diff --git a/Make_global.am b/Make_global.am
index e9f9afd..33986a2 100644
--- a/Make_global.am
+++ b/Make_global.am
@@ -69,7 +69,7 @@
# interface.
# curr:rev:age
-LIBVERSION = 3:1:0
+LIBVERSION = 4:0:1
AM_CPPFLAGS = $(kinclude_CFLAGS) $(all_includes) -I$(top_srcdir)/include \
-I/usr/local/include
diff --git a/include/libipset/data.h b/include/libipset/data.h
index ce1f1ca..2b6b8cd 100644
--- a/include/libipset/data.h
+++ b/include/libipset/data.h
@@ -54,6 +54,9 @@ enum ipset_opt {
IPSET_OPT_BEFORE,
IPSET_OPT_PHYSDEV,
IPSET_OPT_NOMATCH,
+ IPSET_OPT_COUNTERS,
+ IPSET_OPT_PACKETS,
+ IPSET_OPT_BYTES,
/* Internal options */
IPSET_OPT_FLAGS = 48, /* IPSET_FLAG_EXIST| */
IPSET_OPT_CADT_FLAGS, /* IPSET_FLAG_BEFORE| */
diff --git a/include/libipset/linux_ip_set.h b/include/libipset/linux_ip_set.h
index f7ed8c9..8024cdf 100644
--- a/include/libipset/linux_ip_set.h
+++ b/include/libipset/linux_ip_set.h
@@ -108,6 +108,8 @@ enum {
IPSET_ATTR_CIDR2,
IPSET_ATTR_IP2_TO,
IPSET_ATTR_IFACE,
+ IPSET_ATTR_BYTES,
+ IPSET_ATTR_PACKETS,
__IPSET_ATTR_ADT_MAX,
};
#define IPSET_ATTR_ADT_MAX (__IPSET_ATTR_ADT_MAX - 1)
@@ -137,12 +139,13 @@ enum ipset_errno {
IPSET_ERR_REFERENCED,
IPSET_ERR_IPADDR_IPV4,
IPSET_ERR_IPADDR_IPV6,
+ IPSET_ERR_COUNTER,
/* Type specific error codes */
IPSET_ERR_TYPE_SPECIFIC = 4352,
};
-/* Flags at command level */
+/* Flags at command level or match/target flags, lower half of cmdattrs*/
enum ipset_cmd_flags {
IPSET_FLAG_BIT_EXIST = 0,
IPSET_FLAG_EXIST = (1 << IPSET_FLAG_BIT_EXIST),
@@ -150,10 +153,20 @@ enum ipset_cmd_flags {
IPSET_FLAG_LIST_SETNAME = (1 << IPSET_FLAG_BIT_LIST_SETNAME),
IPSET_FLAG_BIT_LIST_HEADER = 2,
IPSET_FLAG_LIST_HEADER = (1 << IPSET_FLAG_BIT_LIST_HEADER),
- IPSET_FLAG_CMD_MAX = 15, /* Lower half */
+ IPSET_FLAG_BIT_SKIP_COUNTER_UPDATE = 3,
+ IPSET_FLAG_SKIP_COUNTER_UPDATE =
+ (1 << IPSET_FLAG_BIT_SKIP_COUNTER_UPDATE),
+ IPSET_FLAG_BIT_SKIP_SUBCOUNTER_UPDATE = 4,
+ IPSET_FLAG_SKIP_SUBCOUNTER_UPDATE =
+ (1 << IPSET_FLAG_BIT_SKIP_SUBCOUNTER_UPDATE),
+ IPSET_FLAG_BIT_MATCH_COUNTERS = 5,
+ IPSET_FLAG_MATCH_COUNTERS = (1 << IPSET_FLAG_BIT_MATCH_COUNTERS),
+ IPSET_FLAG_BIT_RETURN_NOMATCH = 7,
+ IPSET_FLAG_RETURN_NOMATCH = (1 << IPSET_FLAG_BIT_RETURN_NOMATCH),
+ IPSET_FLAG_CMD_MAX = 15,
};
-/* Flags at CADT attribute level */
+/* Flags at CADT attribute level, upper half of cmdattrs */
enum ipset_cadt_flags {
IPSET_FLAG_BIT_BEFORE = 0,
IPSET_FLAG_BEFORE = (1 << IPSET_FLAG_BIT_BEFORE),
@@ -161,7 +174,9 @@ enum ipset_cadt_flags {
IPSET_FLAG_PHYSDEV = (1 << IPSET_FLAG_BIT_PHYSDEV),
IPSET_FLAG_BIT_NOMATCH = 2,
IPSET_FLAG_NOMATCH = (1 << IPSET_FLAG_BIT_NOMATCH),
- IPSET_FLAG_CADT_MAX = 15, /* Upper half */
+ IPSET_FLAG_BIT_WITH_COUNTERS = 3,
+ IPSET_FLAG_WITH_COUNTERS = (1 << IPSET_FLAG_BIT_WITH_COUNTERS),
+ IPSET_FLAG_CADT_MAX = 15,
};
/* Commands with settype-specific attributes */
@@ -190,6 +205,7 @@ enum ip_set_dim {
* If changed, new revision of iptables match/target is required.
*/
IPSET_DIM_MAX = 6,
+ /* Backward compatibility: set match revision 2 */
IPSET_BIT_RETURN_NOMATCH = 7,
};
@@ -202,6 +218,18 @@ enum ip_set_kopt {
IPSET_RETURN_NOMATCH = (1 << IPSET_BIT_RETURN_NOMATCH),
};
+enum {
+ IPSET_COUNTER_NONE = 0,
+ IPSET_COUNTER_EQ,
+ IPSET_COUNTER_NE,
+ IPSET_COUNTER_LT,
+ IPSET_COUNTER_GT,
+};
+
+struct ip_set_counter_match {
+ __u8 op;
+ __u64 value;
+};
/* Interface to iptables/ip6tables */
@@ -228,4 +256,4 @@ struct ip_set_req_version {
unsigned int version;
};
-#endif /*_UAPI_IP_SET_H */
+#endif /* _UAPI_IP_SET_H */
diff --git a/include/libipset/parse.h b/include/libipset/parse.h
index 85aa291..8e0c715 100644
--- a/include/libipset/parse.h
+++ b/include/libipset/parse.h
@@ -74,6 +74,8 @@ extern int ipset_parse_setname(struct ipset_session *session,
enum ipset_opt opt, const char *str);
extern int ipset_parse_timeout(struct ipset_session *session,
enum ipset_opt opt, const char *str);
+extern int ipset_parse_uint64(struct ipset_session *session,
+ enum ipset_opt opt, const char *str);
extern int ipset_parse_uint32(struct ipset_session *session,
enum ipset_opt opt, const char *str);
extern int ipset_parse_uint8(struct ipset_session *session,
diff --git a/lib/data.c b/lib/data.c
index 1973307..04a5997 100644
--- a/lib/data.c
+++ b/lib/data.c
@@ -73,6 +73,8 @@ struct ipset_data {
char name[IPSET_MAXNAMELEN];
char nameref[IPSET_MAXNAMELEN];
char iface[IFNAMSIZ];
+ uint64_t packets;
+ uint64_t bytes;
} adt;
};
};
@@ -273,6 +275,9 @@ ipset_data_set(struct ipset_data *data, enum ipset_opt opt, const void *value)
case IPSET_OPT_SIZE:
data->create.size = *(const uint32_t *) value;
break;
+ case IPSET_OPT_COUNTERS:
+ cadt_flag_type_attr(data, opt, IPSET_FLAG_WITH_COUNTERS);
+ break;
/* Create-specific options, filled out by the kernel */
case IPSET_OPT_ELEMENTS:
data->create.elements = *(const uint32_t *) value;
@@ -325,6 +330,12 @@ ipset_data_set(struct ipset_data *data, enum ipset_opt opt, const void *value)
case IPSET_OPT_IFACE:
ipset_strlcpy(data->adt.iface, value, IFNAMSIZ);
break;
+ case IPSET_OPT_PACKETS:
+ data->adt.packets = *(const uint64_t *) value;
+ break;
+ case IPSET_OPT_BYTES:
+ data->adt.bytes = *(const uint64_t *) value;
+ break;
/* Swap/rename */
case IPSET_OPT_SETNAME2:
ipset_strlcpy(data->setname2, value, IPSET_MAXNAMELEN);
@@ -356,6 +367,9 @@ ipset_data_set(struct ipset_data *data, enum ipset_opt opt, const void *value)
if (data->cadt_flags & IPSET_FLAG_NOMATCH)
ipset_data_flags_set(data,
IPSET_FLAG(IPSET_OPT_NOMATCH));
+ if (data->cadt_flags & IPSET_FLAG_WITH_COUNTERS)
+ ipset_data_flags_set(data,
+ IPSET_FLAG(IPSET_OPT_COUNTERS));
break;
default:
return -1;
@@ -454,6 +468,10 @@ ipset_data_get(const struct ipset_data *data, enum ipset_opt opt)
return &data->adt.proto;
case IPSET_OPT_IFACE:
return &data->adt.iface;
+ case IPSET_OPT_PACKETS:
+ return &data->adt.packets;
+ case IPSET_OPT_BYTES:
+ return &data->adt.bytes;
/* Swap/rename */
case IPSET_OPT_SETNAME2:
return data->setname2;
@@ -465,6 +483,7 @@ ipset_data_get(const struct ipset_data *data, enum ipset_opt opt)
case IPSET_OPT_BEFORE:
case IPSET_OPT_PHYSDEV:
case IPSET_OPT_NOMATCH:
+ case IPSET_OPT_COUNTERS:
return &data->cadt_flags;
default:
return NULL;
@@ -506,6 +525,9 @@ ipset_data_sizeof(enum ipset_opt opt, uint8_t family)
case IPSET_OPT_REFERENCES:
case IPSET_OPT_MEMSIZE:
return sizeof(uint32_t);
+ case IPSET_OPT_PACKETS:
+ case IPSET_OPT_BYTES:
+ return sizeof(uint64_t);
case IPSET_OPT_CIDR:
case IPSET_OPT_CIDR2:
case IPSET_OPT_NETMASK:
@@ -519,6 +541,7 @@ ipset_data_sizeof(enum ipset_opt opt, uint8_t family)
case IPSET_OPT_BEFORE:
case IPSET_OPT_PHYSDEV:
case IPSET_OPT_NOMATCH:
+ case IPSET_OPT_COUNTERS:
return sizeof(uint32_t);
default:
return 0;
diff --git a/lib/errcode.c b/lib/errcode.c
index 1ce5c00..027a736 100644
--- a/lib/errcode.c
+++ b/lib/errcode.c
@@ -70,6 +70,8 @@ static const struct ipset_errcode_table core_errcode_table[] = {
"An IPv4 address is expected, but not received" },
{ IPSET_ERR_IPADDR_IPV6, 0,
"An IPv6 address is expected, but not received" },
+ { IPSET_ERR_COUNTER, 0,
+ "Packet/byte counters cannot be used: set was created without counter support" },
/* ADD specific error codes */
{ IPSET_ERR_EXIST, IPSET_CMD_ADD,
diff --git a/lib/libipset.map b/lib/libipset.map
index 689ccb0..271fe59 100644
--- a/lib/libipset.map
+++ b/lib/libipset.map
@@ -122,3 +122,8 @@ LIBIPSET_3.0 {
global:
ipset_session_outfn;
} LIBIPSET_2.0;
+
+LIBIPSET_4.0 {
+global:
+ ipset_parse_uint64;
+} LIBIPSET_3.0;
diff --git a/lib/parse.c b/lib/parse.c
index 679aefc..0058369 100644
--- a/lib/parse.c
+++ b/lib/parse.c
@@ -1479,6 +1479,34 @@ ipset_parse_after(struct ipset_session *session,
}
/**
+ * ipset_parse_uint64 - parse string as an unsigned long integer
+ * @session: session structure
+ * @opt: option kind of the data
+ * @str: string to parse
+ *
+ * Parse string as an unsigned long integer number.
+ * The value is stored in the data blob of the session.
+ *
+ * Returns 0 on success or a negative error code.
+ */
+int
+ipset_parse_uint64(struct ipset_session *session,
+ enum ipset_opt opt, const char *str)
+{
+ unsigned long long value = 0;
+ int err;
+
+ assert(session);
+ assert(str);
+
+ err = string_to_number_ll(session, str, 0, ULLONG_MAX - 1, &value);
+ if (err)
+ return err;
+
+ return ipset_session_data_set(session, opt, &value);
+}
+
+/**
* ipset_parse_uint32 - parse string as an unsigned integer
* @session: session structure
* @opt: option kind of the data
diff --git a/lib/print.c b/lib/print.c
index 1bd8392..86a7674 100644
--- a/lib/print.c
+++ b/lib/print.c
@@ -387,6 +387,9 @@ ipset_print_number(char *buf, unsigned int len,
else if (maxsize == sizeof(uint32_t))
return snprintf(buf, len, "%lu",
(long unsigned) *(const uint32_t *) number);
+ else if (maxsize == sizeof(uint64_t))
+ return snprintf(buf, len, "%llu",
+ (long long unsigned) *(const uint64_t *) number);
else
assert(0);
return 0;
diff --git a/lib/session.c b/lib/session.c
index 03c1098..4f0b802 100644
--- a/lib/session.c
+++ b/lib/session.c
@@ -5,6 +5,7 @@
* published by the Free Software Foundation.
*/
#include <assert.h> /* assert */
+#include <endian.h> /* htobe64 */
#include <errno.h> /* errno */
#include <setjmp.h> /* setjmp, longjmp */
#include <stdio.h> /* snprintf */
@@ -479,6 +480,14 @@ static const struct ipset_attr_policy adt_attrs[] = {
.opt = IPSET_OPT_IFACE,
.len = IFNAMSIZ,
},
+ [IPSET_ATTR_PACKETS] = {
+ .type = MNL_TYPE_U64,
+ .opt = IPSET_OPT_PACKETS,
+ },
+ [IPSET_ATTR_BYTES] = {
+ .type = MNL_TYPE_U64,
+ .opt = IPSET_OPT_BYTES,
+ },
};
static const struct ipset_attr_policy ipaddr_attrs[] = {
@@ -550,6 +559,7 @@ attr2data(struct ipset_session *session, struct nlattr *nla[],
struct ipset_data *data = session->data;
const struct ipset_attr_policy *attr;
const void *d;
+ uint64_t v64;
uint32_t v32;
uint16_t v16;
int ret;
@@ -599,6 +609,11 @@ attr2data(struct ipset_session *session, struct nlattr *nla[],
} else if (nla[type]->nla_type & NLA_F_NET_BYTEORDER) {
D("netorder attr type %u", type);
switch (attr->type) {
+ case MNL_TYPE_U64: {
+ v64 = be64toh(*(const uint64_t *)d);
+ d = &v64;
+ break;
+ }
case MNL_TYPE_U32: {
v32 = ntohl(*(const uint32_t *)d);
d = &v32;
@@ -773,8 +788,10 @@ list_adt(struct ipset_session *session, struct nlattr *nla[])
safe_dprintf(session, ipset_print_elem, IPSET_OPT_ELEM);
- for (arg = type->args[IPSET_ADD]; arg != NULL && arg->print; arg++) {
- if (!ipset_data_test(data, arg->opt))
+ for (arg = type->args[IPSET_ADD]; arg != NULL && arg->opt; arg++) {
+ D("print arg opt %u %s\n", arg->opt,
+ ipset_data_test(data, arg->opt) ? "(yes)" : "(missing)");
+ if (!(arg->print && ipset_data_test(data, arg->opt)))
continue;
switch (session->mode) {
case IPSET_LIST_SAVE:
@@ -1413,6 +1430,9 @@ attr_len(const struct ipset_attr_policy *attr, uint8_t family, uint16_t *flags)
*flags = NLA_F_NET_BYTEORDER;
return family == NFPROTO_IPV4 ? sizeof(uint32_t)
: sizeof(struct in6_addr);
+ case MNL_TYPE_U64:
+ *flags = NLA_F_NET_BYTEORDER;
+ return sizeof(uint64_t);
case MNL_TYPE_U32:
*flags = NLA_F_NET_BYTEORDER;
return sizeof(uint32_t);
@@ -1465,6 +1485,12 @@ rawdata2attr(struct ipset_session *session, struct nlmsghdr *nlh,
return 1;
switch (attr->type) {
+ case MNL_TYPE_U64: {
+ uint64_t value = htobe64(*(const uint64_t *)d);
+
+ mnl_attr_put(nlh, type | flags, alen, &value);
+ return 0;
+ }
case MNL_TYPE_U32: {
uint32_t value = htonl(*(const uint32_t *)d);