]> granicus.if.org Git - ipset/commitdiff
Support counters in the ipset library
authorJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Tue, 9 Apr 2013 15:17:00 +0000 (17:17 +0200)
committerJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Tue, 9 Apr 2013 19:42:16 +0000 (21:42 +0200)
Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Make_global.am
include/libipset/data.h
include/libipset/linux_ip_set.h
include/libipset/parse.h
lib/data.c
lib/errcode.c
lib/libipset.map
lib/parse.c
lib/print.c
lib/session.c

index e9f9afd4e6859a740105fa96d9340ec4e98feea3..33986a2bd874098a59734cc12208d7ecb6020359 100644 (file)
@@ -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
index ce1f1cac904996a5d03678ce4ca130170e2093d7..2b6b8cdf0f84f604228478292bc78044011046c3 100644 (file)
@@ -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| */
index f7ed8c93af45c24a993447699410b8e69cf73367..8024cdf13b700560e9bd0c1f3df1bacbdd90b900 100644 (file)
@@ -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 */
index 85aa2918e67d0e9cc367cb336342fb183059a161..8e0c7159e692a88fbd667801179820e9cad26b2b 100644 (file)
@@ -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,
index 1973307b27d92f995c18f02b9f747c576b4218c9..04a5997f35e3e00bb908501ba04c0b021c796074 100644 (file)
@@ -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;
index 1ce5c00832cf62c119d1b2685e505b9d0e63c3e7..027a736ac38650494c1842da269c08b6e9a77f1b 100644 (file)
@@ -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,
index 689ccb0993ca3534042caf24fee7beb3f0f14324..271fe59b08dbe48c09bb364276c1483740459c16 100644 (file)
@@ -122,3 +122,8 @@ LIBIPSET_3.0 {
 global:
   ipset_session_outfn;
 } LIBIPSET_2.0;
+
+LIBIPSET_4.0 {
+global:
+  ipset_parse_uint64;
+} LIBIPSET_3.0;
index 679aefcb9336cae514cfb5284864d77cf1a0b1db..0058369a12007f6906e71eccab2dc5f224ef9c2f 100644 (file)
@@ -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
index 1bd8392a750096f9617f18aeb2db245a6daf7948..86a76749fecf19d73f4004c7cd77f9d3d4c1cc4c 100644 (file)
@@ -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;
index 03c1098bbc6945daece3b33bf7aef7685d655cd0..4f0b802b2d56f3fbdcdcd536c6722b2297389bc7 100644 (file)
@@ -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);