summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2008-11-02 21:35:42 +0100
committerPablo Neira Ayuso <pablo@netfilter.org>2008-11-02 21:35:42 +0100
commit76ac8ebe5e49385585c8e29fe530ed4baef390bf (patch)
tree4d0bdca7d2f039a173152dde44818b13d485ec49 /src
parent64ce47955778805afceb6ced58b63839763541ad (diff)
downloadconntrack-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.c202
-rw-r--r--src/parse.c153
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);
}