@@ -11,19 +11,67 @@ enum nfacct_attr_type {
NFACCT_ATTR_NAME = 0,
NFACCT_ATTR_PKTS,
NFACCT_ATTR_BYTES,
+ NFACCT_ATTR_BTHR,
+ NFACCT_ATTR_FMT,
+};
+
+struct nfacct_options;
+
+enum nfacct_option_type {
+ NFACCT_OPT_FMT = 0,
+ NFACCT_OPT_PCW,
+ NFACCT_OPT_BCW,
+ NFACCT_OPT_BTCW,
+};
+
+enum nfacct_format {
+ FMT_DEFAULT=0,
+ FMT_NONE,
+ FMT_TRIPLETS,
+ FMT_IEC,
+ FMT_IEC_KIBIBYTE,
+ FMT_IEC_MEBIBYTE,
+ FMT_IEC_GIBIBYTE,
+ FMT_IEC_TEBIBYTE,
+ FMT_IEC_PEBIBYTE,
+ FMT_IEC_EXBIBYTE,
+ FMT_SI,
+ FMT_SI_KILOBYTE,
+ FMT_SI_MEGABYTE,
+ FMT_SI_GIGABYTE,
+ FMT_SI_TERABYTE,
+ FMT_SI_PETABYTE,
+ FMT_SI_EXABYTE,
+ FMT_MAX,
};
struct nfacct *nfacct_alloc(void);
void nfacct_free(struct nfacct *nfacct);
+struct nfacct_options *nfacct_options_alloc(void);
+void nfacct_options_free(struct nfacct_options *options);
+
void nfacct_attr_set(struct nfacct *nfacct, enum nfacct_attr_type type, const void *data);
void nfacct_attr_set_str(struct nfacct *nfacct, enum nfacct_attr_type type, const char *name);
void nfacct_attr_set_u64(struct nfacct *nfacct, enum nfacct_attr_type type, uint64_t value);
+void nfacct_attr_set_u32(struct nfacct *nfacct, enum nfacct_attr_type type, uint32_t value);
void nfacct_attr_unset(struct nfacct *nfacct, enum nfacct_attr_type type);
const void *nfacct_attr_get(struct nfacct *nfacct, enum nfacct_attr_type type);
const char *nfacct_attr_get_str(struct nfacct *nfacct, enum nfacct_attr_type type);
uint64_t nfacct_attr_get_u64(struct nfacct *nfacct, enum nfacct_attr_type type);
+uint32_t nfacct_attr_get_u32(struct nfacct *nfacct, enum nfacct_attr_type type);
+
+void nfacct_option_set(struct nfacct_options *options, enum nfacct_option_type type, const void *data);
+void nfacct_option_set_u32(struct nfacct_options *options, enum nfacct_option_type type, uint32_t value);
+void nfacct_option_set_tsize(struct nfacct_options *options, enum nfacct_option_type type, size_t value);
+void nfacct_option_unset(struct nfacct_options *options, enum nfacct_option_type type);
+
+const void *nfacct_option_get(struct nfacct_options *options, enum nfacct_option_type type);
+uint32_t nfacct_option_get_u32(struct nfacct_options *options, enum nfacct_option_type type);
+size_t nfacct_option_get_tsize(struct nfacct_options *options, enum nfacct_option_type type);
+
+void parse_nfacct_name(char *buf, const char *name);
struct nlmsghdr;
@@ -33,10 +81,17 @@ int nfacct_nlmsg_parse_payload(const struct nlmsghdr *nlh, struct nfacct *nfacct
#define NFACCT_SNPRINTF_F_FULL (1 << 0)
#define NFACCT_SNPRINTF_F_TIME (1 << 1)
+#define NFACCT_SNPRINTF_F_NUMONLY (1 << 2) /* print "numbers-only" (formatted),
+ useful for determining max column width */
+#define NFACCT_SNPRINTF_F_BONLY (1 << 3) /* print only the "bytes" and "name" columns */
+#define NFACCT_SNPRINTF_F_EXTENDED (1 << 4) /* print packets, bytes, threshold and names */
+#define NFACCT_SNPRINTF_F_SAVE (1 << 5) /* print in a format suitable for 'restore' */
#define NFACCT_SNPRINTF_T_PLAIN 0
#define NFACCT_SNPRINTF_T_XML 1
int nfacct_snprintf(char *buf, size_t size, struct nfacct *nfacct, uint16_t type, uint16_t flags);
+int nfacct_snprintf_with_options(char *buf, size_t size, struct nfacct *nfacct,
+ uint16_t type, uint16_t flags, struct nfacct_options *options);
#endif
@@ -18,6 +18,8 @@ enum nfnl_acct_type {
NFACCT_NAME,
NFACCT_PKTS,
NFACCT_BYTES,
+ NFACCT_BTHR,
+ NFACCT_FMT,
NFACCT_USE,
__NFACCT_MAX
};
@@ -13,6 +13,7 @@
#include <endian.h>
#include <stdlib.h>
#include <string.h>
+#include <locale.h>
#include <inttypes.h>
#include <libmnl/libmnl.h>
@@ -60,6 +61,21 @@ struct nfacct {
char name[NFACCT_NAME_MAX];
uint64_t pkts;
uint64_t bytes;
+ uint64_t bthr;
+ /*
+ * Structure of fmt:
+ * <- reserved: 16 bits ->
+ * <- packets format: 8 bits-><-bytes format: 8 bits ->
+ */
+ uint32_t fmt;
+ uint32_t bitset;
+};
+
+struct nfacct_options {
+ uint32_t fmt;
+ size_t pcw;
+ size_t bcw;
+ size_t btcw;
uint32_t bitset;
};
@@ -91,6 +107,28 @@ void nfacct_free(struct nfacct *nfacct)
EXPORT_SYMBOL(nfacct_free);
/**
+ * nfacct_options_alloc - allocate a new accounting options object
+ *
+ * In case of success, this function returns a valid pointer, otherwise NULL
+ * s returned and errno is appropriately set.
+ */
+struct nfacct_options *nfacct_options_alloc(void)
+{
+ return calloc(1, sizeof(struct nfacct_options));
+}
+EXPORT_SYMBOL(nfacct_options_alloc);
+
+/**
+ * nfacct_options_free - release one accounting options object
+ * \param nfacct pointer to the accounting options object
+ */
+void nfacct_options_free(struct nfacct_options *options)
+{
+ free(options);
+}
+EXPORT_SYMBOL(nfacct_options_free);
+
+/**
* nfacct_attr_set - set one attribute of the accounting object
* \param nfacct pointer to the accounting object
* \param type attribute type you want to set
@@ -114,6 +152,14 @@ nfacct_attr_set(struct nfacct *nfacct, enum nfacct_attr_type type,
nfacct->bytes = *((uint64_t *) data);
nfacct->bitset |= (1 << NFACCT_ATTR_BYTES);
break;
+ case NFACCT_ATTR_BTHR:
+ nfacct->bthr = *((uint64_t *) data);
+ nfacct->bitset |= (1 << NFACCT_ATTR_BTHR);
+ break;
+ case NFACCT_ATTR_FMT:
+ nfacct->fmt = *((uint32_t *) data);
+ nfacct->bitset |= (1 << NFACCT_ATTR_FMT);
+ break;
}
}
EXPORT_SYMBOL(nfacct_attr_set);
@@ -147,6 +193,20 @@ nfacct_attr_set_u64(struct nfacct *nfacct, enum nfacct_attr_type type,
EXPORT_SYMBOL(nfacct_attr_set_u64);
/**
+ * nfacct_attr_set_u32 - set one attribute the accounting object
+ * \param nfacct pointer to the accounting object
+ * \param type attribute type you want to set
+ * \param value unsigned 32-bit integer
+ */
+void
+nfacct_attr_set_u32(struct nfacct *nfacct, enum nfacct_attr_type type,
+ uint32_t value)
+{
+ nfacct_attr_set(nfacct, type, &value);
+}
+EXPORT_SYMBOL(nfacct_attr_set_u32);
+
+/**
* nfacct_attr_unset - unset one attribute the accounting object
* \param nfacct pointer to the accounting object
* \param type attribute type you want to set
@@ -164,6 +224,12 @@ nfacct_attr_unset(struct nfacct *nfacct, enum nfacct_attr_type type)
case NFACCT_ATTR_BYTES:
nfacct->bitset &= ~(1 << NFACCT_ATTR_BYTES);
break;
+ case NFACCT_ATTR_BTHR:
+ nfacct->bitset &= ~(1 << NFACCT_ATTR_BTHR);
+ break;
+ case NFACCT_ATTR_FMT:
+ nfacct->bitset &= ~(1 << NFACCT_ATTR_FMT);
+ break;
}
}
EXPORT_SYMBOL(nfacct_attr_unset);
@@ -193,6 +259,14 @@ const void *nfacct_attr_get(struct nfacct *nfacct, enum nfacct_attr_type type)
if (nfacct->bitset & (1 << NFACCT_ATTR_BYTES))
ret = &nfacct->bytes;
break;
+ case NFACCT_ATTR_BTHR:
+ if (nfacct->bitset & (1 << NFACCT_ATTR_BTHR))
+ ret = &nfacct->bthr;
+ break;
+ case NFACCT_ATTR_FMT:
+ if (nfacct->bitset & (1 << NFACCT_ATTR_FMT))
+ ret = &nfacct->fmt;
+ break;
}
return ret;
}
@@ -228,21 +302,559 @@ uint64_t nfacct_attr_get_u64(struct nfacct *nfacct, enum nfacct_attr_type type)
}
EXPORT_SYMBOL(nfacct_attr_get_u64);
+/**
+ * nfacct_attr_get_u32 - get one attribute the accounting object
+ * \param nfacct pointer to the accounting object
+ * \param type attribute type you want to get
+ *
+ * This function returns a unsigned 32-bits integer. If the attribute is
+ * unsupported, this returns NULL.
+ */
+uint32_t nfacct_attr_get_u32(struct nfacct *nfacct, enum nfacct_attr_type type)
+{
+ const void *ret = nfacct_attr_get(nfacct, type);
+ return ret ? *((uint32_t *)ret) : 0;
+}
+EXPORT_SYMBOL(nfacct_attr_get_u32);
+
+/**
+ * nfacct_option_set - set one option of the accounting options object
+ * \param options pointer to the accounting options object
+ * \param type option type you want to set
+ * \param data pointer to data that will be used to set this option
+ */
+void
+nfacct_option_set(struct nfacct_options *options,
+ enum nfacct_option_type type,
+ const void *data)
+{
+ switch(type) {
+ case NFACCT_OPT_FMT:
+ options->fmt = *((uint32_t *) data);
+ options->bitset |= (1 << NFACCT_OPT_FMT);
+ break;
+ case NFACCT_OPT_PCW:
+ options->pcw = *((uint32_t *) data);
+ options->bitset |= (1 << NFACCT_OPT_PCW);
+ break;
+ case NFACCT_OPT_BCW:
+ options->bcw = *((uint32_t *) data);
+ options->bitset |= (1 << NFACCT_OPT_BCW);
+ break;
+ case NFACCT_OPT_BTCW:
+ options->btcw = *((uint32_t *) data);
+ options->bitset |= (1 << NFACCT_OPT_BTCW);
+ break;
+ }
+}
+EXPORT_SYMBOL(nfacct_option_set);
+
+/**
+ * nfacct_option_set_u32 - set one option in the accounting options object
+ * \param options pointer to the accounting options object
+ * \param type option type you want to set
+ * \param value unsigned 32-bit integer
+ */
+void
+nfacct_option_set_u32(struct nfacct_options *options,
+ enum nfacct_option_type type,
+ uint32_t value)
+{
+ nfacct_option_set(options, type, &value);
+}
+EXPORT_SYMBOL(nfacct_option_set_u32);
+
+/**
+ * nfacct_attr_set_tsize - set one options in the accounting options object
+ * \param options pointer to the accounting options object
+ * \param type option type you want to set
+ * \param value size_t (arch-dependent) integer
+ */
+void
+nfacct_option_set_tsize(struct nfacct_options *options,
+ enum nfacct_option_type type,
+ size_t value)
+{
+ nfacct_option_set(options, type, &value);
+}
+EXPORT_SYMBOL(nfacct_option_set_tsize);
+
+/**
+ * nfacct_option_unset - unset one option in the accounting options object
+ * \param options pointer to the accounting options object
+ * \param type option type you want to unset
+ */
+void
+nfacct_option_unset(struct nfacct_options *options,
+ enum nfacct_option_type type)
+{
+ switch(type) {
+ case NFACCT_OPT_FMT:
+ options->bitset &= ~(1 << NFACCT_OPT_FMT);
+ break;
+ case NFACCT_OPT_PCW:
+ options->bitset &= ~(1 << NFACCT_OPT_PCW);
+ break;
+ case NFACCT_OPT_BCW:
+ options->bitset &= ~(1 << NFACCT_OPT_BCW);
+ break;
+ case NFACCT_OPT_BTCW:
+ options->bitset &= ~(1 << NFACCT_OPT_BTCW);
+ break;
+ }
+}
+EXPORT_SYMBOL(nfacct_option_unset);
+
+/**
+ * nfacct_option_get - get one option from the accounting options object
+ * \param options pointer to the accounting options object
+ * \param type option type you want to get
+ *
+ * This function returns a valid pointer to the option data. If a
+ * unsupported option is used, this returns NULL.
+ */
+const void *nfacct_option_get(struct nfacct_options *options,
+ enum nfacct_option_type type)
+{
+ const void *ret = NULL;
+
+ switch(type) {
+ case NFACCT_OPT_FMT:
+ if (options->bitset & (1 << NFACCT_OPT_FMT))
+ ret = &options->fmt;
+ break;
+ case NFACCT_OPT_PCW:
+ if (options->bitset & (1 << NFACCT_OPT_PCW))
+ ret = &options->pcw;
+ break;
+ case NFACCT_OPT_BCW:
+ if (options->bitset & (1 << NFACCT_OPT_BCW))
+ ret = &options->bcw;
+ break;
+ case NFACCT_OPT_BTCW:
+ if (options->bitset & (1 << NFACCT_OPT_BTCW))
+ ret = &options->btcw;
+ break;
+ }
+ return ret;
+}
+EXPORT_SYMBOL(nfacct_option_get);
+
+/**
+ * nfacct_option_get_u32 - get one option from the accounting options object
+ * \param options pointer to the accounting options object
+ * \param type option type you want to get
+ *
+ * This function returns a unsigned 32-bits integer. If the option is
+ * unsupported, this returns NULL.
+ */
+uint32_t nfacct_option_get_u32(struct nfacct_options *options,
+ enum nfacct_option_type type)
+{
+ const void *ret = nfacct_option_get(options, type);
+ return ret ? *((uint32_t *)ret) : 0;
+}
+EXPORT_SYMBOL(nfacct_option_get_u32);
+
+/**
+ * nfacct_attr_get_tsize - get one option from the accounting options object
+ * \param options pointer to the accounting options object
+ * \param type option type you want to get
+ *
+ * This function returns a size_t (arch-dependent) integer. If the option is
+ * unsupported, this returns NULL.
+ */
+size_t nfacct_option_get_tsize(struct nfacct_options *options,
+ enum nfacct_option_type type)
+{
+ const void *ret = nfacct_option_get(options, type);
+ return ret ? *((size_t *)ret) : 0;
+}
+EXPORT_SYMBOL(nfacct_option_get_tsize);
+
+#define KiB ((unsigned long long) 1 << 10)
+#define MiB ((unsigned long long) KiB << 10)
+#define GiB ((unsigned long long) MiB << 10)
+#define TiB ((unsigned long long) GiB << 10)
+#define PiB ((unsigned long long) TiB << 10)
+#define EiB ((unsigned long long) PiB << 10)
+#define KB ((unsigned long long) 1*1000)
+#define MB ((unsigned long long) KB*1000)
+#define GB ((unsigned long long) MB*1000)
+#define TB ((unsigned long long) GB*1000)
+#define PB ((unsigned long long) TB*1000)
+#define EB ((unsigned long long) PB*1000)
+
+#define STR_FMT_PLAIN_NUMONLY "%s %s %s"
+#define STR_FMT_PLAIN_SAVE "%s %s,%s %"PRIu64" %"PRIu64" %"PRIu64
+#define STR_FMT_PLAIN_EXTENDED "[ pkts = %%%zus bytes = %%%zus%s" \
+ " thr = %%%zus ] = %%s"
+#define STR_FMT_PLAIN_BONLY "[ bytes = %%%zus%s ] = %%s"
+#define STR_FMT_PLAIN_NEW "[ pkts = %%%zus bytes = %%%zus%s ] = %%s"
+#define STR_FMT_PLAIN "{ pkts = %%%zus, bytes = %%%zus%s } = %%s;"
+#define STR_FMT_XML_BONLY "<obj><name>%s</name>" \
+ "<bytes>%s%s</bytes>"
+#define STR_FMT_XML "<obj><name>%s</name>" \
+ "<pkts>%s</pkts>" \
+ "<bytes>%s%s</bytes>"
+#define STR_FMT_XML_EXTENDED STR_FMT_XML \
+ "<threshold>%s</threshold>"
+#define STR_FMT_DEFAULT "%020.0f%s"
+#define STR_FMT_NONE "%.0f%s"
+#define STR_FMT_TRIPLETS "%'.0f%s"
+#define STR_FMT_SI_IEC "%'.3f%s"
+
+#define NFACCT_NUM_DEFAULT { .value = 0., .str = "" }
+
+struct nfacct_number {
+ float value;
+ char str[30];
+};
+
+struct fmt_key {
+ uint64_t num;
+ char name[4];
+ char fmt[4];
+};
+
+static struct fmt_key fmt_keys[] = {
+ [FMT_DEFAULT] = { .num = 1, .name = "", .fmt = "def" },
+ [FMT_NONE] = { .num = 1, .name = "", .fmt = "raw" },
+ [FMT_TRIPLETS] = { .num = 1, .name = "", .fmt = "3pl" },
+ [FMT_IEC] = { .num = 1, .name = "", .fmt = "iec" },
+ [FMT_IEC_KIBIBYTE] = { .num = KiB, .name = "KiB", .fmt = "kib" },
+ [FMT_IEC_MEBIBYTE] = { .num = MiB, .name = "MiB", .fmt = "mib" },
+ [FMT_IEC_GIBIBYTE] = { .num = GiB, .name = "GiB", .fmt = "gib" },
+ [FMT_IEC_TEBIBYTE] = { .num = TiB, .name = "TiB", .fmt = "tib" },
+ [FMT_IEC_PEBIBYTE] = { .num = PiB, .name = "PiB", .fmt = "pib" },
+ [FMT_IEC_EXBIBYTE] = { .num = EiB, .name = "EiB", .fmt = "eib" },
+ [FMT_SI] = { .num = 1, .name = "", .fmt = "si" },
+ [FMT_SI_KILOBYTE] = { .num = KB, .name = "KB", .fmt = "kb" },
+ [FMT_SI_MEGABYTE] = { .num = MB, .name = "MB", .fmt = "mb" },
+ [FMT_SI_GIGABYTE] = { .num = GB, .name = "GB", .fmt = "gb" },
+ [FMT_SI_TERABYTE] = { .num = TB, .name = "TB", .fmt = "tb" },
+ [FMT_SI_PETABYTE] = { .num = PB, .name = "PB", .fmt = "pb" },
+ [FMT_SI_EXABYTE] = { .num = EB, .name = "EB", .fmt = "eb" },
+};
+
+#define SET_RET(x) nf->value /= fmt_keys[x].num; \
+ name = fmt_keys[x].name;
+#define SET_FMT(x) STR_FMT_##x
+#define GET_FMT(x) fmt_keys[x].fmt
+#define SET_RET_FMT(x) \
+ snprintf(nf->str,sizeof(nf->str),SET_FMT(x),nf->value, name)
+
+static void
+format_number(struct nfacct_number *nf, const uint64_t val,
+ const enum nfacct_format fmt)
+{
+ nf->value = (float) val;
+ char *name = "";
+ switch (fmt) {
+ case FMT_IEC:
+ if (nf->value >= EiB) {
+ SET_RET(FMT_IEC_EXBIBYTE);
+ } else if (nf->value >= PiB) {
+ SET_RET(FMT_IEC_PEBIBYTE);
+ } else if (nf->value >= TiB) {
+ SET_RET(FMT_IEC_TEBIBYTE);
+ } else if (nf->value >= GiB) {
+ SET_RET(FMT_IEC_GIBIBYTE);
+ } else if (nf->value >= MiB) {
+ SET_RET(FMT_IEC_MEBIBYTE);
+ } else if (nf->value >= KiB) {
+ SET_RET(FMT_IEC_KIBIBYTE);
+ }
+ SET_RET_FMT(SI_IEC);
+ break;
+ case FMT_SI:
+ if (nf->value >= EB) {
+ SET_RET(FMT_SI_EXABYTE);
+ } else if (nf->value >= PB) {
+ SET_RET(FMT_SI_PETABYTE);
+ } else if (nf->value >= TB) {
+ SET_RET(FMT_SI_TERABYTE);
+ } else if (nf->value >= GB) {
+ SET_RET(FMT_SI_GIGABYTE);
+ } else if (nf->value >= MB) {
+ SET_RET(FMT_SI_MEGABYTE);
+ } else if (nf->value >= KB) {
+ SET_RET(FMT_SI_KILOBYTE);
+ }
+ SET_RET_FMT(SI_IEC);
+ break;
+ case FMT_IEC_EXBIBYTE:
+ case FMT_IEC_PEBIBYTE:
+ case FMT_IEC_TEBIBYTE:
+ case FMT_IEC_GIBIBYTE:
+ case FMT_IEC_MEBIBYTE:
+ case FMT_IEC_KIBIBYTE:
+ case FMT_SI_EXABYTE:
+ case FMT_SI_PETABYTE:
+ case FMT_SI_TERABYTE:
+ case FMT_SI_GIGABYTE:
+ case FMT_SI_MEGABYTE:
+ case FMT_SI_KILOBYTE:
+ SET_RET(fmt);
+ SET_RET_FMT(SI_IEC);
+ break;
+ case FMT_DEFAULT:
+ SET_RET(FMT_DEFAULT);
+ SET_RET_FMT(DEFAULT);
+ break;
+ case FMT_NONE:
+ SET_RET(FMT_NONE);
+ SET_RET_FMT(NONE);
+ break;
+ case FMT_TRIPLETS:
+ SET_RET(FMT_TRIPLETS);
+ SET_RET_FMT(TRIPLETS);
+ default:
+ break;
+ }
+}
+
+void parse_nfacct_name(char *buf, const char *name) {
+ static const char no_quote_chars[] = ",._-0123456789"
+ "abcdefghijklmnopqrstuvwxyz"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ static const char escape_chars[] = "\"\\'";
+ size_t length;
+ const char *p;
+
+ if (buf == NULL)
+ return;
+
+ buf[0] = '\0';
+ if (name == NULL)
+ return;
+
+ length = strspn(name, no_quote_chars);
+
+ if (length > 0 && name[length] == 0) {
+ /* no quoting required */
+ strncat(buf, name, length);
+ } else {
+ /* there is at least one character in the name, which
+ we have to quote. Write double quotes around the
+ name and escape special characters with a backslash */
+ strncat(buf,"\"",1);
+
+ for (p = strpbrk(name, escape_chars); p != NULL;
+ p = strpbrk(name, escape_chars)) {
+ if (p > name) {
+ strncat(buf,name, p - name);
+ }
+ strncat(buf,"\\",1);
+ strncat(buf,p,1);
+ name = p + 1;
+ }
+
+ /* strcat the rest and finish the double quoted
+ string */
+ strncat(buf,name,strlen(name));
+ strncat(buf,"\"",1);
+ }
+}
+
+static
+void parse_nfacct_name_xml(char *buf, const char *name) {
+ static const char escape_chars[] = "\"'<>&";
+ int length;
+ int n;
+ char e[10];
+ const char *p;
+
+ if (buf == NULL)
+ return;
+
+ buf[0] = '\0';
+ if (name == NULL)
+ return;
+
+ length = strcspn(name, escape_chars);
+ if (length > 0 && name[length] == 0) {
+ /* no escaping required */
+ strncat(buf, name, length);
+ } else {
+ for (p = strpbrk(name, escape_chars); p != NULL;
+ p = strpbrk(name, escape_chars)) {
+ if (p > name)
+ strncat(buf, name, p - name);
+
+ n = *p;
+ snprintf(e, sizeof(e), "&#%d;", n);
+ strncat(buf, e, strlen(e));
+ name = p + 1;
+ }
+
+ /* strncat the rest */
+ strncat(buf, name, length);
+ }
+}
+
+#define DEFAULT_LOCALE "en_GB"
+
+static void init_locale(void) {
+ char *lang;
+ char *env = "LANG";
+ lang = getenv(env);
+ setlocale(LC_ALL,(lang == NULL ? DEFAULT_LOCALE : lang));
+}
+
+/* fmt fundamentals */
+#define __offset_fmt 0
+#define __offset_bytes __offset_fmt
+#define __offset_pkt 8
+#define __size_fmt 0xffff
+#define __size_bytes 0xff
+#define __size_pkt __size_bytes
+
+/* internal fmt help functions */
+#define __get_mask(x) ((uint32_t)__size_##x << __offset_##x)
+#define __get_value(x,f) (((uint32_t)x & __get_mask(f)) >> __offset_##f)
+
+/* fmt help functions */
+#define get_fmt(x) __get_value(x,fmt)
+#define get_bytes_fmt(x) __get_value(x,bytes)
+#define get_pkt_fmt(x) __get_value(x,pkt)
+
+#define PRINT_THR(x,y) ((x != 0 && y > x) ? "+" : " ")
+
static int
nfacct_snprintf_plain(char *buf, size_t rem, struct nfacct *nfacct,
- uint16_t flags)
+ uint16_t flags, struct nfacct_options *options)
{
int ret;
+ bool compat = (options == NULL);
+ uint32_t fmt;
+ size_t pcw, bcw, btcw;
+ uint64_t pkts = 0, bytes = 0, thr = 0;
+ char nfacct_name[NFACCT_NAME_MAX * 2 + 4];
+ char fmt_str[sizeof(STR_FMT_PLAIN) +
+ sizeof(STR_FMT_DEFAULT) * 2 + 10];
+ struct nfacct_number pn = NFACCT_NUM_DEFAULT,
+ bn = NFACCT_NUM_DEFAULT,
+ tn = NFACCT_NUM_DEFAULT;
+
+ if (compat) {
+ fmt = FMT_MAX;
+ pcw = 0;
+ bcw = 0;
+ btcw = 0;
+ } else {
+ fmt = nfacct_option_get_u32(options, NFACCT_OPT_FMT);
+ pcw = nfacct_option_get_tsize(options, NFACCT_OPT_PCW);
+ bcw = nfacct_option_get_tsize(options, NFACCT_OPT_BCW);
+ btcw = nfacct_option_get_tsize(options, NFACCT_OPT_BTCW);
+ }
+ if (flags & NFACCT_SNPRINTF_F_BONLY) {
+ /* print bytes + name only */
+ bytes = nfacct_attr_get_u64(nfacct, NFACCT_ATTR_BYTES);
+ thr = nfacct_attr_get_u64(nfacct, NFACCT_ATTR_BTHR);
+
+ if (fmt == FMT_MAX)
+ fmt = nfacct_attr_get_u32(nfacct, NFACCT_ATTR_FMT);
+
+ if (get_fmt(fmt) > FMT_NONE)
+ init_locale();
+
+ format_number(&bn, bytes, get_bytes_fmt(fmt));
+ snprintf(fmt_str, sizeof(fmt_str), STR_FMT_PLAIN_BONLY, bcw,
+ PRINT_THR(thr,bytes));
+ parse_nfacct_name(nfacct_name,
+ nfacct_attr_get_str(nfacct,NFACCT_ATTR_NAME));
+ ret = snprintf(buf, rem, fmt_str, bn.str, nfacct_name);
+ } else if (flags & NFACCT_SNPRINTF_F_FULL) {
+ /* default: print pkts + bytes + name */
+ pkts = nfacct_attr_get_u64(nfacct, NFACCT_ATTR_PKTS);
+ bytes = nfacct_attr_get_u64(nfacct, NFACCT_ATTR_BYTES);
+ thr = nfacct_attr_get_u64(nfacct, NFACCT_ATTR_BTHR);
+
+ if (fmt == FMT_MAX)
+ fmt = nfacct_attr_get_u32(nfacct, NFACCT_ATTR_FMT);
+
+ if (get_fmt(fmt) > FMT_NONE)
+ init_locale();
- if (flags & NFACCT_SNPRINTF_F_FULL) {
- ret = snprintf(buf, rem,
- "{ pkts = %.20"PRIu64", bytes = %.20"PRIu64" } = %s;",
+ format_number(&pn, pkts, get_pkt_fmt(fmt));
+ format_number(&bn, bytes, get_bytes_fmt(fmt));
+ snprintf(fmt_str,sizeof(fmt_str),
+ (compat ? STR_FMT_PLAIN : STR_FMT_PLAIN_NEW),pcw,bcw,
+ (compat ? "" : PRINT_THR(thr,bytes)));
+
+ if (!compat) {
+ parse_nfacct_name(nfacct_name,
+ nfacct_attr_get_str(nfacct,NFACCT_ATTR_NAME));
+ }
+ ret = snprintf(buf, rem, fmt_str,
+ pn.str, bn.str,
+ (compat ? nfacct_attr_get_str(nfacct,
+ NFACCT_ATTR_NAME) :
+ nfacct_name));
+ } else if (flags & NFACCT_SNPRINTF_F_EXTENDED) {
+ /* print pkts + bytes + threshold + name */
+ pkts = nfacct_attr_get_u64(nfacct, NFACCT_ATTR_PKTS);
+ bytes = nfacct_attr_get_u64(nfacct, NFACCT_ATTR_BYTES);
+ thr = nfacct_attr_get_u64(nfacct, NFACCT_ATTR_BTHR);
+
+ if (fmt == FMT_MAX)
+ fmt = nfacct_attr_get_u32(nfacct, NFACCT_ATTR_FMT);
+
+ if (get_fmt(fmt) > FMT_NONE)
+ init_locale();
+
+ format_number(&pn, pkts, get_pkt_fmt(fmt));
+ format_number(&bn, bytes, get_bytes_fmt(fmt));
+
+ if (thr)
+ format_number(&tn, thr, get_bytes_fmt(fmt));
+
+ snprintf(fmt_str,sizeof(fmt_str),STR_FMT_PLAIN_EXTENDED,pcw,
+ bcw,PRINT_THR(thr,bytes), btcw);
+ parse_nfacct_name(nfacct_name,
+ nfacct_attr_get_str(nfacct,NFACCT_ATTR_NAME));
+ ret = snprintf(buf, rem, fmt_str, pn.str, bn.str,
+ (thr ? tn.str : "-"), nfacct_name);
+ } else if (flags & NFACCT_SNPRINTF_F_NUMONLY) {
+ /* numbers only: used to determine the maximum column width */
+ pkts = nfacct_attr_get_u64(nfacct, NFACCT_ATTR_PKTS);
+ bytes = nfacct_attr_get_u64(nfacct, NFACCT_ATTR_BYTES);
+ thr = nfacct_attr_get_u64(nfacct, NFACCT_ATTR_BTHR);
+
+ if (fmt == FMT_MAX)
+ fmt = nfacct_attr_get_u32(nfacct, NFACCT_ATTR_FMT);
+
+ if (get_fmt(fmt) > FMT_NONE)
+ init_locale();
+
+ format_number(&pn, pkts, get_pkt_fmt(fmt));
+ format_number(&bn, bytes, get_bytes_fmt(fmt));
+
+ if (thr)
+ format_number(&tn, thr, get_bytes_fmt(fmt));
+
+ ret = snprintf(buf, rem, STR_FMT_PLAIN_NUMONLY,
+ pn.str, bn.str, (thr ? tn.str : "-"));
+ } else if (flags & NFACCT_SNPRINTF_F_SAVE) {
+ /* save: format useful for 'restore' */
+ fmt = nfacct_attr_get_u32(nfacct, NFACCT_ATTR_FMT);
+ parse_nfacct_name(nfacct_name,
+ nfacct_attr_get_str(nfacct,NFACCT_ATTR_NAME));
+
+ ret = snprintf(buf, rem, STR_FMT_PLAIN_SAVE,
+ nfacct_name,
+ GET_FMT(get_pkt_fmt(fmt)),
+ GET_FMT(get_bytes_fmt(fmt)),
nfacct_attr_get_u64(nfacct, NFACCT_ATTR_PKTS),
nfacct_attr_get_u64(nfacct, NFACCT_ATTR_BYTES),
- nfacct_attr_get_str(nfacct, NFACCT_ATTR_NAME));
+ nfacct_attr_get_u64(nfacct, NFACCT_ATTR_BTHR));
+
} else {
- ret = snprintf(buf, rem, "%s\n",
- nfacct_attr_get_str(nfacct, NFACCT_ATTR_NAME));
+ /* print out name only */
+ parse_nfacct_name(nfacct_name,
+ nfacct_attr_get_str(nfacct,NFACCT_ATTR_NAME));
+ ret = snprintf(buf, rem, "%s\n", nfacct_name);
}
return ret;
@@ -288,19 +900,88 @@ nfacct_snprintf_xml_localtime(char *buf, unsigned int rem, const struct tm *tm)
static int
nfacct_snprintf_xml(char *buf, size_t rem, struct nfacct *nfacct,
- uint16_t flags)
+ uint16_t flags, struct nfacct_options *options)
{
int ret = 0;
+ bool compat = (options == NULL);
unsigned int size = 0, offset = 0;
+ uint32_t fmt;
+ uint64_t pkts = 0, bytes = 0, thr = 0;
+ char nfacct_name[NFACCT_NAME_MAX * 6 + 1];
+ struct nfacct_number pn = NFACCT_NUM_DEFAULT,
+ bn = NFACCT_NUM_DEFAULT,
+ tn = NFACCT_NUM_DEFAULT;
- ret = snprintf(buf, rem,
- "<obj><name>%s</name>"
- "<pkts>%.20"PRIu64"</pkts>"
- "<bytes>%.20"PRIu64"</bytes>",
- nfacct_attr_get_str(nfacct, NFACCT_ATTR_NAME),
- nfacct_attr_get_u64(nfacct, NFACCT_ATTR_BYTES),
- nfacct_attr_get_u64(nfacct, NFACCT_ATTR_PKTS));
+ if (compat) {
+ fmt = FMT_MAX;
+ } else {
+ fmt = nfacct_option_get_u32(options, NFACCT_OPT_FMT);
+ }
+ if (flags & NFACCT_SNPRINTF_F_BONLY) {
+ /* print name + bytes only */
+ bytes = nfacct_attr_get_u64(nfacct, NFACCT_ATTR_BYTES);
+ thr = nfacct_attr_get_u64(nfacct, NFACCT_ATTR_BTHR);
+
+ if (fmt == FMT_MAX)
+ fmt = nfacct_attr_get_u32(nfacct, NFACCT_ATTR_FMT);
+
+ if (get_fmt(fmt) > FMT_NONE)
+ init_locale();
+
+ format_number(&bn, bytes, get_bytes_fmt(fmt));
+ parse_nfacct_name_xml(nfacct_name,
+ nfacct_attr_get_str(nfacct,NFACCT_ATTR_NAME));
+ ret = snprintf(buf, rem, STR_FMT_XML_BONLY,
+ nfacct_name, bn.str, PRINT_THR(thr,bytes));
+ BUFFER_SIZE(ret, size, rem, offset);
+ } else if (flags & NFACCT_SNPRINTF_F_EXTENDED) {
+ /* print name + pkts + bytes + threshold */
+ pkts = nfacct_attr_get_u64(nfacct, NFACCT_ATTR_PKTS);
+ bytes = nfacct_attr_get_u64(nfacct, NFACCT_ATTR_BYTES);
+ thr = nfacct_attr_get_u64(nfacct, NFACCT_ATTR_BTHR);
+
+ if (fmt == FMT_MAX)
+ fmt = nfacct_attr_get_u32(nfacct, NFACCT_ATTR_FMT);
+
+ if (get_fmt(fmt) > FMT_NONE)
+ init_locale();
+
+ format_number(&pn, pkts, get_pkt_fmt(fmt));
+ format_number(&bn, bytes, get_bytes_fmt(fmt));
+ if (thr)
+ format_number(&tn, thr, get_bytes_fmt(fmt));
+
+ parse_nfacct_name_xml(nfacct_name,
+ nfacct_attr_get_str(nfacct,NFACCT_ATTR_NAME));
+ ret = snprintf(buf, rem, STR_FMT_XML_EXTENDED,
+ nfacct_name, pn.str, bn.str,
+ PRINT_THR(thr,bytes), (thr ? tn.str : "-"));
+ BUFFER_SIZE(ret, size, rem, offset);
+ } else {
+ /* default/everything else: print name + pkts + bytes */
+ pkts = nfacct_attr_get_u64(nfacct, NFACCT_ATTR_PKTS);
+ bytes = nfacct_attr_get_u64(nfacct, NFACCT_ATTR_BYTES);
+ thr = nfacct_attr_get_u64(nfacct, NFACCT_ATTR_BTHR);
+
+ if (fmt == FMT_MAX)
+ fmt = nfacct_attr_get_u32(nfacct, NFACCT_ATTR_FMT);
+
+ if (get_fmt(fmt) > FMT_NONE)
+ init_locale();
+
+ format_number(&pn, pkts, get_pkt_fmt(fmt));
+ format_number(&bn, bytes, get_bytes_fmt(fmt));
+ if (!compat) {
+ parse_nfacct_name_xml(nfacct_name,
+ nfacct_attr_get_str(nfacct,NFACCT_ATTR_NAME));
+ }
+ ret = snprintf(buf, rem, STR_FMT_XML,
+ (compat ? nfacct_attr_get_str(nfacct,
+ NFACCT_ATTR_NAME) :
+ nfacct_name) ,pn.str,bn.str,
+ (compat ? "" : PRINT_THR(thr,bytes)));
BUFFER_SIZE(ret, size, rem, offset);
+ }
if (flags & NFACCT_SNPRINTF_F_TIME) {
time_t t;
@@ -322,27 +1003,29 @@ err:
}
/**
- * nfacct_snprintf - print accounting object into one buffer
+ * nfacct_snprintf_with_options - print accounting object into one buffer
* \param buf: pointer to buffer that is used to print the object
* \param size: size of the buffer (or remaining room in it).
* \param nfacct: pointer to a valid accounting object.
* \param type: format output type, NFACCT_SNPRINTF_T_[PLAIN|XML]
* \param flags: output flags (NFACCT_SNPRINTF_F_FULL).
+ * \param options: nfacct options structure.
*
* This function returns -1 in case that some mandatory attributes are
* missing. On sucess, it returns 0.
*/
-int nfacct_snprintf(char *buf, size_t size, struct nfacct *nfacct,
- uint16_t type, uint16_t flags)
+int nfacct_snprintf_with_options(char *buf, size_t size,
+ struct nfacct *nfacct,
+ uint16_t type, uint16_t flags,
+ struct nfacct_options *options)
{
int ret = 0;
-
switch(type) {
case NFACCT_SNPRINTF_T_PLAIN:
- ret = nfacct_snprintf_plain(buf, size, nfacct, flags);
+ ret = nfacct_snprintf_plain(buf,size,nfacct,flags,options);
break;
case NFACCT_SNPRINTF_T_XML:
- ret = nfacct_snprintf_xml(buf, size, nfacct, flags);
+ ret = nfacct_snprintf_xml(buf,size,nfacct,flags,options);
break;
default:
ret = -1;
@@ -350,6 +1033,25 @@ int nfacct_snprintf(char *buf, size_t size, struct nfacct *nfacct,
}
return ret;
}
+EXPORT_SYMBOL(nfacct_snprintf_with_options);
+
+/**
+ * nfacct_snprintf - print accounting object into one buffer
+ * \param buf: pointer to buffer that is used to print the object
+ * \param size: size of the buffer (or remaining room in it).
+ * \param nfacct: pointer to a valid accounting object.
+ * \param type: format output type, NFACCT_SNPRINTF_T_[PLAIN|XML]
+ * \param flags: output flags (NFACCT_SNPRINTF_F_FULL).
+ *
+ * This function returns -1 in case that some mandatory attributes are
+ * missing. On sucess, it returns 0.
+ */
+int nfacct_snprintf(char *buf, size_t size, struct nfacct *nfacct,
+ uint16_t type, uint16_t flags)
+{
+ return nfacct_snprintf_with_options(buf, size, nfacct,
+ type, flags, NULL);
+}
EXPORT_SYMBOL(nfacct_snprintf);
/**
@@ -424,6 +1126,12 @@ void nfacct_nlmsg_build_payload(struct nlmsghdr *nlh, struct nfacct *nfacct)
if (nfacct->bitset & (1 << NFACCT_ATTR_BYTES))
mnl_attr_put_u64(nlh, NFACCT_BYTES, htobe64(nfacct->bytes));
+
+ if (nfacct->bitset & (1 << NFACCT_ATTR_BTHR))
+ mnl_attr_put_u64(nlh, NFACCT_BTHR, htobe64(nfacct->bthr));
+
+ if (nfacct->bitset & (1 << NFACCT_ATTR_FMT))
+ mnl_attr_put_u32(nlh, NFACCT_FMT, htobe32(nfacct->fmt));
}
EXPORT_SYMBOL(nfacct_nlmsg_build_payload);
@@ -444,11 +1152,18 @@ static int nfacct_nlmsg_parse_attr_cb(const struct nlattr *attr, void *data)
break;
case NFACCT_PKTS:
case NFACCT_BYTES:
+ case NFACCT_BTHR:
if (mnl_attr_validate(attr, MNL_TYPE_U64) < 0) {
perror("mnl_attr_validate");
return MNL_CB_ERROR;
}
break;
+ case NFACCT_FMT:
+ if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
+ perror("mnl_attr_validate");
+ return MNL_CB_ERROR;
+ }
+ break;
}
tb[type] = attr;
return MNL_CB_OK;
@@ -478,6 +1193,12 @@ nfacct_nlmsg_parse_payload(const struct nlmsghdr *nlh, struct nfacct *nfacct)
be64toh(mnl_attr_get_u64(tb[NFACCT_PKTS])));
nfacct_attr_set_u64(nfacct, NFACCT_ATTR_BYTES,
be64toh(mnl_attr_get_u64(tb[NFACCT_BYTES])));
+ if (tb[NFACCT_BTHR])
+ nfacct_attr_set_u64(nfacct, NFACCT_ATTR_BTHR,
+ be64toh(mnl_attr_get_u64(tb[NFACCT_BTHR])));
+ if (tb[NFACCT_FMT])
+ nfacct_attr_set_u32(nfacct, NFACCT_ATTR_FMT,
+ be32toh(mnl_attr_get_u32(tb[NFACCT_FMT])));
return 0;
}
@@ -21,4 +21,17 @@ local: *;
LIBNETFILTER_ACCT_1.1 {
nfacct_snprintf;
+ nfacct_attr_set_u32;
+ nfacct_attr_get_u32;
+ nfacct_options_alloc;
+ nfacct_options_free;
+ nfacct_option_set;
+ nfacct_option_set_u32;
+ nfacct_option_set_tsize;
+ nfacct_option_unset;
+ nfacct_option_get;
+ nfacct_option_get_u32;
+ nfacct_option_get_tsize;
+ parse_nfacct_name;
+ nfacct_snprintf_with_options;
} LIBNETFILTER_ACCT_1.0;