diff options
author | Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> | 2013-04-09 17:17:00 +0200 |
---|---|---|
committer | Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> | 2013-04-09 21:42:16 +0200 |
commit | 5a6021823aa0da24b83f8d03f46ad4202f149fa3 (patch) | |
tree | 6ff41aa8262f2bcbd4c9bdc33d4aadc1b01d678f /lib | |
parent | 488c1e17e6fb7b6924b9d31372b05dc457d54cf4 (diff) |
Support counters in the ipset library
Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/data.c | 23 | ||||
-rw-r--r-- | lib/errcode.c | 2 | ||||
-rw-r--r-- | lib/libipset.map | 5 | ||||
-rw-r--r-- | lib/parse.c | 28 | ||||
-rw-r--r-- | lib/print.c | 3 | ||||
-rw-r--r-- | lib/session.c | 30 |
6 files changed, 89 insertions, 2 deletions
@@ -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); |