diff options
author | Pablo Neira Ayuso <pablo@netfilter.org> | 2008-11-02 21:35:42 +0100 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2008-11-02 21:35:42 +0100 |
commit | 76ac8ebe5e49385585c8e29fe530ed4baef390bf (patch) | |
tree | 4d0bdca7d2f039a173152dde44818b13d485ec49 /src | |
parent | 64ce47955778805afceb6ced58b63839763541ad (diff) | |
download | conntrack-tools-76ac8ebe5e49385585c8e29fe530ed4baef390bf.tar.gz conntrack-tools-76ac8ebe5e49385585c8e29fe530ed4baef390bf.zip |
network: rework TLV-based protocol
This patch reworks the TLV-based protocol to reduce the overhead
in the message building. The idea is to group some attributes
that must be present in a consistent configuration. Putting them
together help us to save some cycles in the message building.
Now, oprofile reports ~15% of samples in the build path instead
of ~25%. CPU consumption for 3000 HTTP GET requests per second
(1000 concurrent with apache benchmark tool) is ~45% in my
testbed, that is ~19% more consumption than with no replication
at all.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'src')
-rw-r--r-- | src/build.c | 202 | ||||
-rw-r--r-- | src/parse.c | 153 |
2 files changed, 210 insertions, 145 deletions
diff --git a/src/build.c b/src/build.c index be33c86..5143048 100644 --- a/src/build.c +++ b/src/build.c @@ -1,5 +1,5 @@ /* - * (C) 2006-2007 by Pablo Neira Ayuso <pablo@netfilter.org> + * (C) 2006-2008 by Pablo Neira Ayuso <pablo@netfilter.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,143 +20,139 @@ #include <libnetfilter_conntrack/libnetfilter_conntrack.h> #include "network.h" -static void addattr(struct netpld *pld, int attr, const void *data, size_t len) +static inline void * +put_header(struct netpld *pld, int attr, size_t len) { - struct netattr *nta; - int tlen = NTA_LENGTH(len); - - nta = PLD_TAIL(pld); + struct netattr *nta = PLD_TAIL(pld); + pld->len += NTA_ALIGN(NTA_LENGTH(len)); nta->nta_attr = htons(attr); nta->nta_len = htons(len); - memcpy(NTA_DATA(nta), data, len); - pld->len += NTA_ALIGN(tlen); + return NTA_DATA(nta); } -static void __build_u8(const struct nf_conntrack *ct, - struct netpld *pld, - int attr) +static inline void +addattr(struct netpld *pld, int attr, const void *data, size_t len) { - uint8_t data = nfct_get_attr_u8(ct, attr); - addattr(pld, attr, &data, sizeof(uint8_t)); + void *ptr = put_header(pld, attr, len); + memcpy(ptr, data, len); } -static void __build_u16(const struct nf_conntrack *ct, - struct netpld *pld, - int attr) +static inline void +__build_u8(const struct nf_conntrack *ct, int a, struct netpld *pld, int b) { - uint16_t data = nfct_get_attr_u16(ct, attr); - data = htons(data); - addattr(pld, attr, &data, sizeof(uint16_t)); + void *ptr = put_header(pld, b, sizeof(uint8_t)); + memcpy(ptr, nfct_get_attr(ct, a), sizeof(uint8_t)); } -static void __build_u32(const struct nf_conntrack *ct, - struct netpld *pld, - int attr) +static inline void +__build_u16(const struct nf_conntrack *ct, int a, struct netpld *pld, int b) { - uint32_t data = nfct_get_attr_u32(ct, attr); - data = htonl(data); - addattr(pld, attr, &data, sizeof(uint32_t)); + uint32_t data = nfct_get_attr_u16(ct, a); + data = htons(data); + addattr(pld, b, &data, sizeof(uint16_t)); } -static void __build_pointer_be(const struct nf_conntrack *ct, - struct netpld *pld, - int attr, - size_t size) +static inline void +__build_u32(const struct nf_conntrack *ct, int a, struct netpld *pld, int b) { - addattr(pld, attr, nfct_get_attr(ct, attr), size); + uint32_t data = nfct_get_attr_u32(ct, a); + data = htonl(data); + addattr(pld, b, &data, sizeof(uint32_t)); } -static void __nat_build_u32(uint32_t data, struct netpld *pld, int attr) +static inline void +__build_group(const struct nf_conntrack *ct, int a, struct netpld *pld, + int b, int size) { - data = htonl(data); - addattr(pld, attr, &data, sizeof(uint32_t)); + void *ptr = put_header(pld, b, size); + nfct_get_attr_grp(ct, a, ptr); } -static void __nat_build_u16(uint16_t data, struct netpld *pld, int attr) +static inline void +__build_natseqadj(const struct nf_conntrack *ct, struct netpld *pld) { - data = htons(data); - addattr(pld, attr, &data, sizeof(uint16_t)); + struct nta_attr_natseqadj data = { + .orig_seq_correction_pos = + htonl(nfct_get_attr_u32(ct, ATTR_ORIG_NAT_SEQ_CORRECTION_POS)), + .orig_seq_offset_before = + htonl(nfct_get_attr_u32(ct, ATTR_ORIG_NAT_SEQ_OFFSET_BEFORE)), + .orig_seq_offset_after = + htonl(nfct_get_attr_u32(ct, ATTR_ORIG_NAT_SEQ_OFFSET_AFTER)), + .repl_seq_correction_pos = + htonl(nfct_get_attr_u32(ct, ATTR_REPL_NAT_SEQ_CORRECTION_POS)), + .repl_seq_offset_before = + htonl(nfct_get_attr_u32(ct, ATTR_REPL_NAT_SEQ_OFFSET_BEFORE)), + .repl_seq_offset_after = + htonl(nfct_get_attr_u32(ct, ATTR_REPL_NAT_SEQ_OFFSET_AFTER)) + }; + addattr(pld, NTA_NAT_SEQ_ADJ, &data, sizeof(struct nta_attr_natseqadj)); } +static enum nf_conntrack_attr nat_type[] = + { ATTR_ORIG_NAT_SEQ_CORRECTION_POS, ATTR_ORIG_NAT_SEQ_OFFSET_BEFORE, + ATTR_ORIG_NAT_SEQ_OFFSET_AFTER, ATTR_REPL_NAT_SEQ_CORRECTION_POS, + ATTR_REPL_NAT_SEQ_OFFSET_BEFORE, ATTR_REPL_NAT_SEQ_OFFSET_AFTER }; + /* XXX: ICMP not supported */ void build_netpld(struct nf_conntrack *ct, struct netpld *pld, int query) { - if (nfct_attr_is_set(ct, ATTR_IPV4_SRC)) - __build_pointer_be(ct, pld, ATTR_IPV4_SRC, sizeof(uint32_t)); - if (nfct_attr_is_set(ct, ATTR_IPV4_DST)) - __build_pointer_be(ct, pld, ATTR_IPV4_DST, sizeof(uint32_t)); - if (nfct_attr_is_set(ct, ATTR_IPV6_SRC)) - __build_pointer_be(ct, pld, ATTR_IPV6_SRC, sizeof(uint32_t)*4); - if (nfct_attr_is_set(ct, ATTR_IPV6_DST)) - __build_pointer_be(ct, pld, ATTR_IPV6_DST, sizeof(uint32_t)*4); - if (nfct_attr_is_set(ct, ATTR_L3PROTO)) - __build_u8(ct, pld, ATTR_L3PROTO); - if (nfct_attr_is_set(ct, ATTR_PORT_SRC)) - __build_u16(ct, pld, ATTR_PORT_SRC); - if (nfct_attr_is_set(ct, ATTR_PORT_DST)) - __build_u16(ct, pld, ATTR_PORT_DST); - if (nfct_attr_is_set(ct, ATTR_L4PROTO)) { - uint8_t proto; - - __build_u8(ct, pld, ATTR_L4PROTO); - proto = nfct_get_attr_u8(ct, ATTR_L4PROTO); - if (proto == IPPROTO_TCP) { - if (nfct_attr_is_set(ct, ATTR_TCP_STATE)) - __build_u8(ct, pld, ATTR_TCP_STATE); - } + if (nfct_attr_grp_is_set(ct, ATTR_GRP_ORIG_IPV4)) { + __build_group(ct, ATTR_GRP_ORIG_IPV4, pld, NTA_IPV4, + sizeof(struct nfct_attr_grp_ipv4)); + } else if (nfct_attr_grp_is_set(ct, ATTR_GRP_ORIG_IPV6)) { + __build_group(ct, ATTR_GRP_ORIG_IPV6, pld, NTA_IPV6, + sizeof(struct nfct_attr_grp_ipv6)); + } + + __build_u8(ct, ATTR_L4PROTO, pld, NTA_L4PROTO); + if (nfct_attr_grp_is_set(ct, ATTR_GRP_ORIG_PORT)) { + __build_group(ct, ATTR_GRP_ORIG_PORT, pld, NTA_PORT, + sizeof(struct nfct_attr_grp_port)); } + + __build_u32(ct, ATTR_STATUS, pld, NTA_STATUS); + + if (nfct_attr_is_set(ct, ATTR_TCP_STATE)) + __build_u8(ct, ATTR_TCP_STATE, pld, NTA_STATE); if (nfct_attr_is_set(ct, ATTR_TIMEOUT)) - __build_u32(ct, pld, ATTR_TIMEOUT); + __build_u32(ct, ATTR_TIMEOUT, pld, NTA_TIMEOUT); if (nfct_attr_is_set(ct, ATTR_MARK)) - __build_u32(ct, pld, ATTR_MARK); - if (nfct_attr_is_set(ct, ATTR_STATUS)) - __build_u32(ct, pld, ATTR_STATUS); + __build_u32(ct, ATTR_MARK, pld, NTA_MARK); /* setup the master conntrack */ - if (nfct_attr_is_set(ct, ATTR_MASTER_IPV4_SRC)) - __build_u32(ct, pld, ATTR_MASTER_IPV4_SRC); - if (nfct_attr_is_set(ct, ATTR_MASTER_IPV4_DST)) - __build_u32(ct, pld, ATTR_MASTER_IPV4_DST); - if (nfct_attr_is_set(ct, ATTR_MASTER_L3PROTO)) - __build_u8(ct, pld, ATTR_MASTER_L3PROTO); - if (nfct_attr_is_set(ct, ATTR_MASTER_PORT_SRC)) - __build_u16(ct, pld, ATTR_MASTER_PORT_SRC); - if (nfct_attr_is_set(ct, ATTR_MASTER_PORT_DST)) - __build_u16(ct, pld, ATTR_MASTER_PORT_DST); - if (nfct_attr_is_set(ct, ATTR_MASTER_L4PROTO)) - __build_u8(ct, pld, ATTR_MASTER_L4PROTO); + if (nfct_attr_grp_is_set(ct, ATTR_GRP_MASTER_IPV4)) { + __build_group(ct, ATTR_GRP_MASTER_IPV4, pld, NTA_MASTER_IPV4, + sizeof(struct nfct_attr_grp_ipv4)); + __build_u8(ct, ATTR_MASTER_L4PROTO, pld, NTA_MASTER_L4PROTO); + if (nfct_attr_grp_is_set(ct, ATTR_GRP_MASTER_PORT)) { + __build_group(ct, ATTR_GRP_MASTER_PORT, + pld, NTA_MASTER_PORT, + sizeof(struct nfct_attr_grp_port)); + } + } else if (nfct_attr_grp_is_set(ct, ATTR_GRP_MASTER_IPV6)) { + __build_group(ct, ATTR_GRP_MASTER_IPV6, pld, NTA_MASTER_IPV6, + sizeof(struct nfct_attr_grp_ipv6)); + __build_u8(ct, ATTR_MASTER_L4PROTO, pld, NTA_MASTER_L4PROTO); + if (nfct_attr_grp_is_set(ct, ATTR_GRP_MASTER_PORT)) { + __build_group(ct, ATTR_GRP_MASTER_PORT, + pld, NTA_MASTER_PORT, + sizeof(struct nfct_attr_grp_port)); + } + } /* NAT */ - if (nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) { - uint32_t data = nfct_get_attr_u32(ct, ATTR_REPL_IPV4_DST); - __nat_build_u32(data, pld, ATTR_SNAT_IPV4); - } - if (nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) { - uint32_t data = nfct_get_attr_u32(ct, ATTR_REPL_IPV4_SRC); - __nat_build_u32(data, pld, ATTR_DNAT_IPV4); - } - if (nfct_getobjopt(ct, NFCT_GOPT_IS_SPAT)) { - uint16_t data = nfct_get_attr_u16(ct, ATTR_REPL_PORT_DST); - __nat_build_u16(data, pld, ATTR_SNAT_PORT); - } - if (nfct_getobjopt(ct, NFCT_GOPT_IS_DPAT)) { - uint16_t data = nfct_get_attr_u16(ct, ATTR_REPL_PORT_SRC); - __nat_build_u16(data, pld, ATTR_DNAT_PORT); - } + if (nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) + __build_u32(ct, ATTR_REPL_IPV4_DST, pld, NTA_SNAT_IPV4); + if (nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) + __build_u32(ct, ATTR_REPL_IPV4_SRC, pld, NTA_DNAT_IPV4); + if (nfct_getobjopt(ct, NFCT_GOPT_IS_SPAT)) + __build_u16(ct, ATTR_REPL_PORT_DST, pld, NTA_SPAT_PORT); + if (nfct_getobjopt(ct, NFCT_GOPT_IS_DPAT)) + __build_u16(ct, ATTR_REPL_PORT_SRC, pld, NTA_DPAT_PORT); /* NAT sequence adjustment */ - if (nfct_attr_is_set(ct, ATTR_ORIG_NAT_SEQ_CORRECTION_POS)) - __build_u32(ct, pld, ATTR_ORIG_NAT_SEQ_CORRECTION_POS); - if (nfct_attr_is_set(ct, ATTR_ORIG_NAT_SEQ_OFFSET_BEFORE)) - __build_u32(ct, pld, ATTR_ORIG_NAT_SEQ_OFFSET_BEFORE); - if (nfct_attr_is_set(ct, ATTR_ORIG_NAT_SEQ_OFFSET_AFTER)) - __build_u32(ct, pld, ATTR_ORIG_NAT_SEQ_OFFSET_AFTER); - if (nfct_attr_is_set(ct, ATTR_REPL_NAT_SEQ_CORRECTION_POS)) - __build_u32(ct, pld, ATTR_REPL_NAT_SEQ_CORRECTION_POS); - if (nfct_attr_is_set(ct, ATTR_REPL_NAT_SEQ_OFFSET_BEFORE)) - __build_u32(ct, pld, ATTR_REPL_NAT_SEQ_OFFSET_BEFORE); - if (nfct_attr_is_set(ct, ATTR_REPL_NAT_SEQ_OFFSET_AFTER)) - __build_u32(ct, pld, ATTR_REPL_NAT_SEQ_OFFSET_AFTER); + if (nfct_attr_is_set_array(ct, nat_type, 6)) + __build_natseqadj(ct, pld); pld->query = query; diff --git a/src/parse.c b/src/parse.c index b14e487..0184c5a 100644 --- a/src/parse.c +++ b/src/parse.c @@ -24,61 +24,127 @@ #define ssizeof(x) (int)sizeof(x) #endif -static void parse_u8(struct nf_conntrack *ct, int attr, void *data) +static void parse_u8(struct nf_conntrack *ct, int attr, void *data); +static void parse_u16(struct nf_conntrack *ct, int attr, void *data); +static void parse_u32(struct nf_conntrack *ct, int attr, void *data); +static void parse_group(struct nf_conntrack *ct, int attr, void *data); +static void parse_nat_seq_adj(struct nf_conntrack *ct, int attr, void *data); + +struct parser { + void (*parse)(struct nf_conntrack *ct, int attr, void *data); + int attr; +}; + +static struct parser h[ATTR_MAX] = { + [NTA_IPV4] = { + .parse = parse_group, + .attr = ATTR_GRP_ORIG_IPV4, + }, + [NTA_IPV6] = { + .parse = parse_group, + .attr = ATTR_GRP_ORIG_IPV6, + }, + [NTA_PORT] = { + .parse = parse_group, + .attr = ATTR_GRP_ORIG_PORT, + }, + [NTA_L4PROTO] = { + .parse = parse_u8, + .attr = ATTR_L4PROTO, + }, + [NTA_STATE] = { + .parse = parse_u8, + .attr = ATTR_TCP_STATE, + }, + [NTA_STATUS] = { + .parse = parse_u32, + .attr = ATTR_STATUS, + }, + [NTA_MARK] = { + .parse = parse_u32, + .attr = ATTR_MARK, + }, + [NTA_TIMEOUT] = { + .parse = parse_u32, + .attr = ATTR_TIMEOUT, + }, + [NTA_MASTER_IPV4] = { + .parse = parse_group, + .attr = ATTR_GRP_MASTER_IPV4, + }, + [NTA_MASTER_IPV6] = { + .parse = parse_group, + .attr = ATTR_GRP_MASTER_IPV6, + }, + [NTA_MASTER_PORT] = { + .parse = parse_group, + .attr = ATTR_GRP_MASTER_PORT, + }, + [NTA_SNAT_IPV4] = { + .parse = parse_u32, + .attr = ATTR_SNAT_IPV4, + }, + [NTA_DNAT_IPV4] = { + .parse = parse_u32, + .attr = ATTR_DNAT_IPV4, + }, + [NTA_SPAT_PORT] = { + .parse = parse_u16, + .attr = ATTR_SNAT_PORT, + }, + [NTA_DPAT_PORT] = { + .parse = parse_u16, + .attr = ATTR_SNAT_PORT, + }, + [NTA_NAT_SEQ_ADJ] = { + .parse = parse_nat_seq_adj, + }, +}; + +static void +parse_u8(struct nf_conntrack *ct, int attr, void *data) { uint8_t *value = (uint8_t *) data; - nfct_set_attr_u8(ct, attr, *value); + nfct_set_attr_u8(ct, h[attr].attr, *value); } -static void parse_u16(struct nf_conntrack *ct, int attr, void *data) +static void +parse_u16(struct nf_conntrack *ct, int attr, void *data) { uint16_t *value = (uint16_t *) data; - nfct_set_attr_u16(ct, attr, ntohs(*value)); + nfct_set_attr_u16(ct, h[attr].attr, ntohs(*value)); } -static void parse_u32(struct nf_conntrack *ct, int attr, void *data) +static void +parse_u32(struct nf_conntrack *ct, int attr, void *data) { uint32_t *value = (uint32_t *) data; - nfct_set_attr_u32(ct, attr, ntohl(*value)); + nfct_set_attr_u32(ct, h[attr].attr, ntohl(*value)); } -static void parse_pointer_be(struct nf_conntrack *ct, int attr, void *data) +static void +parse_group(struct nf_conntrack *ct, int attr, void *data) { - nfct_set_attr(ct, attr, data); + nfct_set_attr_grp(ct, h[attr].attr, data); } -typedef void (*parse)(struct nf_conntrack *ct, int attr, void *data); - -static parse h[ATTR_MAX] = { - [ATTR_IPV4_SRC] = parse_pointer_be, - [ATTR_IPV4_DST] = parse_pointer_be, - [ATTR_IPV6_SRC] = parse_pointer_be, - [ATTR_IPV6_DST] = parse_pointer_be, - [ATTR_L3PROTO] = parse_u8, - [ATTR_PORT_SRC] = parse_u16, - [ATTR_PORT_DST] = parse_u16, - [ATTR_L4PROTO] = parse_u8, - [ATTR_TCP_STATE] = parse_u8, - [ATTR_SNAT_IPV4] = parse_u32, - [ATTR_DNAT_IPV4] = parse_u32, - [ATTR_SNAT_PORT] = parse_u16, - [ATTR_DNAT_PORT] = parse_u16, - [ATTR_TIMEOUT] = parse_u32, - [ATTR_MARK] = parse_u32, - [ATTR_STATUS] = parse_u32, - [ATTR_MASTER_IPV4_SRC] = parse_u32, - [ATTR_MASTER_IPV4_DST] = parse_u32, - [ATTR_MASTER_L3PROTO] = parse_u8, - [ATTR_MASTER_PORT_SRC] = parse_u16, - [ATTR_MASTER_PORT_DST] = parse_u16, - [ATTR_MASTER_L4PROTO] = parse_u8, - [ATTR_ORIG_NAT_SEQ_CORRECTION_POS] = parse_u32, - [ATTR_ORIG_NAT_SEQ_OFFSET_BEFORE] = parse_u32, - [ATTR_ORIG_NAT_SEQ_OFFSET_AFTER] = parse_u32, - [ATTR_REPL_NAT_SEQ_CORRECTION_POS] = parse_u32, - [ATTR_REPL_NAT_SEQ_OFFSET_BEFORE] = parse_u32, - [ATTR_REPL_NAT_SEQ_OFFSET_AFTER] = parse_u32, -}; +static void +parse_nat_seq_adj(struct nf_conntrack *ct, int attr, void *data) +{ + struct nta_attr_natseqadj *this = data; + nfct_set_attr_u32(ct, ATTR_ORIG_NAT_SEQ_CORRECTION_POS, + ntohl(this->orig_seq_correction_pos)); + nfct_set_attr_u32(ct, ATTR_ORIG_NAT_SEQ_OFFSET_BEFORE, + ntohl(this->orig_seq_correction_pos)); + nfct_set_attr_u32(ct, ATTR_ORIG_NAT_SEQ_OFFSET_AFTER, + ntohl(this->orig_seq_correction_pos)); + nfct_set_attr_u32(ct, ATTR_REPL_NAT_SEQ_CORRECTION_POS, + ntohl(this->orig_seq_correction_pos)); + nfct_set_attr_u32(ct, ATTR_REPL_NAT_SEQ_OFFSET_BEFORE, + ntohl(this->orig_seq_correction_pos)); + nfct_set_attr_u32(ct, ATTR_REPL_NAT_SEQ_OFFSET_AFTER, + ntohl(this->orig_seq_correction_pos)); +} int parse_netpld(struct nf_conntrack *ct, @@ -109,8 +175,11 @@ parse_netpld(struct nf_conntrack *ct, ATTR_NETWORK2HOST(attr); if (attr->nta_len > len) return -1; - if (h[attr->nta_attr]) - h[attr->nta_attr](ct, attr->nta_attr, NTA_DATA(attr)); + if (h[attr->nta_attr].parse == NULL) { + attr = NTA_NEXT(attr, len); + continue; + } + h[attr->nta_attr].parse(ct, attr->nta_attr, NTA_DATA(attr)); attr = NTA_NEXT(attr, len); } |