From 5a6021823aa0da24b83f8d03f46ad4202f149fa3 Mon Sep 17 00:00:00 2001 From: Jozsef Kadlecsik Date: Tue, 9 Apr 2013 17:17:00 +0200 Subject: Support counters in the ipset library Signed-off-by: Jozsef Kadlecsik --- Make_global.am | 2 +- include/libipset/data.h | 3 +++ include/libipset/linux_ip_set.h | 38 +++++++++++++++++++++++++++++++++----- include/libipset/parse.h | 2 ++ lib/data.c | 23 +++++++++++++++++++++++ lib/errcode.c | 2 ++ lib/libipset.map | 5 +++++ lib/parse.c | 28 ++++++++++++++++++++++++++++ lib/print.c | 3 +++ lib/session.c | 30 ++++++++++++++++++++++++++++-- 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 @@ -1478,6 +1478,34 @@ ipset_parse_after(struct ipset_session *session, return ipset_data_set(data, opt, str); } +/** + * 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 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 */ +#include /* htobe64 */ #include /* errno */ #include /* setjmp, longjmp */ #include /* 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); -- cgit v1.2.3