From c1dd8442aac6cadb29110f763f23cafc63135a79 Mon Sep 17 00:00:00 2001 From: Anton Danilov Date: Thu, 28 Aug 2014 10:11:31 +0400 Subject: libipset: Add userspace code for the skbinfo extension support. Add userspace code to support of the skbinfo extension independly of set types. Defines constants, flag and function for print/parse/send/recieve of skbinfo parameters. Signed-off-by: Anton Danilov Signed-off-by: Jozsef Kadlecsik --- lib/data.c | 30 ++++++++++++++++++++++++++- lib/debug.c | 9 ++++++++ lib/errcode.c | 2 ++ lib/parse.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/print.c | 49 ++++++++++++++++++++++++++++++++++++++++++++ lib/session.c | 12 +++++++++++ 6 files changed, 167 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/data.c b/lib/data.c index c214bec..8372a2f 100644 --- a/lib/data.c +++ b/lib/data.c @@ -78,6 +78,9 @@ struct ipset_data { uint64_t packets; uint64_t bytes; char comment[IPSET_MAX_COMMENT_SIZE+1]; + uint64_t skbmark; + uint32_t skbprio; + uint16_t skbqueue; } adt; }; }; @@ -312,6 +315,9 @@ ipset_data_set(struct ipset_data *data, enum ipset_opt opt, const void *value) case IPSET_OPT_FORCEADD: cadt_flag_type_attr(data, opt, IPSET_FLAG_WITH_FORCEADD); break; + case IPSET_OPT_SKBINFO: + cadt_flag_type_attr(data, opt, IPSET_FLAG_WITH_SKBINFO); + break; /* Create-specific options, filled out by the kernel */ case IPSET_OPT_ELEMENTS: data->create.elements = *(const uint32_t *) value; @@ -374,6 +380,15 @@ ipset_data_set(struct ipset_data *data, enum ipset_opt opt, const void *value) ipset_strlcpy(data->adt.comment, value, IPSET_MAX_COMMENT_SIZE + 1); break; + case IPSET_OPT_SKBMARK: + data->adt.skbmark = *(const uint64_t *) value; + break; + case IPSET_OPT_SKBPRIO: + data->adt.skbprio = *(const uint32_t *) value; + break; + case IPSET_OPT_SKBQUEUE: + data->adt.skbqueue = *(const uint16_t *) value; + break; /* Swap/rename */ case IPSET_OPT_SETNAME2: ipset_strlcpy(data->setname2, value, IPSET_MAXNAMELEN); @@ -410,7 +425,10 @@ ipset_data_set(struct ipset_data *data, enum ipset_opt opt, const void *value) IPSET_FLAG(IPSET_OPT_COUNTERS)); if (data->cadt_flags & IPSET_FLAG_WITH_COMMENT) ipset_data_flags_set(data, - IPSET_FLAG(IPSET_OPT_CREATE_COMMENT)); + IPSET_FLAG(IPSET_OPT_CREATE_COMMENT)); + if (data->cadt_flags & IPSET_FLAG_WITH_SKBINFO) + ipset_data_flags_set(data, + IPSET_FLAG(IPSET_OPT_SKBINFO)); break; default: return -1; @@ -519,6 +537,12 @@ ipset_data_get(const struct ipset_data *data, enum ipset_opt opt) return &data->adt.bytes; case IPSET_OPT_ADT_COMMENT: return &data->adt.comment; + case IPSET_OPT_SKBMARK: + return &data->adt.skbmark; + case IPSET_OPT_SKBPRIO: + return &data->adt.skbprio; + case IPSET_OPT_SKBQUEUE: + return &data->adt.skbqueue; /* Swap/rename */ case IPSET_OPT_SETNAME2: return data->setname2; @@ -533,6 +557,7 @@ ipset_data_get(const struct ipset_data *data, enum ipset_opt opt) case IPSET_OPT_COUNTERS: case IPSET_OPT_CREATE_COMMENT: case IPSET_OPT_FORCEADD: + case IPSET_OPT_SKBINFO: return &data->cadt_flags; default: return NULL; @@ -562,6 +587,7 @@ ipset_data_sizeof(enum ipset_opt opt, uint8_t family) return sizeof(uint32_t); case IPSET_OPT_PORT: case IPSET_OPT_PORT_TO: + case IPSET_OPT_SKBQUEUE: return sizeof(uint16_t); case IPSET_SETNAME: case IPSET_OPT_NAME: @@ -576,9 +602,11 @@ ipset_data_sizeof(enum ipset_opt opt, uint8_t family) case IPSET_OPT_ELEMENTS: case IPSET_OPT_REFERENCES: case IPSET_OPT_MEMSIZE: + case IPSET_OPT_SKBPRIO: return sizeof(uint32_t); case IPSET_OPT_PACKETS: case IPSET_OPT_BYTES: + case IPSET_OPT_SKBMARK: return sizeof(uint64_t); case IPSET_OPT_CIDR: case IPSET_OPT_CIDR2: diff --git a/lib/debug.c b/lib/debug.c index 1240e22..b2c5003 100644 --- a/lib/debug.c +++ b/lib/debug.c @@ -67,6 +67,9 @@ static const struct ipset_attrname adtattr2name[] = { [IPSET_ATTR_IP2_TO] = { .name = "IP2_TO" }, [IPSET_ATTR_IFACE] = { .name = "IFACE" }, [IPSET_ATTR_COMMENT] = { .name = "COMMENT" }, + [IPSET_ATTR_SKBMARK] = { .name = "SKBMARK" }, + [IPSET_ATTR_SKBPRIO] = { .name = "SKBPRIO" }, + [IPSET_ATTR_SKBQUEUE] = { .name = "SKBQUEUE" }, }; static void @@ -98,6 +101,12 @@ debug_cadt_attrs(int max, const struct ipset_attr_policy *policy, fprintf(stderr, "\t\t%s: %u\n", attr2name[i].name, ntohl(v)); break; + case MNL_TYPE_U64: + fprintf(stderr, "\t\t%s: 0x%llx\n", + attr2name[i].name, (long long int) + be64toh(*(uint64_t *) + mnl_attr_get_payload(nla[i]))); + break; case MNL_TYPE_NUL_STRING: fprintf(stderr, "\t\t%s: %s\n", attr2name[i].name, diff --git a/lib/errcode.c b/lib/errcode.c index 86eeabd..8eb275b 100644 --- a/lib/errcode.c +++ b/lib/errcode.c @@ -76,6 +76,8 @@ static const struct ipset_errcode_table core_errcode_table[] = { "Packet/byte counters cannot be used: set was created without counter support" }, { IPSET_ERR_COMMENT, 0, "Comment string is too long!" }, + { IPSET_ERR_SKBINFO, 0, + "Skbinfo mapping cannot be used: set was created without skbinfo support" }, /* ADD specific error codes */ { IPSET_ERR_EXIST, IPSET_CMD_ADD, diff --git a/lib/parse.c b/lib/parse.c index 6ed65cb..88d2888 100644 --- a/lib/parse.c +++ b/lib/parse.c @@ -1609,6 +1609,23 @@ ipset_parse_uint32(struct ipset_session *session, return err; } +int +ipset_parse_uint16(struct ipset_session *session, + enum ipset_opt opt, const char *str) +{ + uint16_t value; + int err; + + assert(session); + assert(str); + + err = string_to_u16(session, str, &value); + if (err == 0) + return ipset_session_data_set(session, opt, &value); + + return err; +} + /** * ipset_parse_uint8 - parse string as an unsigned short integer * @session: session structure @@ -1806,6 +1823,55 @@ int ipset_parse_comment(struct ipset_session *session, return ipset_data_set(data, opt, str); } +int +ipset_parse_skbmark(struct ipset_session *session, + enum ipset_opt opt, const char *str) +{ + struct ipset_data *data; + uint64_t result = 0; + unsigned long mark, mask; + int ret = 0; + + assert(session); + assert(opt == IPSET_OPT_SKBMARK); + assert(str); + + data = ipset_session_data(session); + ret = sscanf(str, "0x%lx/0x%lx", &mark, &mask); + if (ret != 2) { + mask = 0xffffffff; + ret = sscanf(str, "0x%lx", &mark); + if (ret != 1) + return syntax_err("Invalid skbmark format, " + "it should be: " + " MARK/MASK or MARK (see manpage)"); + } + result = ((uint64_t)(mark) << 32) | (mask & 0xffffffff); + return ipset_data_set(data, IPSET_OPT_SKBMARK, &result); +} + +int +ipset_parse_skbprio(struct ipset_session *session, + enum ipset_opt opt, const char *str) +{ + struct ipset_data *data; + unsigned maj, min; + uint32_t major; + int err; + + assert(session); + assert(opt == IPSET_OPT_SKBPRIO); + assert(str); + + data = ipset_session_data(session); + err = sscanf(str, "%x:%x", &maj, &min); + if (err != 2) + return syntax_err("Invalid skbprio format, it should be:"\ + "MAJOR:MINOR (see manpage)"); + major = ((uint32_t)maj << 16) | (min & 0xffff); + return ipset_data_set(data, IPSET_OPT_SKBPRIO, &major); +} + /** * ipset_parse_output - parse output format name * @session: session structure diff --git a/lib/print.c b/lib/print.c index a7abdcf..7f42434 100644 --- a/lib/print.c +++ b/lib/print.c @@ -596,6 +596,55 @@ int ipset_print_comment(char *buf, unsigned int len, return offset; } +int +ipset_print_skbmark(char *buf, unsigned int len, + const struct ipset_data *data, enum ipset_opt opt, + uint8_t env UNUSED) +{ + int size, offset = 0; + const uint64_t *skbmark; + uint32_t mark, mask; + + assert(buf); + assert(len > 0); + assert(data); + assert(opt == IPSET_OPT_SKBMARK); + + skbmark = ipset_data_get(data, IPSET_OPT_SKBMARK); + assert(skbmark); + mark = *skbmark >> 32; + mask = *skbmark & 0xffffffff; + if (mask == 0xffffffff) + size = snprintf(buf + offset, len, "0x%"PRIx32, mark); + else + size = snprintf(buf + offset, len, + "0x%"PRIx32"/0x%"PRIx32, mark, mask); + SNPRINTF_FAILURE(size, len, offset); + return offset; +} + +int +ipset_print_skbprio(char *buf, unsigned int len, + const struct ipset_data *data, enum ipset_opt opt, + uint8_t env UNUSED) +{ + int size, offset = 0; + const uint32_t *skbprio; + + assert(buf); + assert(len > 0); + assert(data); + assert(opt == IPSET_OPT_SKBPRIO); + + skbprio = ipset_data_get(data, opt); + assert(skbprio); + size = snprintf(buf + offset, len, "%x:%x", + *skbprio >> 16, *skbprio & 0xffff); + SNPRINTF_FAILURE(size, len, offset); + return offset; +} + + /** * ipset_print_proto - print protocol name * @buf: printing buffer diff --git a/lib/session.c b/lib/session.c index d2957a5..33ce4de 100644 --- a/lib/session.c +++ b/lib/session.c @@ -501,6 +501,18 @@ static const struct ipset_attr_policy adt_attrs[] = { .opt = IPSET_OPT_ADT_COMMENT, .len = IPSET_MAX_COMMENT_SIZE + 1, }, + [IPSET_ATTR_SKBMARK] = { + .type = MNL_TYPE_U64, + .opt = IPSET_OPT_SKBMARK, + }, + [IPSET_ATTR_SKBPRIO] = { + .type = MNL_TYPE_U32, + .opt = IPSET_OPT_SKBPRIO, + }, + [IPSET_ATTR_SKBQUEUE] = { + .type = MNL_TYPE_U16, + .opt = IPSET_OPT_SKBQUEUE, + }, }; static const struct ipset_attr_policy ipaddr_attrs[] = { -- cgit v1.2.3