From 5eb3bc6d5594fccfff26329a26225f999e971652 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Mon, 16 Apr 2007 19:08:42 +0000 Subject: first step forward to merge conntrackd and conntrack into the same building chain --- src/sync-notrack.c | 127 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 src/sync-notrack.c (limited to 'src/sync-notrack.c') diff --git a/src/sync-notrack.c b/src/sync-notrack.c new file mode 100644 index 0000000..2b5ae38 --- /dev/null +++ b/src/sync-notrack.c @@ -0,0 +1,127 @@ +/* + * (C) 2006-2007 by Pablo Neira Ayuso + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "conntrackd.h" +#include "sync.h" +#include "network.h" +#include "us-conntrack.h" +#include "alarm.h" + +static void refresher(struct alarm_list *a, void *data) +{ + struct us_conntrack *u = data; + char buf[8192]; + int size; + + if (nfct_get_attr_u32(u->ct, ATTR_STATUS) & IPS_DYING) { + + debug_ct(u->ct, "persistence destroy"); + + size = build_network_msg(NFCT_Q_DESTROY, + STATE(subsys_event), + u->ct, + buf, + sizeof(buf)); + + __cache_del(u->cache, u->ct); + mcast_send_netmsg(STATE_SYNC(mcast_client), buf); + } else { + + debug_ct(u->ct, "persistence update"); + + a->expires = random() % CONFIG(refresh) + 1; + size = build_network_msg(NFCT_Q_UPDATE, + STATE(subsys_event), + u->ct, + buf, + sizeof(buf)); + mcast_send_netmsg(STATE_SYNC(mcast_client), buf); + } +} + +static void cache_notrack_add(struct us_conntrack *u, void *data) +{ + struct alarm_list *alarm = data; + + init_alarm(alarm); + set_alarm_expiration(alarm, (random() % conf.refresh) + 1); + set_alarm_data(alarm, u); + set_alarm_function(alarm, refresher); + add_alarm(alarm); +} + +static void cache_notrack_update(struct us_conntrack *u, void *data) +{ + struct alarm_list *alarm = data; + mod_alarm(alarm, (random() % conf.refresh) + 1); +} + +static void cache_notrack_destroy(struct us_conntrack *u, void *data) +{ + struct alarm_list *alarm = data; + del_alarm(alarm); +} + +static struct cache_extra cache_notrack_extra = { + .size = sizeof(struct alarm_list), + .add = cache_notrack_add, + .update = cache_notrack_update, + .destroy = cache_notrack_destroy +}; + +static int notrack_pre_recv(const struct nlnetwork *net) +{ + unsigned int exp_seq; + + /* + * Ignore error messages: Although this message type is not ever + * generated in notrack mode, we don't want to crash the daemon + * if someone nuts mixes nack and notrack. + */ + if (net->flags & (NET_RESYNC | NET_NACK)) + return 1; + + /* + * Multicast sequence tracking: we keep track of multicast messages + * although we don't do any explicit message recovery. So, why do + * we do sequence tracking? Just to let know the sysadmin. + * + * Let t be 1 < t < RefreshTime. To ensure consistency, conntrackd + * retransmit every t seconds a message with the state of a certain + * entry even if such entry did not change. This mechanism also + * provides passive resynchronization, in other words, there is + * no facility to request a full synchronization from new nodes that + * just joined the cluster, instead they just get resynchronized in + * RefreshTime seconds at worst case. + */ + mcast_track_seq(net->seq, &exp_seq); + + return 0; +} + +static void notrack_post_send(const struct nlnetwork *n, struct us_conntrack *u) +{ +} + +struct sync_mode notrack = { + .internal_cache_flags = LIFETIME, + .external_cache_flags = TIMER | LIFETIME, + .internal_cache_extra = &cache_notrack_extra, + .pre_recv = notrack_pre_recv, + .post_send = notrack_post_send, +}; -- cgit v1.2.3 From 2932c6b8e6952ae84b221b854b43810c61e5c8fa Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Fri, 18 May 2007 19:33:40 +0000 Subject: - remove dead code sync-mode.c - flush nack queue in the conntrackd -f path - do not increase add_fail counter for EEXIST errors - cleanup sync-nack code - improve mcast_recv_netmsg: sanity check before checksumming! --- include/sync.h | 4 ++- src/cache.c | 9 ++++--- src/cache_iterators.c | 6 ++++- src/network.c | 47 ++++++++++++++++++++++++---------- src/sync-mode.c | 51 ++++++++++-------------------------- src/sync-nack.c | 71 ++++++++++++++++++++++++--------------------------- src/sync-notrack.c | 4 ++- 7 files changed, 96 insertions(+), 96 deletions(-) (limited to 'src/sync-notrack.c') diff --git a/include/sync.h b/include/sync.h index 7756c87..d8f1bca 100644 --- a/include/sync.h +++ b/include/sync.h @@ -14,7 +14,9 @@ struct sync_mode { void (*kill)(void); int (*local)(int fd, int type, void *data); int (*pre_recv)(const struct nlnetwork *net); - void (*post_send)(const struct nlnetwork *net, struct us_conntrack *u); + void (*post_send)(int type, + const struct nlnetwork *net, + struct us_conntrack *u); }; extern struct sync_mode notrack; diff --git a/src/cache.c b/src/cache.c index 6f7442b..32caee5 100644 --- a/src/cache.c +++ b/src/cache.c @@ -228,7 +228,7 @@ static struct us_conntrack *__add(struct cache *c, struct nf_conntrack *ct) data += c->features[i]->size; } - if (c->extra) + if (c->extra && c->extra->add) c->extra->add(u, ((void *) u) + c->extra_offset); return u; @@ -247,7 +247,8 @@ struct us_conntrack *__cache_add(struct cache *c, struct nf_conntrack *ct) c->add_ok++; return u; } - c->add_fail++; + if (errno != EEXIST) + c->add_fail++; return NULL; } @@ -281,7 +282,7 @@ static struct us_conntrack *__update(struct cache *c, struct nf_conntrack *ct) data += c->features[i]->size; } - if (c->extra) + if (c->extra && c->extra->update) c->extra->update(u, ((void *) u) + c->extra_offset); if (nfct_attr_is_set(ct, ATTR_STATUS)) @@ -380,7 +381,7 @@ static int __del(struct cache *c, struct nf_conntrack *ct) data += c->features[i]->size; } - if (c->extra) + if (c->extra && c->extra->destroy) c->extra->destroy(u, ((void *) u) + c->extra_offset); hashtable_del(c->h, u); diff --git a/src/cache_iterators.c b/src/cache_iterators.c index 5d5d22b..e1f3798 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -182,6 +182,10 @@ static int do_flush(void *data1, void *data2) c->features[i]->destroy(u, data); data += c->features[i]->size; } + + if (c->extra && c->extra->destroy) + c->extra->destroy(u, ((void *) u) + c->extra_offset); + free(u->ct); return 0; @@ -215,7 +219,7 @@ static int do_bulk(void *data1, void *data2) debug_ct(u->ct, "failed to build"); mcast_send_netmsg(STATE_SYNC(mcast_client), net); - STATE_SYNC(mcast_sync)->post_send(net, u); + STATE_SYNC(mcast_sync)->post_send(NFCT_T_UPDATE, net, u); /* keep iterating even if we have found errors */ return 0; diff --git a/src/network.c b/src/network.c index b9be318..51e89c7 100644 --- a/src/network.c +++ b/src/network.c @@ -70,7 +70,7 @@ int mcast_resend_netmsg(struct mcast_sock *m, void *data) { struct nlnetwork *net = data; struct nlmsghdr *nlh = data + sizeof(struct nlnetwork); - unsigned int len = htonl(nlh->nlmsg_len) + sizeof(struct nlnetwork); + unsigned int len; net->flags = ntohs(net->flags); @@ -80,10 +80,10 @@ int mcast_resend_netmsg(struct mcast_sock *m, void *data) net->flags |= NET_HELLO; } - if (net->flags & NET_NACK || net->flags & NET_ACK) { - struct nlnetwork_ack *nack = (struct nlnetwork_ack *) net; + if (net->flags & NET_NACK || net->flags & NET_ACK) len = sizeof(struct nlnetwork_ack); - } + else + len = sizeof(struct nlnetwork) + ntohl(nlh->nlmsg_len); net->flags = htons(net->flags); net->seq = htonl(cur_seq++); @@ -147,32 +147,44 @@ int mcast_recv_netmsg(struct mcast_sock *m, void *data, int len) if (ret <= 0) return ret; + /* message too small: no room for the header */ if (ret < sizeof(struct nlnetwork)) return -1; - if (!valid_checksum(data, ret)) - return -1; - - net->flags = ntohs(net->flags); - net->seq = ntohl(net->seq); - - if (net->flags & NET_HELLO) - STATE_SYNC(last_seq_recv) = net->seq-1; + if (ntohs(net->flags) & NET_HELLO) + STATE_SYNC(last_seq_recv) = ntohl(net->seq) - 1; - if (net->flags & NET_NACK || net->flags & NET_ACK) { + if (ntohs(net->flags) & NET_NACK || ntohs(net->flags) & NET_ACK) { struct nlnetwork_ack *nack = (struct nlnetwork_ack *) net; + /* message too small: no room for the header */ if (ret < sizeof(struct nlnetwork_ack)) return -1; + if (!valid_checksum(data, ret)) + return -1; + + /* host byte order conversion */ + net->flags = ntohs(net->flags); + net->seq = ntohl(net->seq); + + /* acknowledgement conversion */ nack->from = ntohl(nack->from); nack->to = ntohl(nack->to); return ret; } - if (net->flags & NET_RESYNC) + if (ntohs(net->flags) & NET_RESYNC) { + if (!valid_checksum(data, ret)) + return -1; + + /* host byte order conversion */ + net->flags = ntohs(net->flags); + net->seq = ntohl(net->seq); + return ret; + } /* information received is too small */ if (ret < NLMSG_SPACE(sizeof(struct nfgenmsg))) @@ -197,6 +209,13 @@ int mcast_recv_netmsg(struct mcast_sock *m, void *data, int len) if (nfhdr->version != NFNETLINK_V0) return -1; + if (!valid_checksum(data, ret)) + return -1; + + /* host byte order conversion */ + net->flags = ntohs(net->flags); + net->seq = ntohl(net->seq); + if (nlh_network2host(nlh) == -1) return -1; diff --git a/src/sync-mode.c b/src/sync-mode.c index b32bef7..0a195d7 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -282,18 +282,15 @@ static void mcast_send_sync(struct nlmsghdr *nlh, { char buf[4096]; struct nlnetwork *net = (struct nlnetwork *) buf; - int mangled = 0; memset(buf, 0, sizeof(buf)); if (!state_helper_verdict(type, ct)) return; - if (!mangled) - memcpy(buf + sizeof(struct nlnetwork), nlh, nlh->nlmsg_len); - + memcpy(buf + sizeof(struct nlnetwork), nlh, nlh->nlmsg_len); mcast_send_netmsg(STATE_SYNC(mcast_client), net); - STATE_SYNC(mcast_sync)->post_send(net, u); + STATE_SYNC(mcast_sync)->post_send(type, net, u); } static void overrun_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh) @@ -333,7 +330,8 @@ retry: } else { if (errno == EEXIST) { char buf[4096]; - struct nlmsghdr *nlh = (struct nlmsghdr *) buf; + unsigned int size = sizeof(struct nlnetwork); + struct nlmsghdr *nlh = (struct nlmsghdr *) (buf + size); int ret = build_network_msg(NFCT_Q_DESTROY, STATE(subsys_event), @@ -344,9 +342,10 @@ retry: return; cache_del(STATE_SYNC(internal), ct); - mcast_send_sync(nlh, NULL, ct, NFCT_T_NEW); + mcast_send_sync(nlh, NULL, ct, NFCT_T_DESTROY); goto retry; } + dlog(STATE(log), "can't add to internal cache: " "%s\n", strerror(errno)); debug_ct(ct, "can't add"); @@ -360,19 +359,8 @@ static void event_update_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh) nfct_attr_unset(ct, ATTR_TIMEOUT); if ((u = cache_update(STATE_SYNC(internal), ct)) == NULL) { - /* - * Perhaps we are losing events. If we are working - * in relax mode then add a new entry to the cache. - * - * FIXME: relax transitions not implemented yet - */ - if ((CONFIG(flags) & RELAX_TRANSITIONS) - && (u = cache_add(STATE_SYNC(internal), ct))) { - debug_ct(u->ct, "forcing internal update"); - } else { - debug_ct(ct, "can't update"); - return; - } + debug_ct(ct, "can't update"); + return; } debug_ct(u->ct, "internal update"); mcast_send_sync(nlh, u, ct, NFCT_T_UPDATE); @@ -382,24 +370,11 @@ static int event_destroy_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh) { nfct_attr_unset(ct, ATTR_TIMEOUT); - if (CONFIG(flags) & DELAY_DESTROY_MSG) { - - nfct_set_attr_u32(ct, ATTR_STATUS, IPS_DYING); - - if (cache_update(STATE_SYNC(internal), ct)) { - debug_ct(ct, "delay internal destroy"); - return 1; - } else { - debug_ct(ct, "can't delay destroy!"); - return 0; - } - } else { - if (cache_del(STATE_SYNC(internal), ct)) { - mcast_send_sync(nlh, NULL, ct, NFCT_T_DESTROY); - debug_ct(ct, "internal destroy"); - } else - debug_ct(ct, "can't destroy"); - } + if (cache_del(STATE_SYNC(internal), ct)) { + mcast_send_sync(nlh, NULL, ct, NFCT_T_DESTROY); + debug_ct(ct, "internal destroy"); + } else + debug_ct(ct, "can't destroy"); } struct ct_mode sync_mode = { diff --git a/src/sync-nack.c b/src/sync-nack.c index 288dba4..73f6dc2 100644 --- a/src/sync-nack.c +++ b/src/sync-nack.c @@ -43,37 +43,24 @@ struct cache_nack { static void cache_nack_add(struct us_conntrack *u, void *data) { struct cache_nack *cn = data; - INIT_LIST_HEAD(&cn->head); - list_add(&cn->head, &queue); } -static void cache_nack_update(struct us_conntrack *u, void *data) +static void cache_nack_del(struct us_conntrack *u, void *data) { struct cache_nack *cn = data; - if (cn->head.next != LIST_POISON1 && - cn->head.prev != LIST_POISON2) - list_del(&cn->head); + if (cn->head.next == &cn->head && + cn->head.prev == &cn->head) + return; - INIT_LIST_HEAD(&cn->head); - list_add(&cn->head, &queue); -} - -static void cache_nack_destroy(struct us_conntrack *u, void *data) -{ - struct cache_nack *cn = data; - - if (cn->head.next != LIST_POISON1 && - cn->head.prev != LIST_POISON2) - list_del(&cn->head); + list_del(&cn->head); } static struct cache_extra cache_nack_extra = { .size = sizeof(struct cache_nack), .add = cache_nack_add, - .update = cache_nack_update, - .destroy = cache_nack_destroy + .destroy = cache_nack_del }; static int nack_init() @@ -200,7 +187,9 @@ static void queue_resend(struct cache *c, unsigned int from, unsigned int to) } mcast_send_netmsg(STATE_SYNC(mcast_client), buf); - STATE_SYNC(mcast_sync)->post_send(net, u); + STATE_SYNC(mcast_sync)->post_send(NFCT_T_UPDATE, + net, + u); dp("(newseq=%u)\n", *seq); } } @@ -224,6 +213,7 @@ static void queue_empty(struct cache *c, unsigned int from, unsigned int to) debug_ct(u->ct, "ack received: empty queue"); dp("queue: deleting from queue (seq=%u)\n", cn->seq); list_del(&cn->head); + INIT_LIST_HEAD(&cn->head); } } unlock(); @@ -272,28 +262,35 @@ static int nack_pre_recv(const struct nlnetwork *net) return 0; } -static void nack_post_send(const struct nlnetwork *net, struct us_conntrack *u) +static void nack_post_send(int type, + const struct nlnetwork *net, + struct us_conntrack *u) { - unsigned int size = sizeof(struct nlnetwork); - struct nlmsghdr *nlh = (struct nlmsghdr *) ((void *) net + size); - - if (NFNL_MSG_TYPE(ntohs(nlh->nlmsg_type)) == IPCTNL_MSG_CT_DELETE) { - buffer_add(STATE_SYNC(buffer), net, - ntohl(nlh->nlmsg_len) + size); - } else if (u != NULL) { - unsigned int *seq; - struct list_head *n; - struct cache_nack *cn; - - cn = (struct cache_nack *) + unsigned int size = sizeof(struct nlnetwork); + struct nlmsghdr *nlh = (struct nlmsghdr *) ((void *) net + size); + struct cache_nack *cn; + + size += ntohl(nlh->nlmsg_len); + + switch(type) { + case NFCT_T_NEW: + case NFCT_T_UPDATE: + cn = (struct cache_nack *) cache_get_extra(STATE_SYNC(internal), u); - cn->seq = ntohl(net->seq); - if (cn->head.next != LIST_POISON1 && - cn->head.prev != LIST_POISON2) - list_del(&cn->head); + if (cn->head.next == &cn->head && + cn->head.prev == &cn->head) + goto insert; + + list_del(&cn->head); INIT_LIST_HEAD(&cn->head); +insert: + cn->seq = ntohl(net->seq); list_add(&cn->head, &queue); + break; + case NFCT_T_DESTROY: + buffer_add(STATE_SYNC(buffer), net, size); + break; } } diff --git a/src/sync-notrack.c b/src/sync-notrack.c index 2b5ae38..cc56436 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -114,7 +114,9 @@ static int notrack_pre_recv(const struct nlnetwork *net) return 0; } -static void notrack_post_send(const struct nlnetwork *n, struct us_conntrack *u) +static void notrack_post_send(int type, + const struct nlnetwork *n, + struct us_conntrack *u) { } -- cgit v1.2.3 From cea33148e4ccf108f587e5796c026600aba35ab1 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Mon, 4 Jun 2007 15:19:42 +0000 Subject: o remove useless backlog parameter in multicast sockets o remove reminiscents of delay destroy message and relax transitions o remove confusing StripNAT parameter: NAT support enabled by default o relax event tracking: *_update callbacks use cache_update_force o use wraparound-aware functions after/before/between o lots of cleanups --- ChangeLog | 6 ++ configure.in | 2 +- examples/sync/nack/node1/conntrackd.conf | 6 -- examples/sync/nack/node2/conntrackd.conf | 6 -- examples/sync/persistent/node1/conntrackd.conf | 6 -- examples/sync/persistent/node2/conntrackd.conf | 6 -- include/conntrackd.h | 17 +--- include/mcast.h | 1 - include/network.h | 19 +++++ include/sync.h | 8 +- src/cache_iterators.c | 3 +- src/netlink.c | 6 +- src/network.c | 27 ++----- src/read_config_yy.y | 12 ++- src/stats-mode.c | 20 +---- src/sync-mode.c | 104 +++++++++++-------------- src/sync-nack.c | 27 ++++--- src/sync-notrack.c | 44 +++-------- 18 files changed, 122 insertions(+), 198 deletions(-) (limited to 'src/sync-notrack.c') diff --git a/ChangeLog b/ChangeLog index 396d3a4..05348e1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,6 +5,12 @@ version 0.9.4 (yet unreleased) o simplify checksum code: use UDP/multicast checksum facilities o fix silly bug in build_network_message: out of bound memset o fix error message in configure.in (Eric Leblond) +o remove useless backlog parameter in multicast sockets +o remove reminiscents of delay destroy message and relax transitions +o remove confusing StripNAT parameter: NAT support enabled by default +o relax event tracking: *_update callbacks use cache_update_force +o use wraparound-aware functions after/before/between +o lots of cleanups = conntrack = o fix segfault with conntrack --output (Krzysztof Oledzky) diff --git a/configure.in b/configure.in index 7a1445d..37e7a9c 100644 --- a/configure.in +++ b/configure.in @@ -1,4 +1,4 @@ -AC_INIT(conntrack-tools, 0.9.3, pablo@netfilter.org) +AC_INIT(conntrack-tools, 0.9.4, pablo@netfilter.org) AC_CANONICAL_SYSTEM diff --git a/examples/sync/nack/node1/conntrackd.conf b/examples/sync/nack/node1/conntrackd.conf index f24fa7e..edec9cf 100644 --- a/examples/sync/nack/node1/conntrackd.conf +++ b/examples/sync/nack/node1/conntrackd.conf @@ -33,7 +33,6 @@ Sync { IPv4_address 225.0.0.50 IPv4_interface 192.168.100.100 # IP of dedicated link Group 3780 - Backlog 20 } # Enable/Disable message checksumming @@ -118,8 +117,3 @@ IgnoreProtocol { VRRP # numeric numbers also valid } - -# -# Strip NAT traffic -# -StripNAT diff --git a/examples/sync/nack/node2/conntrackd.conf b/examples/sync/nack/node2/conntrackd.conf index 4f15773..de5f4d2 100644 --- a/examples/sync/nack/node2/conntrackd.conf +++ b/examples/sync/nack/node2/conntrackd.conf @@ -32,7 +32,6 @@ Sync { IPv4_address 225.0.0.50 IPv4_interface 192.168.100.200 # IP of dedicated link Group 3780 - Backlog 20 } # Enable/Disable message checksumming @@ -117,8 +116,3 @@ IgnoreProtocol { VRRP # numeric numbers also valid } - -# -# Strip NAT traffic -# -StripNAT diff --git a/examples/sync/persistent/node1/conntrackd.conf b/examples/sync/persistent/node1/conntrackd.conf index 90afeb7..60f264b 100644 --- a/examples/sync/persistent/node1/conntrackd.conf +++ b/examples/sync/persistent/node1/conntrackd.conf @@ -38,7 +38,6 @@ Sync { IPv4_address 225.0.0.50 IPv4_interface 192.168.100.100 # IP of dedicated link Group 3780 - Backlog 20 } # Enable/Disable message checksumming @@ -123,8 +122,3 @@ IgnoreProtocol { VRRP # numeric numbers also valid } - -# -# Strip NAT traffic -# -StripNAT diff --git a/examples/sync/persistent/node2/conntrackd.conf b/examples/sync/persistent/node2/conntrackd.conf index aee4a29..6a1806b 100644 --- a/examples/sync/persistent/node2/conntrackd.conf +++ b/examples/sync/persistent/node2/conntrackd.conf @@ -38,7 +38,6 @@ Sync { IPv4_address 225.0.0.50 IPv4_interface 192.168.100.200 # IP of dedicated link Group 3780 - Backlog 20 } # Enable/Disable message checksumming @@ -123,8 +122,3 @@ IgnoreProtocol { VRRP # numeric numbers also valid } - -# -# Strip NAT traffic -# -StripNAT diff --git a/include/conntrackd.h b/include/conntrackd.h index 76b9747..a620400 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -30,22 +30,13 @@ #define DEFAULT_LOCKFILE "/var/lock/conntrackd.lock" enum { - STRIP_NAT_BIT = 0, - STRIP_NAT = (1 << STRIP_NAT_BIT), - - DELAY_DESTROY_MSG_BIT = 1, - DELAY_DESTROY_MSG = (1 << DELAY_DESTROY_MSG_BIT), - - RELAX_TRANSITIONS_BIT = 2, - RELAX_TRANSITIONS = (1 << RELAX_TRANSITIONS_BIT), - - SYNC_MODE_PERSISTENT_BIT = 3, + SYNC_MODE_PERSISTENT_BIT = 0, SYNC_MODE_PERSISTENT = (1 << SYNC_MODE_PERSISTENT_BIT), - SYNC_MODE_NACK_BIT = 4, + SYNC_MODE_NACK_BIT = 1, SYNC_MODE_NACK = (1 << SYNC_MODE_NACK_BIT), - DONT_CHECKSUM_BIT = 5, + DONT_CHECKSUM_BIT = 2, DONT_CHECKSUM = (1 << DONT_CHECKSUM_BIT), }; @@ -122,7 +113,7 @@ struct ct_sync_state { struct mcast_sock *mcast_server; /* multicast socket: incoming */ struct mcast_sock *mcast_client; /* multicast socket: outgoing */ - struct sync_mode *mcast_sync; + struct sync_mode *sync; /* sync mode */ struct buffer *buffer; u_int32_t last_seq_sent; /* last sequence number sent */ diff --git a/include/mcast.h b/include/mcast.h index be1d0cd..66676dc 100644 --- a/include/mcast.h +++ b/include/mcast.h @@ -5,7 +5,6 @@ struct mcast_conf { int ipproto; - int backlog; int reuseaddr; int checksum; unsigned short port; diff --git a/include/network.h b/include/network.h index 176274e..5ba808a 100644 --- a/include/network.h +++ b/include/network.h @@ -30,4 +30,23 @@ enum { NET_ACK = (1 << NET_ACK_BIT), }; +/* extracted from net/tcp.h */ + +/* + * The next routines deal with comparing 32 bit unsigned ints + * and worry about wraparound (automatic with unsigned arithmetic). + */ + +static inline int before(__u32 seq1, __u32 seq2) +{ + return (__s32)(seq1-seq2) < 0; +} +#define after(seq2, seq1) before(seq1, seq2) + +/* is s2<=s1<=s3 ? */ +static inline int between(__u32 seq1, __u32 seq2, __u32 seq3) +{ + return seq3 - seq2 >= seq1 - seq2; +} + #endif diff --git a/include/sync.h b/include/sync.h index d8f1bca..72f6313 100644 --- a/include/sync.h +++ b/include/sync.h @@ -13,10 +13,10 @@ struct sync_mode { int (*init)(void); void (*kill)(void); int (*local)(int fd, int type, void *data); - int (*pre_recv)(const struct nlnetwork *net); - void (*post_send)(int type, - const struct nlnetwork *net, - struct us_conntrack *u); + int (*recv)(const struct nlnetwork *net); /* recv callback */ + void (*send)(int type, /* send callback */ + const struct nlnetwork *net, + struct us_conntrack *u); }; extern struct sync_mode notrack; diff --git a/src/cache_iterators.c b/src/cache_iterators.c index 1c03fef..fd6694a 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -219,7 +219,8 @@ static int do_bulk(void *data1, void *data2) debug_ct(u->ct, "failed to build"); mcast_send_netmsg(STATE_SYNC(mcast_client), net); - STATE_SYNC(mcast_sync)->post_send(NFCT_T_UPDATE, net, u); + if (STATE_SYNC(sync)->send) + STATE_SYNC(sync)->send(NFCT_T_UPDATE, net, u); /* keep iterating even if we have found errors */ return 0; diff --git a/src/netlink.c b/src/netlink.c index b1f9fd7..5f7cbeb 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -32,15 +32,13 @@ int ignore_conntrack(struct nf_conntrack *ct) return 1; /* Accept DNAT'ed traffic: not really coming to the local machine */ - if ((CONFIG(flags) & STRIP_NAT) && - nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) { + if (nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) { debug_ct(ct, "DNAT"); return 0; } /* Accept SNAT'ed traffic: not really coming to the local machine */ - if ((CONFIG(flags) & STRIP_NAT) && - nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) { + if (nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) { debug_ct(ct, "SNAT"); return 0; } diff --git a/src/network.c b/src/network.c index abd30fe..a7ce740 100644 --- a/src/network.c +++ b/src/network.c @@ -205,33 +205,16 @@ int mcast_track_seq(u_int32_t seq, u_int32_t *exp_seq) goto out; /* out of sequence: some messages got lost */ - if (seq > STATE_SYNC(last_seq_recv)+1) { + if (after(seq, STATE_SYNC(last_seq_recv)+1)) { STATE_SYNC(packets_lost) += seq-STATE_SYNC(last_seq_recv)+1; ret = 0; goto out; } - /* out of sequence: replayed or sequence wrapped around issues */ - if (seq < STATE_SYNC(last_seq_recv)+1) { - /* - * Check if the sequence has wrapped around. - * Perhaps it can be a replayed packet. - */ - if (STATE_SYNC(last_seq_recv)+1-seq > ~0U/2) { - /* - * Indeed, it is a wrapped around - */ - STATE_SYNC(packets_lost) += - ~0U-STATE_SYNC(last_seq_recv)+1+seq; - } else { - /* - * It is a delayed packet - */ - dlog(STATE(log), "delayed packet? exp=%u rcv=%u", - STATE_SYNC(last_seq_recv)+1, seq); - } - ret = 0; - } + /* out of sequence: replayed/delayed packet? */ + if (before(seq, STATE_SYNC(last_seq_recv)+1)) + dlog(STATE(log), "delayed packet? exp=%u rcv=%u", + STATE_SYNC(last_seq_recv)+1, seq); out: *exp_seq = STATE_SYNC(last_seq_recv)+1; diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 988b540..57250b4 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -84,7 +84,8 @@ lock : T_LOCK T_PATH_VAL strip_nat: T_STRIP_NAT { - conf.flags |= STRIP_NAT; + fprintf(stderr, "Notice: StripNAT clause is obsolete. " + "Please, remove it from conntrackd.conf\n"); }; refreshtime : T_REFRESH T_NUMBER @@ -228,7 +229,8 @@ multicast_option : T_IPV6_IFACE T_IP multicast_option : T_BACKLOG T_NUMBER { - conf.mcast.backlog = $2; + fprintf(stderr, "Notice: Backlog option inside Multicast clause is " + "obsolete. Please, remove it from conntrackd.conf.\n"); }; multicast_option : T_GROUP T_NUMBER @@ -354,12 +356,14 @@ window_size: T_WINDOWSIZE T_NUMBER relax_transitions: T_RELAX_TRANSITIONS { - conf.flags |= RELAX_TRANSITIONS; + fprintf(stderr, "Notice: RelaxTransitions clause is obsolete. " + "Please, remove it from conntrackd.conf\n"); }; delay_destroy_msgs: T_DELAY { - conf.flags |= DELAY_DESTROY_MSG; + fprintf(stderr, "Notice: DelayDestroyMessages clause is obsolete. " + "Please, remove it from conntrackd.conf\n"); }; listen_to: T_LISTEN_TO T_IP diff --git a/src/stats-mode.c b/src/stats-mode.c index 22474e2..f65fbdb 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -139,7 +139,6 @@ static void overrun_stats() static void event_new_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh) { - debug_ct(ct, "debug event"); if (cache_add(STATE_STATS(cache), ct)) { debug_ct(ct, "cache new"); } else { @@ -151,22 +150,9 @@ static void event_new_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh) static void event_update_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh) { - debug_ct(ct, "update"); - - if (!cache_update(STATE_STATS(cache), ct)) { - /* - * Perhaps we are losing events. If we are working - * in relax mode then add a new entry to the cache. - * - * FIXME: relax transitions not implemented yet - */ - if ((CONFIG(flags) & RELAX_TRANSITIONS) - && cache_add(STATE_STATS(cache), ct)) { - debug_ct(ct, "forcing cache update"); - } else { - debug_ct(ct, "can't update"); - return; - } + if (!cache_update_force(STATE_STATS(cache), ct)) { + debug_ct(ct, "can't update"); + return; } debug_ct(ct, "update"); } diff --git a/src/sync-mode.c b/src/sync-mode.c index d7bee9d..cb95392 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -32,26 +32,25 @@ static void mcast_handler() { int ret; - char buf[4096], tmp[256]; - struct mcast_sock *m = STATE_SYNC(mcast_server); - unsigned int type; - struct nlnetwork *net = (struct nlnetwork *) buf; - unsigned int size = sizeof(struct nlnetwork); - struct nlmsghdr *nlh = (struct nlmsghdr *) (buf + size); - struct nf_conntrack *ct = (struct nf_conntrack *) tmp; + unsigned int type, size = sizeof(struct nlnetwork); + char __net[4096]; + struct nlnetwork *net = (struct nlnetwork *) __net; + struct nlmsghdr *nlh = (struct nlmsghdr *) (__net + size); + char __ct[nfct_maxsize()]; + struct nf_conntrack *ct = (struct nf_conntrack *) __ct; struct us_conntrack *u = NULL; - memset(tmp, 0, sizeof(tmp)); - - ret = mcast_recv_netmsg(m, buf, sizeof(buf)); + ret = mcast_recv_netmsg(STATE_SYNC(mcast_server), net, sizeof(__net)); if (ret <= 0) { STATE(malformed)++; return; } - if (STATE_SYNC(mcast_sync)->pre_recv(net)) + if (STATE_SYNC(sync)->recv(net)) return; + memset(ct, 0, sizeof(__ct)); + if ((type = parse_network_msg(ct, nlh)) == NFCT_T_ERROR) { STATE(malformed)++; return; @@ -111,19 +110,19 @@ static int init_sync(void) memset(state.sync, 0, sizeof(struct ct_sync_state)); if (CONFIG(flags) & SYNC_MODE_NACK) - STATE_SYNC(mcast_sync) = &nack; + STATE_SYNC(sync) = &nack; else /* default to persistent mode */ - STATE_SYNC(mcast_sync) = ¬rack; + STATE_SYNC(sync) = ¬rack; - if (STATE_SYNC(mcast_sync)->init) - STATE_SYNC(mcast_sync)->init(); + if (STATE_SYNC(sync)->init) + STATE_SYNC(sync)->init(); STATE_SYNC(internal) = cache_create("internal", - STATE_SYNC(mcast_sync)->internal_cache_flags, + STATE_SYNC(sync)->internal_cache_flags, CONFIG(family), - STATE_SYNC(mcast_sync)->internal_cache_extra); + STATE_SYNC(sync)->internal_cache_extra); if (!STATE_SYNC(internal)) { dlog(STATE(log), "[FAIL] can't allocate memory for " @@ -133,7 +132,7 @@ static int init_sync(void) STATE_SYNC(external) = cache_create("external", - STATE_SYNC(mcast_sync)->external_cache_flags, + STATE_SYNC(sync)->external_cache_flags, CONFIG(family), NULL); @@ -192,8 +191,8 @@ static void kill_sync() destroy_alarm_thread(); - if (STATE_SYNC(mcast_sync)->kill) - STATE_SYNC(mcast_sync)->kill(); + if (STATE_SYNC(sync)->kill) + STATE_SYNC(sync)->kill(); } static dump_stats_sync(int fd) @@ -253,8 +252,8 @@ static int local_handler_sync(int fd, int type, void *data) cache_bulk(STATE_SYNC(internal)); break; default: - if (STATE_SYNC(mcast_sync)->local) - ret = STATE_SYNC(mcast_sync)->local(fd, type, data); + if (STATE_SYNC(sync)->local) + ret = STATE_SYNC(sync)->local(fd, type, data); break; } @@ -280,17 +279,18 @@ static void mcast_send_sync(struct nlmsghdr *nlh, struct nf_conntrack *ct, int type) { - char buf[4096]; - struct nlnetwork *net = (struct nlnetwork *) buf; + char __net[4096]; + struct nlnetwork *net = (struct nlnetwork *) __net; - memset(buf, 0, sizeof(buf)); + memset(__net, 0, sizeof(__net)); if (!state_helper_verdict(type, ct)) return; - memcpy(buf + sizeof(struct nlnetwork), nlh, nlh->nlmsg_len); - mcast_send_netmsg(STATE_SYNC(mcast_client), net); - STATE_SYNC(mcast_sync)->post_send(type, net, u); + memcpy(__net + sizeof(struct nlnetwork), nlh, nlh->nlmsg_len); + mcast_send_netmsg(STATE_SYNC(mcast_client), net); + if (STATE_SYNC(sync)->send) + STATE_SYNC(sync)->send(type, net, u); } static int overrun_cb(enum nf_conntrack_msg_type type, @@ -313,18 +313,16 @@ static int overrun_cb(enum nf_conntrack_msg_type type, if (!cache_test(STATE_SYNC(internal), ct)) { if ((u = cache_update_force(STATE_SYNC(internal), ct))) { int ret; - char buf[4096]; - struct nlnetwork *net = (struct nlnetwork *) buf; - unsigned int size = sizeof(struct nlnetwork); - struct nlmsghdr *nlh = (struct nlmsghdr *) (buf + size); + char __nlh[4096]; + struct nlmsghdr *nlh = (struct nlmsghdr *) __nlh; debug_ct(u->ct, "overrun resync"); - ret = build_network_msg(NFCT_Q_UPDATE, - STATE(subsys_dump), - u->ct, - buf, - sizeof(buf)); + ret = nfct_build_query(STATE(subsys_dump), + NFCT_Q_UPDATE, + u->ct, + __nlh, + sizeof(__nlh)); if (ret == -1) { dlog(STATE(log), "can't build overrun"); @@ -346,18 +344,16 @@ static int overrun_purge_step(void *data1, void *data2) ret = nfct_query(h, NFCT_Q_GET, u->ct); if (ret == -1 && errno == ENOENT) { - char buf[4096]; - struct nlnetwork *net = (struct nlnetwork *) buf; - unsigned int size = sizeof(struct nlnetwork); - struct nlmsghdr *nlh = (struct nlmsghdr *) (buf + size); + char __nlh[4096]; + struct nlmsghdr *nlh = (struct nlmsghdr *) (__nlh); debug_ct(u->ct, "overrun purge resync"); - - ret = build_network_msg(NFCT_Q_DESTROY, - STATE(subsys_dump), - u->ct, - buf, - sizeof(buf)); + + ret = nfct_build_query(STATE(subsys_dump), + NFCT_Q_DESTROY, + u->ct, + __nlh, + sizeof(__nlh)); if (ret == -1) dlog(STATE(log), "failed to build network message"); @@ -411,18 +407,6 @@ retry: debug_ct(u->ct, "internal new"); } else { if (errno == EEXIST) { - char buf[4096]; - unsigned int size = sizeof(struct nlnetwork); - struct nlmsghdr *nlh = (struct nlmsghdr *) (buf + size); - - int ret = build_network_msg(NFCT_Q_DESTROY, - STATE(subsys_event), - ct, - buf, - sizeof(buf)); - if (ret == -1) - return; - cache_del(STATE_SYNC(internal), ct); mcast_send_sync(nlh, NULL, ct, NFCT_T_DESTROY); goto retry; @@ -440,7 +424,7 @@ static void event_update_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh) nfct_attr_unset(ct, ATTR_TIMEOUT); - if ((u = cache_update(STATE_SYNC(internal), ct)) == NULL) { + if ((u = cache_update_force(STATE_SYNC(internal), ct)) == NULL) { debug_ct(ct, "can't update"); return; } diff --git a/src/sync-nack.c b/src/sync-nack.c index 73f6dc2..e435b09 100644 --- a/src/sync-nack.c +++ b/src/sync-nack.c @@ -136,7 +136,7 @@ static int buffer_compare(void *data1, void *data2) unsigned old_seq = ntohl(net->seq); - if (ntohl(net->seq) >= nack->from && ntohl(net->seq) <= nack->to) { + if (between(ntohl(net->seq), nack->from, nack->to)) { if (mcast_resend_netmsg(STATE_SYNC(mcast_client), net)) dp("resend destroy (old seq=%u) (seq=%u)\n", old_seq, ntohl(net->seq)); @@ -149,7 +149,7 @@ static int buffer_remove(void *data1, void *data2) struct nlnetwork *net = data1; struct nlnetwork_ack *h = data2; - if (ntohl(net->seq) >= h->from && ntohl(net->seq) <= h->to) { + if (between(ntohl(net->seq), h->from, h->to)) { dp("remove from buffer (seq=%u)\n", ntohl(net->seq)); __buffer_del(STATE_SYNC(buffer), data1); } @@ -169,7 +169,7 @@ static void queue_resend(struct cache *c, unsigned int from, unsigned int to) u = cache_get_conntrack(STATE_SYNC(internal), cn); - if (cn->seq >= from && cn->seq <= to) { + if (between(cn->seq, from, to)) { debug_ct(u->ct, "resend nack"); dp("resending nack'ed (oldseq=%u) ", cn->seq); @@ -186,10 +186,9 @@ static void queue_resend(struct cache *c, unsigned int from, unsigned int to) break; } - mcast_send_netmsg(STATE_SYNC(mcast_client), buf); - STATE_SYNC(mcast_sync)->post_send(NFCT_T_UPDATE, - net, - u); + mcast_send_netmsg(STATE_SYNC(mcast_client), buf); + if (STATE_SYNC(sync)->send) + STATE_SYNC(sync)->send(NFCT_T_UPDATE, net, u); dp("(newseq=%u)\n", *seq); } } @@ -208,7 +207,7 @@ static void queue_empty(struct cache *c, unsigned int from, unsigned int to) struct cache_nack *cn = (struct cache_nack *) n; u = cache_get_conntrack(STATE_SYNC(internal), cn); - if (cn->seq >= from && cn->seq <= to) { + if (between(cn->seq, from, to)) { dp("remove %u\n", cn->seq); debug_ct(u->ct, "ack received: empty queue"); dp("queue: deleting from queue (seq=%u)\n", cn->seq); @@ -219,7 +218,7 @@ static void queue_empty(struct cache *c, unsigned int from, unsigned int to) unlock(); } -static int nack_pre_recv(const struct nlnetwork *net) +static int nack_recv(const struct nlnetwork *net) { static unsigned int window = 0; unsigned int exp_seq; @@ -262,9 +261,9 @@ static int nack_pre_recv(const struct nlnetwork *net) return 0; } -static void nack_post_send(int type, - const struct nlnetwork *net, - struct us_conntrack *u) +static void nack_send(int type, + const struct nlnetwork *net, + struct us_conntrack *u) { unsigned int size = sizeof(struct nlnetwork); struct nlmsghdr *nlh = (struct nlmsghdr *) ((void *) net + size); @@ -301,6 +300,6 @@ struct sync_mode nack = { .init = nack_init, .kill = nack_kill, .local = nack_local, - .pre_recv = nack_pre_recv, - .post_send = nack_post_send, + .recv = nack_recv, + .send = nack_send, }; diff --git a/src/sync-notrack.c b/src/sync-notrack.c index cc56436..4a470f9 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -25,33 +25,18 @@ static void refresher(struct alarm_list *a, void *data) { struct us_conntrack *u = data; - char buf[8192]; + char __net[4096]; int size; - if (nfct_get_attr_u32(u->ct, ATTR_STATUS) & IPS_DYING) { - - debug_ct(u->ct, "persistence destroy"); + debug_ct(u->ct, "persistence update"); - size = build_network_msg(NFCT_Q_DESTROY, - STATE(subsys_event), - u->ct, - buf, - sizeof(buf)); - - __cache_del(u->cache, u->ct); - mcast_send_netmsg(STATE_SYNC(mcast_client), buf); - } else { - - debug_ct(u->ct, "persistence update"); - - a->expires = random() % CONFIG(refresh) + 1; - size = build_network_msg(NFCT_Q_UPDATE, - STATE(subsys_event), - u->ct, - buf, - sizeof(buf)); - mcast_send_netmsg(STATE_SYNC(mcast_client), buf); - } + a->expires = random() % CONFIG(refresh) + 1; + size = build_network_msg(NFCT_Q_UPDATE, + STATE(subsys_event), + u->ct, + __net, + sizeof(__net)); + mcast_send_netmsg(STATE_SYNC(mcast_client), __net); } static void cache_notrack_add(struct us_conntrack *u, void *data) @@ -84,7 +69,7 @@ static struct cache_extra cache_notrack_extra = { .destroy = cache_notrack_destroy }; -static int notrack_pre_recv(const struct nlnetwork *net) +static int notrack_recv(const struct nlnetwork *net) { unsigned int exp_seq; @@ -114,16 +99,9 @@ static int notrack_pre_recv(const struct nlnetwork *net) return 0; } -static void notrack_post_send(int type, - const struct nlnetwork *n, - struct us_conntrack *u) -{ -} - struct sync_mode notrack = { .internal_cache_flags = LIFETIME, .external_cache_flags = TIMER | LIFETIME, .internal_cache_extra = &cache_notrack_extra, - .pre_recv = notrack_pre_recv, - .post_send = notrack_post_send, + .recv = notrack_recv, }; -- cgit v1.2.3 From 3f3a6701978df8ca16ebb5988eb7a46771deb964 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Tue, 19 Jun 2007 17:00:44 +0000 Subject: - more cleanups and code refactorization - remove several debug calls - create a child to dispatch dump requests: this will help to simplify the current locking schema. Later. --- ChangeLog | 2 ++ include/network.h | 22 +++++++------ include/sync.h | 6 ++-- src/cache.c | 1 - src/cache_iterators.c | 22 ++----------- src/ignore_pool.c | 1 - src/local.c | 19 +++-------- src/network.c | 89 ++++++++++++++++++++++++++++++++++++--------------- src/run.c | 13 ++++++-- src/stats-mode.c | 8 +++-- src/sync-mode.c | 69 ++++++++++++++++----------------------- src/sync-nack.c | 63 +++++++++++++----------------------- src/sync-notrack.c | 13 ++------ 13 files changed, 156 insertions(+), 172 deletions(-) (limited to 'src/sync-notrack.c') diff --git a/ChangeLog b/ChangeLog index f1ae81f..aa93d4c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -14,6 +14,8 @@ o relax event tracking: *_update callbacks use cache_update_force o use wraparound-aware functions after/before/between o commit phase: if conntrack exists, update it o local requests return EXIT_FAILURE if it can't connect to the daemon +o remove several debug statements +o fork when internal/external dump cache requests are received o lots of cleanups = conntrack = diff --git a/include/network.h b/include/network.h index 243815a..31903a5 100644 --- a/include/network.h +++ b/include/network.h @@ -3,32 +3,34 @@ #include -struct nlnetwork { +struct nethdr { u_int16_t flags; u_int16_t padding; u_int32_t seq; }; +#define NETHDR_SIZ sizeof(struct nethdr) -struct nlnetwork_ack { +struct nethdr_ack { u_int16_t flags; u_int16_t padding; u_int32_t seq; u_int32_t from; u_int32_t to; }; +#define NETHDR_ACK_SIZ sizeof(struct nethdr_ack) enum { - NET_HELLO_BIT = 0, - NET_HELLO = (1 << NET_HELLO_BIT), + NET_F_HELLO_BIT = 0, + NET_F_HELLO = (1 << NET_F_HELLO_BIT), - NET_RESYNC_BIT = 1, - NET_RESYNC = (1 << NET_RESYNC_BIT), + NET_F_RESYNC_BIT = 1, + NET_F_RESYNC = (1 << NET_F_RESYNC_BIT), - NET_NACK_BIT = 2, - NET_NACK = (1 << NET_NACK_BIT), + NET_F_NACK_BIT = 2, + NET_F_NACK = (1 << NET_F_NACK_BIT), - NET_ACK_BIT = 3, - NET_ACK = (1 << NET_ACK_BIT), + NET_F_ACK_BIT = 3, + NET_F_ACK = (1 << NET_F_ACK_BIT), }; /* extracted from net/tcp.h */ diff --git a/include/sync.h b/include/sync.h index 72f6313..a737e81 100644 --- a/include/sync.h +++ b/include/sync.h @@ -1,7 +1,7 @@ #ifndef _SYNC_HOOKS_H_ #define _SYNC_HOOKS_H_ -struct nlnetwork; +struct nethdr; struct us_conntrack; struct sync_mode { @@ -13,9 +13,9 @@ struct sync_mode { int (*init)(void); void (*kill)(void); int (*local)(int fd, int type, void *data); - int (*recv)(const struct nlnetwork *net); /* recv callback */ + int (*recv)(const struct nethdr *net); /* recv callback */ void (*send)(int type, /* send callback */ - const struct nlnetwork *net, + const struct nethdr *net, struct us_conntrack *u); }; diff --git a/src/cache.c b/src/cache.c index 1b130c8..3bf331c 100644 --- a/src/cache.c +++ b/src/cache.c @@ -23,7 +23,6 @@ #include #include "us-conntrack.h" #include "cache.h" -#include "debug.h" static u_int32_t hash(const void *data, struct hashtable *table) { diff --git a/src/cache_iterators.c b/src/cache_iterators.c index 279ddab..7ae25fa 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -23,7 +23,6 @@ #include #include #include "us-conntrack.h" -#include "debug.h" struct __dump_container { int fd; @@ -120,8 +119,7 @@ static int do_commit(void *data1, void *data2) free(ct); if (ret == -1) { - /* XXX: Please cleanup this debug crap, default in logfile */ - debug("--- failed to build: %s --- \n", strerror(errno)); + dlog(STATE(log), "failed to build: %s", strerror(errno)); return 0; } @@ -135,10 +133,8 @@ static int do_commit(void *data1, void *data2) c->commit_fail++; break; } - debug("--- failed to commit: %s --- \n", strerror(errno)); } else { c->commit_ok++; - debug("----- commit -----\n"); } /* keep iterating even if we have found errors */ @@ -207,20 +203,8 @@ static int do_bulk(void *data1, void *data2) { int ret; struct us_conntrack *u = data2; - char buf[4096]; - struct nlnetwork *net = (struct nlnetwork *) buf; - - ret = build_network_msg(NFCT_Q_UPDATE, - STATE(subsys_dump), - u->ct, - buf, - sizeof(buf)); - if (ret == -1) - debug_ct(u->ct, "failed to build"); - - mcast_send_netmsg(STATE_SYNC(mcast_client), net); - if (STATE_SYNC(sync)->send) - STATE_SYNC(sync)->send(NFCT_T_UPDATE, net, u); + + mcast_build_send_update(u); /* keep iterating even if we have found errors */ return 0; diff --git a/src/ignore_pool.c b/src/ignore_pool.c index 5946617..d6f0e93 100644 --- a/src/ignore_pool.c +++ b/src/ignore_pool.c @@ -20,7 +20,6 @@ #include "hash.h" #include "conntrackd.h" #include "ignore.h" -#include "debug.h" #include #define IGNORE_POOL_SIZE 32 diff --git a/src/local.c b/src/local.c index eef70ad..be51b9e 100644 --- a/src/local.c +++ b/src/local.c @@ -1,5 +1,5 @@ /* - * (C) 2006 by Pablo Neira Ayuso + * (C) 2006-2007 by Pablo Neira Ayuso * * 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 @@ -22,7 +22,6 @@ #include #include #include -#include "debug.h" #include "local.h" @@ -32,14 +31,11 @@ int local_server_create(struct local_conf *conf) int len; struct sockaddr_un local; - if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { - debug("local_server_create:socket"); + if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) return -1; - } if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &conf->reuseaddr, sizeof(conf->reuseaddr)) == -1) { - debug("local_server_create:setsockopt"); close(fd); return -1; } @@ -50,14 +46,12 @@ int local_server_create(struct local_conf *conf) unlink(conf->path); if (bind(fd, (struct sockaddr *) &local, len) == -1) { - debug("local_server_create:bind"); close(fd); return -1; } if (listen(fd, conf->backlog) == -1) { close(fd); - debug("local_server_create:listen"); return -1; } @@ -76,10 +70,8 @@ int do_local_server_step(int fd, void *data, struct sockaddr_un local; size_t sin_size = sizeof(struct sockaddr_un); - if ((rfd = accept(fd, (struct sockaddr *)&local, &sin_size)) == -1) { - debug("do_local_server_step:accept"); + if ((rfd = accept(fd, (struct sockaddr *)&local, &sin_size)) == -1) return -1; - } process(rfd, data); close(rfd); @@ -102,7 +94,6 @@ int local_client_create(struct local_conf *conf) if (connect(fd, (struct sockaddr *) &local, len) == -1) { close(fd); - debug("local_client_create: connect: "); return -1; } @@ -146,10 +137,8 @@ int do_local_request(int request, return -1; ret = send(fd, &request, sizeof(int), 0); - if (ret == -1) { - debug("send:"); + if (ret == -1) return -1; - } do_local_client_step(fd, step); diff --git a/src/network.c b/src/network.c index 37f437e..159bdf3 100644 --- a/src/network.c +++ b/src/network.c @@ -23,12 +23,12 @@ static unsigned int seq_set, cur_seq; static int send_netmsg(struct mcast_sock *m, void *data, unsigned int len) { - struct nlnetwork *net = data; + struct nethdr *net = data; if (!seq_set) { seq_set = 1; cur_seq = time(NULL); - net->flags |= NET_HELLO; + net->flags |= NET_F_HELLO; } net->flags = htons(net->flags); @@ -49,9 +49,9 @@ static int send_netmsg(struct mcast_sock *m, void *data, unsigned int len) int mcast_send_netmsg(struct mcast_sock *m, void *data) { - struct nlmsghdr *nlh = data + sizeof(struct nlnetwork); - unsigned int len = nlh->nlmsg_len + sizeof(struct nlnetwork); - struct nlnetwork *net = data; + struct nlmsghdr *nlh = data + NETHDR_SIZ; + unsigned int len = nlh->nlmsg_len + NETHDR_SIZ; + struct nethdr *net = data; if (nlh_host2network(nlh) == -1) return -1; @@ -61,40 +61,77 @@ int mcast_send_netmsg(struct mcast_sock *m, void *data) int mcast_resend_netmsg(struct mcast_sock *m, void *data) { - struct nlnetwork *net = data; - struct nlmsghdr *nlh = data + sizeof(struct nlnetwork); + struct nethdr *net = data; + struct nlmsghdr *nlh = data + NETHDR_SIZ; unsigned int len; net->flags = ntohs(net->flags); - if (net->flags & NET_NACK || net->flags & NET_ACK) - len = sizeof(struct nlnetwork_ack); + if (net->flags & NET_F_NACK || net->flags & NET_F_ACK) + len = NETHDR_ACK_SIZ; else - len = sizeof(struct nlnetwork) + ntohl(nlh->nlmsg_len); + len = ntohl(nlh->nlmsg_len) + NETHDR_SIZ; return send_netmsg(m, data, len); } int mcast_send_error(struct mcast_sock *m, void *data) { - struct nlnetwork *net = data; - unsigned int len = sizeof(struct nlnetwork); + struct nethdr *net = data; + unsigned int len = NETHDR_SIZ; - if (net->flags & NET_NACK || net->flags & NET_ACK) { - struct nlnetwork_ack *nack = (struct nlnetwork_ack *) net; + if (net->flags & NET_F_NACK || net->flags & NET_F_ACK) { + struct nethdr_ack *nack = (struct nethdr_ack *) net; nack->from = htonl(nack->from); nack->to = htonl(nack->to); - len = sizeof(struct nlnetwork_ack); + len = NETHDR_ACK_SIZ; } return send_netmsg(m, data, len); } +#include "us-conntrack.h" +#include "sync.h" + +static int __build_send(struct us_conntrack *u, int type, int query) +{ + char __net[4096]; + struct nethdr *net = (struct nethdr *) __net; + + if (!state_helper_verdict(type, u->ct)) + return 0; + + int ret = build_network_msg(query, + STATE(subsys_event), + u->ct, + __net, + sizeof(__net)); + + if (ret == -1) + return -1; + + mcast_send_netmsg(STATE_SYNC(mcast_client), __net); + if (STATE_SYNC(sync)->send) + STATE_SYNC(sync)->send(type, net, u); + + return 0; +} + +int mcast_build_send_update(struct us_conntrack *u) +{ + return __build_send(u, NFCT_T_UPDATE, NFCT_Q_UPDATE); +} + +int mcast_build_send_destroy(struct us_conntrack *u) +{ + return __build_send(u, NFCT_T_DESTROY, NFCT_Q_DESTROY); +} + int mcast_recv_netmsg(struct mcast_sock *m, void *data, int len) { int ret; - struct nlnetwork *net = data; - struct nlmsghdr *nlh = data + sizeof(struct nlnetwork); + struct nethdr *net = data; + struct nlmsghdr *nlh = data + NETHDR_SIZ; struct nfgenmsg *nfhdr; ret = mcast_recv(m, net, len); @@ -102,17 +139,17 @@ int mcast_recv_netmsg(struct mcast_sock *m, void *data, int len) return ret; /* message too small: no room for the header */ - if (ret < sizeof(struct nlnetwork)) + if (ret < NETHDR_SIZ) return -1; - if (ntohs(net->flags) & NET_HELLO) + if (ntohs(net->flags) & NET_F_HELLO) STATE_SYNC(last_seq_recv) = ntohl(net->seq) - 1; - if (ntohs(net->flags) & NET_NACK || ntohs(net->flags) & NET_ACK) { - struct nlnetwork_ack *nack = (struct nlnetwork_ack *) net; + if (ntohs(net->flags) & NET_F_NACK || ntohs(net->flags) & NET_F_ACK) { + struct nethdr_ack *nack = (struct nethdr_ack *) net; /* message too small: no room for the header */ - if (ret < sizeof(struct nlnetwork_ack)) + if (ret < NETHDR_ACK_SIZ) return -1; /* host byte order conversion */ @@ -126,7 +163,7 @@ int mcast_recv_netmsg(struct mcast_sock *m, void *data, int len) return ret; } - if (ntohs(net->flags) & NET_RESYNC) { + if (ntohs(net->flags) & NET_F_RESYNC) { /* host byte order conversion */ net->flags = ntohs(net->flags); net->seq = ntohl(net->seq); @@ -139,7 +176,7 @@ int mcast_recv_netmsg(struct mcast_sock *m, void *data, int len) return -1; /* information received and message length does not match */ - if (ret != ntohl(nlh->nlmsg_len) + sizeof(struct nlnetwork)) + if (ret != ntohl(nlh->nlmsg_len) + NETHDR_SIZ) return -1; /* this message does not come from ctnetlink */ @@ -209,8 +246,8 @@ int build_network_msg(const int msg_type, unsigned int size) { memset(buffer, 0, size); - buffer += sizeof(struct nlnetwork); - size -= sizeof(struct nlnetwork); + buffer += NETHDR_SIZ; + size -= NETHDR_SIZ; return nfct_build_query(ssh, msg_type, ct, buffer, size); } diff --git a/src/run.c b/src/run.c index b7dc543..0173c9f 100644 --- a/src/run.c +++ b/src/run.c @@ -47,6 +47,11 @@ void killer(int foo) exit(0); } +static void child(int foo) +{ + while(wait(NULL) > 0); +} + void local_handler(int fd, void *data) { int ret; @@ -54,11 +59,11 @@ void local_handler(int fd, void *data) ret = read(fd, &type, sizeof(type)); if (ret == -1) { - dlog(STATE(log), "can't read from unix socket\n"); + dlog(STATE(log), "can't read from unix socket"); return; } if (ret == 0) { - debug("nothing to process\n"); + dlog(STATE(log), "local request: nothing to process?"); return; } @@ -122,6 +127,7 @@ int init(int mode) sigemptyset(&STATE(block)); sigaddset(&STATE(block), SIGTERM); sigaddset(&STATE(block), SIGINT); + sigaddset(&STATE(block), SIGCHLD); if (signal(SIGINT, killer) == SIG_ERR) return -1; @@ -133,6 +139,9 @@ int init(int mode) if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) return -1; + if (signal(SIGCHLD, child) == SIG_ERR) + return -1; + dlog(STATE(log), "[OK] initialization completed"); return 0; diff --git a/src/stats-mode.c b/src/stats-mode.c index f65fbdb..92794cd 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -142,9 +142,11 @@ static void event_new_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh) if (cache_add(STATE_STATS(cache), ct)) { debug_ct(ct, "cache new"); } else { - dlog(STATE(log), "can't add to cache cache: " - "%s\n", strerror(errno)); - debug_ct(ct, "can't add"); + if (errno != EEXIST) { + dlog(STATE(log), "can't add to cache cache: " + "%s\n", strerror(errno)); + debug_ct(ct, "can't add"); + } } } diff --git a/src/sync-mode.c b/src/sync-mode.c index cb95392..8433532 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -32,10 +32,10 @@ static void mcast_handler() { int ret; - unsigned int type, size = sizeof(struct nlnetwork); + unsigned int type; char __net[4096]; - struct nlnetwork *net = (struct nlnetwork *) __net; - struct nlmsghdr *nlh = (struct nlmsghdr *) (__net + size); + struct nethdr *net = (struct nethdr *) __net; + struct nlmsghdr *nlh = (struct nlmsghdr *) (__net + NETHDR_SIZ); char __ct[nfct_maxsize()]; struct nf_conntrack *ct = (struct nf_conntrack *) __ct; struct us_conntrack *u = NULL; @@ -93,7 +93,7 @@ retry: debug_ct(ct, "can't destroy"); break; default: - debug("unknown type %d\n", type); + dlog(STATE(log), "mcast received unknown msg type %d\n", type); break; } } @@ -216,16 +216,32 @@ static int local_handler_sync(int fd, int type, void *data) switch(type) { case DUMP_INTERNAL: - cache_dump(STATE_SYNC(internal), fd, NFCT_O_PLAIN); + ret = fork(); + if (ret == 0) { + cache_dump(STATE_SYNC(internal), fd, NFCT_O_PLAIN); + exit(EXIT_SUCCESS); + } break; case DUMP_EXTERNAL: - cache_dump(STATE_SYNC(external), fd, NFCT_O_PLAIN); + ret = fork(); + if (ret == 0) { + cache_dump(STATE_SYNC(external), fd, NFCT_O_PLAIN); + exit(EXIT_SUCCESS); + } break; case DUMP_INT_XML: - cache_dump(STATE_SYNC(internal), fd, NFCT_O_XML); + ret = fork(); + if (ret == 0) { + cache_dump(STATE_SYNC(internal), fd, NFCT_O_XML); + exit(EXIT_SUCCESS); + } break; case DUMP_EXT_XML: - cache_dump(STATE_SYNC(external), fd, NFCT_O_XML); + ret = fork(); + if (ret == 0) { + cache_dump(STATE_SYNC(external), fd, NFCT_O_XML); + exit(EXIT_SUCCESS); + } break; case COMMIT: dlog(STATE(log), "[REQ] commit external cache to master table"); @@ -280,14 +296,14 @@ static void mcast_send_sync(struct nlmsghdr *nlh, int type) { char __net[4096]; - struct nlnetwork *net = (struct nlnetwork *) __net; + struct nethdr *net = (struct nethdr *) __net; memset(__net, 0, sizeof(__net)); if (!state_helper_verdict(type, ct)) return; - memcpy(__net + sizeof(struct nlnetwork), nlh, nlh->nlmsg_len); + memcpy(__net + NETHDR_SIZ, nlh, nlh->nlmsg_len); mcast_send_netmsg(STATE_SYNC(mcast_client), net); if (STATE_SYNC(sync)->send) STATE_SYNC(sync)->send(type, net, u); @@ -312,24 +328,8 @@ static int overrun_cb(enum nf_conntrack_msg_type type, if (!cache_test(STATE_SYNC(internal), ct)) { if ((u = cache_update_force(STATE_SYNC(internal), ct))) { - int ret; - char __nlh[4096]; - struct nlmsghdr *nlh = (struct nlmsghdr *) __nlh; - debug_ct(u->ct, "overrun resync"); - - ret = nfct_build_query(STATE(subsys_dump), - NFCT_Q_UPDATE, - u->ct, - __nlh, - sizeof(__nlh)); - - if (ret == -1) { - dlog(STATE(log), "can't build overrun"); - return NFCT_CB_CONTINUE; - } - - mcast_send_sync(nlh, u, ct, NFCT_T_UPDATE); + mcast_build_send_update(u); } } @@ -344,21 +344,8 @@ static int overrun_purge_step(void *data1, void *data2) ret = nfct_query(h, NFCT_Q_GET, u->ct); if (ret == -1 && errno == ENOENT) { - char __nlh[4096]; - struct nlmsghdr *nlh = (struct nlmsghdr *) (__nlh); - debug_ct(u->ct, "overrun purge resync"); - - ret = nfct_build_query(STATE(subsys_dump), - NFCT_Q_DESTROY, - u->ct, - __nlh, - sizeof(__nlh)); - - if (ret == -1) - dlog(STATE(log), "failed to build network message"); - - mcast_send_sync(nlh, NULL, u->ct, NFCT_T_DESTROY); + mcast_build_send_destroy(u); __cache_del(STATE_SYNC(internal), u->ct); } diff --git a/src/sync-nack.c b/src/sync-nack.c index 1f62294..20ad1f4 100644 --- a/src/sync-nack.c +++ b/src/sync-nack.c @@ -79,14 +79,14 @@ static void nack_kill() static void mcast_send_control(u_int32_t flags, u_int32_t from, u_int32_t to) { - struct nlnetwork_ack ack = { + struct nethdr_ack ack = { .flags = flags, .from = from, .to = to, }; mcast_send_error(STATE_SYNC(mcast_client), &ack); - buffer_add(STATE_SYNC(buffer), &ack, sizeof(struct nlnetwork_ack)); + buffer_add(STATE_SYNC(buffer), &ack, NETHDR_ACK_SIZ); } static int nack_local(int fd, int type, void *data) @@ -95,7 +95,7 @@ static int nack_local(int fd, int type, void *data) switch(type) { case REQUEST_DUMP: - mcast_send_control(NET_RESYNC, 0, 0); + mcast_send_control(NET_F_RESYNC, 0, 0); dlog(STATE(log), "[REQ] request resync"); break; default: @@ -108,9 +108,9 @@ static int nack_local(int fd, int type, void *data) static int buffer_compare(void *data1, void *data2) { - struct nlnetwork *net = data1; - struct nlnetwork_ack *nack = data2; - struct nlmsghdr *nlh = data1 + sizeof(struct nlnetwork); + struct nethdr *net = data1; + struct nethdr_ack *nack = data2; + struct nlmsghdr *nlh = data1 + NETHDR_SIZ; unsigned old_seq = ntohl(net->seq); @@ -124,8 +124,8 @@ static int buffer_compare(void *data1, void *data2) static int buffer_remove(void *data1, void *data2) { - struct nlnetwork *net = data1; - struct nlnetwork_ack *h = data2; + struct nethdr *net = data1; + struct nethdr_ack *h = data2; if (between(ntohl(net->seq), h->from, h->to)) { dp("remove from buffer (seq=%u)\n", ntohl(net->seq)); @@ -138,9 +138,7 @@ static void queue_resend(struct cache *c, unsigned int from, unsigned int to) { struct list_head *n; struct us_conntrack *u; - unsigned int *seq; - lock(); list_for_each(n, &queue) { struct cache_nack *cn = (struct cache_nack *) n; struct us_conntrack *u; @@ -151,35 +149,19 @@ static void queue_resend(struct cache *c, unsigned int from, unsigned int to) debug_ct(u->ct, "resend nack"); dp("resending nack'ed (oldseq=%u) ", cn->seq); - char buf[4096]; - struct nlnetwork *net = (struct nlnetwork *) buf; - - int ret = build_network_msg(NFCT_Q_UPDATE, - STATE(subsys_event), - u->ct, - buf, - sizeof(buf)); - if (ret == -1) { - unlock(); - break; - } - - mcast_send_netmsg(STATE_SYNC(mcast_client), buf); - if (STATE_SYNC(sync)->send) - STATE_SYNC(sync)->send(NFCT_T_UPDATE, net, u); - dp("(newseq=%u)\n", *seq); + if (mcast_build_send_update(u) == -1) + continue; + + dp("(newseq=%u)\n", cn->seq); } } - unlock(); } static void queue_empty(struct cache *c, unsigned int from, unsigned int to) { struct list_head *n, *tmp; struct us_conntrack *u; - unsigned int *seq; - lock(); dp("ACK from %u to %u\n", from, to); list_for_each_safe(n, tmp, &queue) { struct cache_nack *cn = (struct cache_nack *) n; @@ -193,10 +175,9 @@ static void queue_empty(struct cache *c, unsigned int from, unsigned int to) INIT_LIST_HEAD(&cn->head); } } - unlock(); } -static int nack_recv(const struct nlnetwork *net) +static int nack_recv(const struct nethdr *net) { static unsigned int window = 0; unsigned int exp_seq; @@ -206,31 +187,31 @@ static int nack_recv(const struct nlnetwork *net) if (!mcast_track_seq(net->seq, &exp_seq)) { dp("OOS: sending nack (seq=%u)\n", exp_seq); - mcast_send_control(NET_NACK, exp_seq, net->seq - 1); + mcast_send_control(NET_F_NACK, exp_seq, net->seq - 1); window = CONFIG(window_size); } else { /* received a window, send an acknowledgement */ if (--window == 0) { dp("sending ack (seq=%u)\n", net->seq); - mcast_send_control(NET_ACK, + mcast_send_control(NET_F_ACK, net->seq - CONFIG(window_size), net->seq); } } - if (net->flags & NET_NACK) { - struct nlnetwork_ack *nack = (struct nlnetwork_ack *) net; + if (net->flags & NET_F_NACK) { + struct nethdr_ack *nack = (struct nethdr_ack *) net; dp("NACK: from seq=%u to seq=%u\n", nack->from, nack->to); queue_resend(STATE_SYNC(internal), nack->from, nack->to); buffer_iterate(STATE_SYNC(buffer), nack, buffer_compare); return 1; - } else if (net->flags & NET_RESYNC) { + } else if (net->flags & NET_F_RESYNC) { dp("RESYNC ALL\n"); cache_bulk(STATE_SYNC(internal)); return 1; - } else if (net->flags & NET_ACK) { - struct nlnetwork_ack *h = (struct nlnetwork_ack *) net; + } else if (net->flags & NET_F_ACK) { + struct nethdr_ack *h = (struct nethdr_ack *) net; dp("ACK: from seq=%u to seq=%u\n", h->from, h->to); queue_empty(STATE_SYNC(internal), h->from, h->to); @@ -242,10 +223,10 @@ static int nack_recv(const struct nlnetwork *net) } static void nack_send(int type, - const struct nlnetwork *net, + const struct nethdr *net, struct us_conntrack *u) { - unsigned int size = sizeof(struct nlnetwork); + int size = NETHDR_SIZ; struct nlmsghdr *nlh = (struct nlmsghdr *) ((void *) net + size); struct cache_nack *cn; diff --git a/src/sync-notrack.c b/src/sync-notrack.c index 4a470f9..1d6eba8 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -25,18 +25,11 @@ static void refresher(struct alarm_list *a, void *data) { struct us_conntrack *u = data; - char __net[4096]; - int size; debug_ct(u->ct, "persistence update"); a->expires = random() % CONFIG(refresh) + 1; - size = build_network_msg(NFCT_Q_UPDATE, - STATE(subsys_event), - u->ct, - __net, - sizeof(__net)); - mcast_send_netmsg(STATE_SYNC(mcast_client), __net); + mcast_build_send_update(u); } static void cache_notrack_add(struct us_conntrack *u, void *data) @@ -69,7 +62,7 @@ static struct cache_extra cache_notrack_extra = { .destroy = cache_notrack_destroy }; -static int notrack_recv(const struct nlnetwork *net) +static int notrack_recv(const struct nethdr *net) { unsigned int exp_seq; @@ -78,7 +71,7 @@ static int notrack_recv(const struct nlnetwork *net) * generated in notrack mode, we don't want to crash the daemon * if someone nuts mixes nack and notrack. */ - if (net->flags & (NET_RESYNC | NET_NACK)) + if (net->flags) return 1; /* -- cgit v1.2.3 From 96084e1a1f2e0a49c961bbddb9fffd2e03bfae3f Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Mon, 9 Jul 2007 19:11:53 +0000 Subject: - conntrack-tools requires libnetfilter_conntrack >= 0.0.81 - add len field to nethdr - implement buffered send/recv to batch messages - stop using netlink format for network messages: use similar TLV-based format - reduce synchronization messages size up to 60% - introduce periodic alive messages for sync-nack protocol - timeslice alarm implementation: remove alarm pthread, remove locking - simplify debugging functions: use nfct_snprintf instead - remove major use of libnfnetlink functions: use libnetfilter_conntrack API - deprecate conntrackd -F, use conntrack -F instead - major rework of the network infrastructure: much simple, less messy --- ChangeLog | 16 ++++ configure.in | 4 +- include/Makefile.am | 2 +- include/buffer.h | 5 +- include/conntrackd.h | 21 ++-- include/debug.h | 56 ++--------- include/network.h | 106 +++++++++++++++++++- include/sync.h | 7 +- include/timer.h | 17 ++++ src/Makefile.am | 7 +- src/alarm.c | 37 ++----- src/buffer.c | 26 ++--- src/build.c | 113 ++++++++++++++++++++++ src/cache.c | 40 +------- src/cache_iterators.c | 54 +---------- src/cache_timer.c | 2 +- src/lock.c | 32 ------- src/main.c | 1 + src/mcast.c | 1 - src/netlink.c | 137 ++++++-------------------- src/network.c | 238 +++++++++++++++++---------------------------- src/parse.c | 76 +++++++++++++++ src/proxy.c | 124 ------------------------ src/run.c | 72 ++++++++++---- src/state_helper.c | 2 +- src/stats-mode.c | 10 +- src/sync-mode.c | 152 +++++++++++++++++------------ src/sync-nack.c | 260 ++++++++++++++++++++++++++++++++++---------------- src/sync-notrack.c | 6 +- src/timer.c | 75 +++++++++++++++ 30 files changed, 909 insertions(+), 790 deletions(-) create mode 100644 include/timer.h create mode 100644 src/build.c create mode 100644 src/parse.c delete mode 100644 src/proxy.c create mode 100644 src/timer.c (limited to 'src/sync-notrack.c') diff --git a/ChangeLog b/ChangeLog index 0166c97..b65966b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +version 0.9.5 (yet unreleased) +------------------------------ + += conntrackd = +o conntrack-tools requires libnetfilter_conntrack >= 0.0.81 +o add len field to nethdr +o implement buffered send/recv to batch messages +o stop using netlink format for network messages: use similar TLV-based format +o reduce synchronization messages size up to 60% +o introduce periodic alive messages for sync-nack protocol +o timeslice alarm implementation: remove alarm pthread, remove locking +o simplify debugging functions: use nfct_snprintf instead +o remove major use of libnfnetlink functions: use libnetfilter_conntrack API +o deprecate conntrackd -F, use conntrack -F instead +o major rework of the network infrastructure: much simple, less messy + version 0.9.4 (2007/07/02) ------------------------------ diff --git a/configure.in b/configure.in index 41a001c..7e1cd20 100644 --- a/configure.in +++ b/configure.in @@ -1,4 +1,4 @@ -AC_INIT(conntrack-tools, 0.9.4, pablo@netfilter.org) +AC_INIT(conntrack-tools, 0.9.5, pablo@netfilter.org) AC_CANONICAL_SYSTEM @@ -18,7 +18,7 @@ esac dnl Dependencies LIBNFNETLINK_REQUIRED=0.0.25 -LIBNETFILTER_CONNTRACK_REQUIRED=0.0.80 +LIBNETFILTER_CONNTRACK_REQUIRED=0.0.81 PKG_CHECK_MODULES(LIBNFNETLINK, libnfnetlink >= $LIBNFNETLINK_REQUIRED,, AC_MSG_ERROR(Cannot find libnfnetlink >= $LIBNFNETLINK_REQUIRED)) diff --git a/include/Makefile.am b/include/Makefile.am index a7716d9..7b6bc14 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -2,5 +2,5 @@ noinst_HEADERS = alarm.h jhash.h slist.h cache.h linux_list.h \ sync.h conntrackd.h local.h us-conntrack.h \ debug.h log.h hash.h mcast.h buffer.h conntrack.h \ - state_helper.h network.h ignore.h + state_helper.h network.h ignore.h timer.h diff --git a/include/buffer.h b/include/buffer.h index 8d72dfb..cb42f51 100644 --- a/include/buffer.h +++ b/include/buffer.h @@ -4,13 +4,12 @@ #include #include #include -#include #include "linux_list.h" struct buffer { - pthread_mutex_t lock; size_t max_size; size_t cur_size; + unsigned int num_elems; struct list_head head; }; @@ -22,9 +21,9 @@ struct buffer_node { struct buffer *buffer_create(size_t max_size); void buffer_destroy(struct buffer *b); +unsigned int buffer_len(struct buffer *b); int buffer_add(struct buffer *b, const void *data, size_t size); void buffer_del(struct buffer *b, void *data); -void __buffer_del(struct buffer *b, void *data); void buffer_iterate(struct buffer *b, void *data, int (*iterate)(void *data1, void *data2)); diff --git a/include/conntrackd.h b/include/conntrackd.h index a620400..e89fc79 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -10,6 +10,7 @@ #include "debug.h" #include #include "state_helper.h" +#include "linux_list.h" #include /* UNIX facilities */ @@ -92,11 +93,8 @@ struct ct_general_state { struct ct_mode *mode; struct ignore_pool *ignore_pool; - struct nfnl_handle *event; /* event handler */ - struct nfnl_handle *dump; /* dump handler */ - - struct nfnl_subsys_handle *subsys_event; /* events */ - struct nfnl_subsys_handle *subsys_dump; /* dump */ + struct nfct_handle *event; /* event handler */ + struct nfct_handle *dump; /* dump handler */ /* statistics */ u_int64_t malformed; @@ -114,7 +112,6 @@ struct ct_sync_state { struct mcast_sock *mcast_client; /* multicast socket: outgoing */ struct sync_mode *sync; /* sync mode */ - struct buffer *buffer; u_int32_t last_seq_sent; /* last sequence number sent */ u_int32_t last_seq_recv; /* last sequence number recv */ @@ -141,17 +138,19 @@ extern struct ct_general_state st; #define IPPROTO_VRRP 112 #endif +#define STEPS_PER_SECONDS 5 + struct ct_mode { int (*init)(void); int (*add_fds_to_set)(fd_set *readfds); - void (*step)(fd_set *readfds); + void (*run)(fd_set *readfds, int step); int (*local)(int fd, int type, void *data); void (*kill)(void); - void (*dump)(struct nf_conntrack *ct, struct nlmsghdr *nlh); + void (*dump)(struct nf_conntrack *ct); void (*overrun)(void); - void (*event_new)(struct nf_conntrack *ct, struct nlmsghdr *nlh); - void (*event_upd)(struct nf_conntrack *ct, struct nlmsghdr *nlh); - int (*event_dst)(struct nf_conntrack *ct, struct nlmsghdr *nlh); + void (*event_new)(struct nf_conntrack *ct); + void (*event_upd)(struct nf_conntrack *ct); + int (*event_dst)(struct nf_conntrack *ct); }; /* conntrackd modes */ diff --git a/include/debug.h b/include/debug.h index 4d1f44f..1ffd9ac 100644 --- a/include/debug.h +++ b/include/debug.h @@ -1,57 +1,21 @@ #ifndef _DEBUG_H #define _DEBUG_H -#if 0 -#define debug printf -#else -#define debug -#endif - -#include -#include #include #undef DEBUG_CT -static inline void debug_ct(struct nf_conntrack *ct, char *msg) -{ #ifdef DEBUG_CT - struct in_addr addr, addr2, addr3, addr4; - - debug("----%s (%p) ----\n", msg, ct); - memcpy(&addr, - nfct_get_attr(ct, ATTR_ORIG_IPV4_SRC), - sizeof(u_int32_t)); - memcpy(&addr2, - nfct_get_attr(ct, ATTR_ORIG_IPV4_DST), - sizeof(u_int32_t)); - memcpy(&addr3, - nfct_get_attr(ct, ATTR_REPL_IPV4_SRC), - sizeof(u_int32_t)); - memcpy(&addr4, - nfct_get_attr(ct, ATTR_REPL_IPV4_DST), - sizeof(u_int32_t)); - - debug("status: %x\n", nfct_get_attr_u32(ct, ATTR_STATUS)); - debug("l3:%d l4:%d ", - nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO), - nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO)); - debug("%s:%hu ->", inet_ntoa(addr), - ntohs(nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC))); - debug("%s:%hu\n", - inet_ntoa(addr2), - ntohs(nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST))); - debug("l3:%d l4:%d ", - nfct_get_attr_u8(ct, ATTR_REPL_L3PROTO), - nfct_get_attr_u8(ct, ATTR_REPL_L4PROTO)); - debug("%s:%hu ->", - inet_ntoa(addr3), - ntohs(nfct_get_attr_u16(ct, ATTR_REPL_PORT_SRC))); - debug("%s:%hu\n", - inet_ntoa(addr4), - ntohs(nfct_get_attr_u16(ct, ATTR_REPL_PORT_DST))); - debug("-------------------------\n"); +#define debug_ct(ct, msg) \ +({ \ + char buf[1024]; \ + nfct_snprintf(buf, 1024, ct, NFCT_T_ALL, 0, 0); \ + printf("[%s]: %s\n", msg, buf); \ +}) +#define debug printf +#else +#define debug_ct(ct, msg) +#define debug #endif -} #endif diff --git a/include/network.h b/include/network.h index 31903a5..bc9431d 100644 --- a/include/network.h +++ b/include/network.h @@ -5,14 +5,17 @@ struct nethdr { u_int16_t flags; - u_int16_t padding; + u_int16_t len; u_int32_t seq; }; #define NETHDR_SIZ sizeof(struct nethdr) +#define NETHDR_DATA(x) \ + (struct netpld *)(((char *)x) + sizeof(struct nethdr)) + struct nethdr_ack { u_int16_t flags; - u_int16_t padding; + u_int16_t len; u_int32_t seq; u_int32_t from; u_int32_t to; @@ -31,8 +34,59 @@ enum { NET_F_ACK_BIT = 3, NET_F_ACK = (1 << NET_F_ACK_BIT), + + NET_F_ALIVE_BIT = 4, + NET_F_ALIVE = (1 << NET_F_ALIVE_BIT), }; +#define BUILD_NETMSG(ct, query) \ +({ \ + char __net[4096]; \ + memset(__net, 0, sizeof(__net)); \ + build_netmsg(ct, query, (struct nethdr *) __net); \ + (struct nethdr *) __net; \ +}) + +struct us_conntrack; +struct mcast_sock; + +void build_netmsg(struct nf_conntrack *ct, int query, struct nethdr *net); +int prepare_send_netmsg(struct mcast_sock *m, void *data); +int mcast_send_netmsg(struct mcast_sock *m, void *data); +int mcast_recv_netmsg(struct mcast_sock *m, void *data, int len); + +#define IS_DATA(x) ((x->flags & ~NET_F_HELLO) == 0) +#define IS_ACK(x) (x->flags & NET_F_ACK) +#define IS_NACK(x) (x->flags & NET_F_NACK) +#define IS_RESYNC(x) (x->flags & NET_F_RESYNC) +#define IS_ALIVE(x) (x->flags & NET_F_ALIVE) +#define IS_CTL(x) IS_ACK(x) || IS_NACK(x) || IS_RESYNC(x) || IS_ALIVE(x) +#define IS_HELLO(x) (x->flags & NET_F_HELLO) + +#define HDR_NETWORK2HOST(x) \ +({ \ + x->flags = ntohs(x->flags); \ + x->len = ntohs(x->len); \ + x->seq = ntohl(x->seq); \ + if (IS_CTL(x)) { \ + struct nethdr_ack *__ack = (struct nethdr_ack *) x; \ + __ack->from = ntohl(__ack->from); \ + __ack->to = ntohl(__ack->to); \ + } \ +}) + +#define HDR_HOST2NETWORK(x) \ +({ \ + if (IS_CTL(x)) { \ + struct nethdr_ack *__ack = (struct nethdr_ack *) x; \ + __ack->from = htonl(__ack->from); \ + __ack->to = htonl(__ack->to); \ + } \ + x->flags = htons(x->flags); \ + x->len = htons(x->len); \ + x->seq = htonl(x->seq); \ +}) + /* extracted from net/tcp.h */ /* @@ -52,4 +106,52 @@ static inline int between(__u32 seq1, __u32 seq2, __u32 seq3) return seq3 - seq2 >= seq1 - seq2; } +struct netpld { + u_int16_t len; + u_int16_t query; +}; +#define NETPLD_SIZ sizeof(struct netpld) + +#define PLD_NETWORK2HOST(x) \ +({ \ + x->len = ntohs(x->len); \ + x->query = ntohs(x->query); \ +}) + +#define PLD_HOST2NETWORK(x) \ +({ \ + x->len = htons(x->len); \ + x->query = htons(x->query); \ +}) + +struct netattr { + u_int16_t nta_len; + u_int16_t nta_attr; +}; + +#define ATTR_NETWORK2HOST(x) \ +({ \ + x->nta_len = ntohs(x->nta_len); \ + x->nta_attr = ntohs(x->nta_attr); \ +}) + +#define PLD_DATA(x) \ + (struct netattr *)(((char *)x) + sizeof(struct netpld)) + +#define PLD_TAIL(x) \ + (struct netattr *)(((char *)x) + sizeof(struct netpld) + x->len) + +#define NTA_DATA(x) \ + (void *)(((char *)x) + sizeof(struct netattr)) + +#define NTA_NEXT(x, len) \ +({ \ + len -= NTA_ALIGN(NTA_LENGTH(x->nta_len)); \ + (struct netattr *)(((char *)x) + NTA_ALIGN(NTA_LENGTH(x->nta_len))); \ +}) + +#define NTA_ALIGNTO 4 +#define NTA_ALIGN(len) (((len) + NTA_ALIGNTO - 1) & ~(NTA_ALIGNTO - 1)) +#define NTA_LENGTH(len) (NTA_ALIGN(sizeof(struct netattr)) + (len)) + #endif diff --git a/include/sync.h b/include/sync.h index a737e81..6345513 100644 --- a/include/sync.h +++ b/include/sync.h @@ -13,10 +13,9 @@ struct sync_mode { int (*init)(void); void (*kill)(void); int (*local)(int fd, int type, void *data); - int (*recv)(const struct nethdr *net); /* recv callback */ - void (*send)(int type, /* send callback */ - const struct nethdr *net, - struct us_conntrack *u); + int (*recv)(const struct nethdr *net); + void (*send)(struct nethdr *net, struct us_conntrack *u); + void (*run)(int step); }; extern struct sync_mode notrack; diff --git a/include/timer.h b/include/timer.h new file mode 100644 index 0000000..37b0fc9 --- /dev/null +++ b/include/timer.h @@ -0,0 +1,17 @@ +#ifndef _TIMER_H_ +#define _TIMER_H_ + +#include + +struct timer { + long credits; + struct timeval start; + struct timeval stop; + struct timeval diff; +}; + +#define GET_CREDITS(x) x.credits +#define GET_STARTTIME(x) x.start +#define GET_STOPTIME(x) x.stop + +#endif diff --git a/src/Makefile.am b/src/Makefile.am index 8647d04..d71e23c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -10,7 +10,7 @@ conntrack_SOURCES = conntrack.c conntrack_LDADD = ../extensions/libct_proto_tcp.la ../extensions/libct_proto_udp.la ../extensions/libct_proto_icmp.la conntrackd_SOURCES = alarm.c main.c run.c hash.c buffer.c \ - local.c log.c mcast.c netlink.c proxy.c lock.c \ + local.c log.c mcast.c netlink.c \ ignore_pool.c \ cache.c cache_iterators.c \ cache_lifetime.c cache_timer.c \ @@ -18,9 +18,10 @@ conntrackd_SOURCES = alarm.c main.c run.c hash.c buffer.c \ traffic_stats.c stats-mode.c \ network.c \ state_helper.c state_helper_tcp.c \ + timer.c \ + build.c parse.c \ read_config_yy.y read_config_lex.l -conntrackd_LDFLAGS = $(all_libraries) -lnfnetlink -lnetfilter_conntrack \ - -lpthread +conntrackd_LDFLAGS = $(all_libraries) -lnfnetlink -lnetfilter_conntrack EXTRA_DIST = read_config_yy.h diff --git a/src/alarm.c b/src/alarm.c index 1a465c2..b4db167 100644 --- a/src/alarm.c +++ b/src/alarm.c @@ -22,17 +22,13 @@ #include "conntrackd.h" #include "alarm.h" #include "jhash.h" -#include #include #include /* alarm cascade */ -#define ALARM_CASCADE_SIZE 10 +#define ALARM_CASCADE_SIZE STEPS_PER_SECONDS static struct list_head *alarm_cascade; -/* thread stuff */ -static pthread_t alarm_thread; - struct alarm_list *create_alarm() { return (struct alarm_list *) malloc(sizeof(struct alarm_list)); @@ -86,24 +82,11 @@ int mod_alarm(struct alarm_list *alarm, unsigned long expires) return 0; } -void __run_alarms() +void do_alarm_run(int step) { struct list_head *i, *tmp; struct alarm_list *t; - struct timespec req = {0, 1000000000 / ALARM_CASCADE_SIZE}; - struct timespec rem; - static int step = 0; - -retry: - if (nanosleep(&req, &rem) == -1) { - /* interrupted syscall: retry with remaining time */ - if (errno == EINTR) { - memcpy(&req, &rem, sizeof(struct timespec)); - goto retry; - } - } - lock(); list_for_each_safe(i, tmp, &alarm_cascade[step]) { t = (struct alarm_list *) i; @@ -111,17 +94,9 @@ retry: if (t->expires == 0) t->function(t, t->data); } - step = (step + 1) < ALARM_CASCADE_SIZE ? step + 1 : 0; - unlock(); -} - -void *run_alarms(void *foo) -{ - while(1) - __run_alarms(); } -int create_alarm_thread() +int init_alarm_scheduler() { int i; @@ -132,10 +107,10 @@ int create_alarm_thread() for (i=0; imax_size = max_size; INIT_LIST_HEAD(&b->head); - pthread_mutex_init(&b->lock, NULL); return b; } @@ -39,14 +38,12 @@ void buffer_destroy(struct buffer *b) struct list_head *i, *tmp; struct buffer_node *node; - pthread_mutex_lock(&b->lock); + /* XXX: set cur_size and num_elems */ list_for_each_safe(i, tmp, &b->head) { node = (struct buffer_node *) i; list_del(i); free(node); } - pthread_mutex_unlock(&b->lock); - pthread_mutex_destroy(&b->lock); free(b); } @@ -70,8 +67,6 @@ int buffer_add(struct buffer *b, const void *data, size_t size) int ret = 0; struct buffer_node *n; - pthread_mutex_lock(&b->lock); - /* does it fit this buffer? */ if (size > b->max_size) { errno = ENOSPC; @@ -97,28 +92,22 @@ retry: list_add(&n->head, &b->head); b->cur_size += size; + b->num_elems++; err: - pthread_mutex_unlock(&b->lock); return ret; } -void __buffer_del(struct buffer *b, void *data) +void buffer_del(struct buffer *b, void *data) { struct buffer_node *n = container_of(data, struct buffer_node, data); list_del(&n->head); b->cur_size -= n->size; + b->num_elems--; free(n); } -void buffer_del(struct buffer *b, void *data) -{ - pthread_mutex_lock(&b->lock); - buffer_del(b, data); - pthread_mutex_unlock(&b->lock); -} - void buffer_iterate(struct buffer *b, void *data, int (*iterate)(void *data1, void *data2)) @@ -126,11 +115,14 @@ void buffer_iterate(struct buffer *b, struct list_head *i, *tmp; struct buffer_node *n; - pthread_mutex_lock(&b->lock); list_for_each_safe(i, tmp, &b->head) { n = (struct buffer_node *) i; if (iterate(n->data, data)) break; } - pthread_mutex_unlock(&b->lock); +} + +unsigned int buffer_len(struct buffer *b) +{ + return b->num_elems; } diff --git a/src/build.c b/src/build.c new file mode 100644 index 0000000..b77dbc2 --- /dev/null +++ b/src/build.c @@ -0,0 +1,113 @@ +/* + * (C) 2006-2007 by Pablo Neira Ayuso + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include "network.h" + +static void addattr(struct netpld *pld, int attr, const void *data, int len) +{ + struct netattr *nta; + int tlen = NTA_LENGTH(len); + + nta = PLD_TAIL(pld); + nta->nta_attr = htons(attr); + nta->nta_len = htons(len); + memcpy(NTA_DATA(nta), data, len); + pld->len += NTA_ALIGN(tlen); +} + +static void __build_u8(const struct nf_conntrack *ct, + struct netpld *pld, + int attr) +{ + u_int8_t data = nfct_get_attr_u8(ct, attr); + addattr(pld, attr, &data, sizeof(u_int8_t)); +} + +static void __build_u16(const struct nf_conntrack *ct, + struct netpld *pld, + int attr) +{ + u_int16_t data = nfct_get_attr_u16(ct, attr); + data = htons(data); + addattr(pld, attr, &data, sizeof(u_int16_t)); +} + +static void __build_u32(const struct nf_conntrack *ct, + struct netpld *pld, + int attr) +{ + u_int32_t data = nfct_get_attr_u32(ct, attr); + data = htonl(data); + addattr(pld, attr, &data, sizeof(u_int32_t)); +} + +/* XXX: IPv6 and ICMP not supported */ +void build_netpld(struct nf_conntrack *ct, struct netpld *pld, int query) +{ + /* undo NAT */ + if (nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) + nfct_setobjopt(ct, NFCT_SOPT_UNDO_SNAT); + if (nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) + nfct_setobjopt(ct, NFCT_SOPT_UNDO_DNAT); + if (nfct_getobjopt(ct, NFCT_GOPT_IS_SPAT)) + nfct_setobjopt(ct, NFCT_SOPT_UNDO_SPAT); + if (nfct_getobjopt(ct, NFCT_GOPT_IS_DPAT)) + nfct_setobjopt(ct, NFCT_SOPT_UNDO_DPAT); + + /* build message */ + if (nfct_attr_is_set(ct, ATTR_IPV4_SRC)) + __build_u32(ct, pld, ATTR_IPV4_SRC); + if (nfct_attr_is_set(ct, ATTR_IPV4_DST)) + __build_u32(ct, pld, ATTR_IPV4_DST); + 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)) { + u_int8_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_is_set(ct, ATTR_SNAT_IPV4)) + __build_u32(ct, pld, ATTR_SNAT_IPV4); + if (nfct_attr_is_set(ct, ATTR_DNAT_IPV4)) + __build_u32(ct, pld, ATTR_DNAT_IPV4); + if (nfct_attr_is_set(ct, ATTR_SNAT_PORT)) + __build_u16(ct, pld, ATTR_SNAT_PORT); + if (nfct_attr_is_set(ct, ATTR_DNAT_PORT)) + __build_u16(ct, pld, ATTR_DNAT_PORT); + if (nfct_attr_is_set(ct, ATTR_TIMEOUT)) + __build_u32(ct, pld, ATTR_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); + + pld->query = query; + + PLD_HOST2NETWORK(pld); +} diff --git a/src/cache.c b/src/cache.c index 3bf331c..1e20d95 100644 --- a/src/cache.c +++ b/src/cache.c @@ -193,9 +193,7 @@ struct cache *cache_create(char *name, void cache_destroy(struct cache *c) { - lock(); hashtable_destroy(c->h); - unlock(); free(c->features); free(c->feature_offset); free(c); @@ -237,7 +235,7 @@ static struct us_conntrack *__add(struct cache *c, struct nf_conntrack *ct) return NULL; } -struct us_conntrack *__cache_add(struct cache *c, struct nf_conntrack *ct) +struct us_conntrack *cache_add(struct cache *c, struct nf_conntrack *ct) { struct us_conntrack *u; @@ -252,17 +250,6 @@ struct us_conntrack *__cache_add(struct cache *c, struct nf_conntrack *ct) return NULL; } -struct us_conntrack *cache_add(struct cache *c, struct nf_conntrack *ct) -{ - struct us_conntrack *u; - - lock(); - u = __cache_add(c, ct); - unlock(); - - return u; -} - static struct us_conntrack *__update(struct cache *c, struct nf_conntrack *ct) { size_t size = c->h->datasize; @@ -317,9 +304,7 @@ struct us_conntrack *cache_update(struct cache *c, struct nf_conntrack *ct) { struct us_conntrack *u; - lock(); u = __cache_update(c, ct); - unlock(); return u; } @@ -329,19 +314,15 @@ struct us_conntrack *cache_update_force(struct cache *c, { struct us_conntrack *u; - lock(); if ((u = __update(c, ct)) != NULL) { c->upd_ok++; - unlock(); return u; } if ((u = __add(c, ct)) != NULL) { c->add_ok++; - unlock(); return u; } c->add_fail++; - unlock(); return NULL; } @@ -354,9 +335,7 @@ int cache_test(struct cache *c, struct nf_conntrack *ct) u->ct = ct; - lock(); ret = hashtable_test(c->h, u); - unlock(); return ret != NULL; } @@ -390,7 +369,7 @@ static int __del(struct cache *c, struct nf_conntrack *ct) return 0; } -int __cache_del(struct cache *c, struct nf_conntrack *ct) +int cache_del(struct cache *c, struct nf_conntrack *ct) { if (__del(c, ct)) { c->del_ok++; @@ -401,17 +380,6 @@ int __cache_del(struct cache *c, struct nf_conntrack *ct) return 0; } -int cache_del(struct cache *c, struct nf_conntrack *ct) -{ - int ret; - - lock(); - ret = __cache_del(c, ct); - unlock(); - - return ret; -} - struct us_conntrack *cache_get_conntrack(struct cache *c, void *data) { return data - c->extra_offset; @@ -427,7 +395,6 @@ void cache_stats(struct cache *c, int fd) char buf[512]; int size; - lock(); size = sprintf(buf, "cache %s:\n" "current active connections:\t%12u\n" "connections created:\t\t%12u\tfailed:\t%12u\n" @@ -441,7 +408,6 @@ void cache_stats(struct cache *c, int fd) c->upd_fail, c->del_ok, c->del_fail); - unlock(); send(fd, buf, size, 0); } @@ -449,7 +415,5 @@ void cache_iterate(struct cache *c, void *data, int (*iterate)(void *data1, void *data2)) { - lock(); hashtable_iterate(c->h, data, iterate); - unlock(); } diff --git a/src/cache_iterators.c b/src/cache_iterators.c index 446cac8..1d1b2e8 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -71,37 +71,25 @@ void cache_dump(struct cache *c, int fd, int type) .type = type }; - /* does not require locking: called inside fork() */ hashtable_iterate(c->h, (void *) &tmp, do_dump); } +/* no need to clone, called from child process */ static int do_commit(void *data1, void *data2) { int ret; struct cache *c = data1; struct us_conntrack *u = data2; - struct nf_conntrack *ct; - char buf[4096]; - struct nlmsghdr *nlh = (struct nlmsghdr *)buf; - - ct = nfct_clone(u->ct); - if (ct == NULL) - return 0; + struct nf_conntrack *ct = u->ct; + /* XXX: related connections */ if (nfct_attr_is_set(ct, ATTR_STATUS)) { u_int32_t status = nfct_get_attr_u32(ct, ATTR_STATUS); status &= ~IPS_EXPECTED; nfct_set_attr_u32(ct, ATTR_STATUS, status); } - if (nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) - nfct_setobjopt(ct, NFCT_SOPT_UNDO_SNAT); - if (nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) - nfct_setobjopt(ct, NFCT_SOPT_UNDO_DNAT); - if (nfct_getobjopt(ct, NFCT_GOPT_IS_SPAT)) - nfct_setobjopt(ct, NFCT_SOPT_UNDO_SPAT); - if (nfct_getobjopt(ct, NFCT_GOPT_IS_DPAT)) - nfct_setobjopt(ct, NFCT_SOPT_UNDO_DPAT); + nfct_setobjopt(ct, NFCT_SOPT_SETUP_REPLY); /* * Set a reduced timeout for candidate-to-be-committed @@ -109,20 +97,12 @@ static int do_commit(void *data1, void *data2) */ nfct_set_attr_u32(ct, ATTR_TIMEOUT, CONFIG(commit_timeout)); - ret = nfct_build_query(STATE(subsys_dump), - NFCT_Q_CREATE_UPDATE, - ct, - nlh, - sizeof(buf)); - - free(ct); - if (ret == -1) { dlog(STATE(log), "failed to build: %s", strerror(errno)); return 0; } - ret = nfnl_query(STATE(dump), nlh); + ret = nfct_query(STATE(dump), NFCT_Q_CREATE_UPDATE, ct); if (ret == -1) { switch(errno) { case EEXIST: @@ -146,7 +126,6 @@ void cache_commit(struct cache *c) unsigned int commit_exist = c->commit_exist; unsigned int commit_fail = c->commit_fail; - /* does not require locking: called inside fork() */ hashtable_iterate(c->h, c, do_commit); /* calculate new entries committed */ @@ -187,30 +166,7 @@ static int do_flush(void *data1, void *data2) void cache_flush(struct cache *c) { - lock(); hashtable_iterate(c->h, c, do_flush); hashtable_flush(c->h); c->flush++; - unlock(); -} - -#include "sync.h" -#include "network.h" - -static int do_bulk(void *data1, void *data2) -{ - int ret; - struct us_conntrack *u = data2; - - mcast_build_send_update(u); - - /* keep iterating even if we have found errors */ - return 0; -} - -void cache_bulk(struct cache *c) -{ - lock(); - hashtable_iterate(c->h, NULL, do_bulk); - unlock(); } diff --git a/src/cache_timer.c b/src/cache_timer.c index 213b59a..f3940f3 100644 --- a/src/cache_timer.c +++ b/src/cache_timer.c @@ -27,7 +27,7 @@ static void timeout(struct alarm_list *a, void *data) struct us_conntrack *u = data; debug_ct(u->ct, "expired timeout"); - __cache_del(u->cache, u->ct); + cache_del(u->cache, u->ct); } static void timer_add(struct us_conntrack *u, void *data) diff --git a/src/lock.c b/src/lock.c index cd68baf..e69de29 100644 --- a/src/lock.c +++ b/src/lock.c @@ -1,32 +0,0 @@ -/* - * (C) 2006 by Pablo Neira Ayuso - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include - -static pthread_mutex_t global_lock = PTHREAD_MUTEX_INITIALIZER; - -void lock() -{ - pthread_mutex_lock(&global_lock); -} - -void unlock() -{ - pthread_mutex_unlock(&global_lock); -} diff --git a/src/main.c b/src/main.c index a039793..007b76e 100644 --- a/src/main.c +++ b/src/main.c @@ -187,6 +187,7 @@ int main(int argc, char *argv[]) case 'F': set_operation_mode(&type, REQUEST, argv); action = FLUSH_MASTER; + break; case 'f': set_operation_mode(&type, REQUEST, argv); action = FLUSH_CACHE; diff --git a/src/mcast.c b/src/mcast.c index 85992fb..6193a59 100644 --- a/src/mcast.c +++ b/src/mcast.c @@ -87,7 +87,6 @@ struct mcast_sock *mcast_server_create(struct mcast_conf *conf) return NULL; } - switch(conf->ipproto) { case AF_INET: if (setsockopt(m->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, diff --git a/src/netlink.c b/src/netlink.c index 5f7cbeb..be5f82e 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -52,19 +52,10 @@ int ignore_conntrack(struct nf_conntrack *ct) return 0; } -static int nl_event_handler(struct nlmsghdr *nlh, - struct nfattr *nfa[], - void *data) +static int event_handler(enum nf_conntrack_msg_type type, + struct nf_conntrack *ct, + void *data) { - char tmp[1024]; - struct nf_conntrack *ct = (struct nf_conntrack *) tmp; - int type; - - memset(tmp, 0, sizeof(tmp)); - - if ((type = nfct_parse_conntrack(NFCT_T_ALL, nlh, ct)) == NFCT_T_ERROR) - return NFCT_CB_STOP; - /* * Ignore this conntrack: it talks about a * connection that is not interesting for us. @@ -74,13 +65,13 @@ static int nl_event_handler(struct nlmsghdr *nlh, switch(type) { case NFCT_T_NEW: - STATE(mode)->event_new(ct, nlh); + STATE(mode)->event_new(ct); break; case NFCT_T_UPDATE: - STATE(mode)->event_upd(ct, nlh); + STATE(mode)->event_upd(ct); break; case NFCT_T_DESTROY: - if (STATE(mode)->event_dst(ct, nlh)) + if (STATE(mode)->event_dst(ct)) update_traffic_stats(ct); break; default: @@ -88,30 +79,31 @@ static int nl_event_handler(struct nlmsghdr *nlh, break; } - return NFCT_CB_STOP; + return NFCT_CB_CONTINUE; } +#include +#include +#include + int nl_init_event_handler(void) { - struct nfnl_callback cb_events = { - .call = nl_event_handler, - .attr_count = CTA_MAX - }; - - /* open event netlink socket */ - STATE(event) = nfnl_open(); + STATE(event) = nfct_open(CONNTRACK, NFCT_ALL_CT_GROUPS); if (!STATE(event)) return -1; + fcntl(nfct_fd(STATE(event)), F_SETFL, O_NONBLOCK); + /* set up socket buffer size */ if (CONFIG(netlink_buffer_size)) - nfnl_rcvbufsiz(STATE(event), CONFIG(netlink_buffer_size)); + nfnl_rcvbufsiz(nfct_nfnlh(STATE(event)), + CONFIG(netlink_buffer_size)); else { socklen_t socklen = sizeof(unsigned int); unsigned int read_size; /* get current buffer size */ - getsockopt(nfnl_fd(STATE(event)), SOL_SOCKET, + getsockopt(nfct_fd(STATE(event)), SOL_SOCKET, SO_RCVBUF, &read_size, &socklen); CONFIG(netlink_buffer_size) = read_size; @@ -122,40 +114,16 @@ int nl_init_event_handler(void) CONFIG(netlink_buffer_size_max_grown) = CONFIG(netlink_buffer_size); - /* open event subsystem */ - STATE(subsys_event) = nfnl_subsys_open(STATE(event), - NFNL_SUBSYS_CTNETLINK, - IPCTNL_MSG_MAX, - NFCT_ALL_CT_GROUPS); - if (STATE(subsys_event) == NULL) - return -1; - - /* register callback for new and update events */ - nfnl_callback_register(STATE(subsys_event), - IPCTNL_MSG_CT_NEW, - &cb_events); - - /* register callback for delete events */ - nfnl_callback_register(STATE(subsys_event), - IPCTNL_MSG_CT_DELETE, - &cb_events); + /* register callback for events */ + nfct_callback_register(STATE(event), NFCT_T_ALL, event_handler, NULL); return 0; } -static int nl_dump_handler(struct nlmsghdr *nlh, - struct nfattr *nfa[], - void *data) +static int dump_handler(enum nf_conntrack_msg_type type, + struct nf_conntrack *ct, + void *data) { - char buf[1024]; - struct nf_conntrack *ct = (struct nf_conntrack *) buf; - int type; - - memset(buf, 0, sizeof(buf)); - - if ((type = nfct_parse_conntrack(NFCT_T_ALL, nlh, ct)) == NFCT_T_ERROR) - return NFCT_CB_CONTINUE; - /* * Ignore this conntrack: it talks about a * connection that is not interesting for us. @@ -165,7 +133,7 @@ static int nl_dump_handler(struct nlmsghdr *nlh, switch(type) { case NFCT_T_UPDATE: - STATE(mode)->dump(ct, nlh); + STATE(mode)->dump(ct); break; default: dlog(STATE(log), "received unknown msg from ctnetlink"); @@ -176,30 +144,15 @@ static int nl_dump_handler(struct nlmsghdr *nlh, int nl_init_dump_handler(void) { - struct nfnl_callback cb_dump = { - .call = nl_dump_handler, - .attr_count = CTA_MAX - }; - /* open dump netlink socket */ - STATE(dump) = nfnl_open(); + STATE(dump) = nfct_open(CONNTRACK, 0); if (!STATE(dump)) return -1; - /* open dump subsystem */ - STATE(subsys_dump) = nfnl_subsys_open(STATE(dump), - NFNL_SUBSYS_CTNETLINK, - IPCTNL_MSG_MAX, - 0); - if (STATE(subsys_dump) == NULL) - return -1; - /* register callback for dumped entries */ - nfnl_callback_register(STATE(subsys_dump), - IPCTNL_MSG_CT_NEW, - &cb_dump); + nfct_callback_register(STATE(dump), NFCT_T_ALL, dump_handler, NULL); - if (nl_dump_conntrack_table(STATE(dump), STATE(subsys_dump)) == -1) + if (nl_dump_conntrack_table() == -1) return -1; return 0; @@ -207,7 +160,7 @@ int nl_init_dump_handler(void) static int warned = 0; -void nl_resize_socket_buffer(struct nfnl_handle *h) +void nl_resize_socket_buffer(struct nfct_handle *h) { unsigned int s = CONFIG(netlink_buffer_size) * 2; @@ -228,44 +181,14 @@ void nl_resize_socket_buffer(struct nfnl_handle *h) warned = 1; } - CONFIG(netlink_buffer_size) = nfnl_rcvbufsiz(h, s); + CONFIG(netlink_buffer_size) = nfnl_rcvbufsiz(nfct_nfnlh(h), s); /* notify the sysadmin */ dlog(STATE(log), "netlink socket buffer size has been set to %u bytes", CONFIG(netlink_buffer_size)); } -int nl_dump_conntrack_table(struct nfnl_handle *h, - struct nfnl_subsys_handle *subsys) +int nl_dump_conntrack_table(void) { - struct nfnlhdr req; - - memset(&req, 0, sizeof(req)); - nfct_build_query(subsys, - NFCT_Q_DUMP, - &CONFIG(family), - &req, - sizeof(req)); - - if (nfnl_query(h, &req.nlh) == -1) - return -1; - - return 0; -} - -int nl_flush_master_conntrack_table(void) -{ - struct nfnlhdr req; - - memset(&req, 0, sizeof(req)); - nfct_build_query(STATE(subsys_dump), - NFCT_Q_FLUSH, - &CONFIG(family), - &req, - sizeof(req)); - - if (nfnl_query(STATE(dump), &req.nlh) == -1) - return -1; - - return 0; + return nfct_query(STATE(dump), NFCT_Q_DUMP, &CONFIG(family)); } diff --git a/src/network.c b/src/network.c index 159bdf3..d162839 100644 --- a/src/network.c +++ b/src/network.c @@ -18,190 +18,159 @@ #include "conntrackd.h" #include "network.h" +#include "us-conntrack.h" +#include "sync.h" static unsigned int seq_set, cur_seq; -static int send_netmsg(struct mcast_sock *m, void *data, unsigned int len) +static int __do_send(struct mcast_sock *m, void *data, int len) { struct nethdr *net = data; - if (!seq_set) { - seq_set = 1; - cur_seq = time(NULL); - net->flags |= NET_F_HELLO; - } - - net->flags = htons(net->flags); - net->seq = htonl(cur_seq++); - #undef _TEST_DROP #ifdef _TEST_DROP static int drop = 0; - if (++drop > 10) { + if (++drop >= 10) { + printf("drop sq: %u fl:%u len:%u\n", + ntohl(net->seq), ntohs(net->flags), + ntohs(net->len)); drop = 0; - printf("dropping resend (seq=%u)\n", ntohl(net->seq)); return 0; } #endif + debug("send sq: %u fl:%u len:%u\n", + ntohl(net->seq), ntohs(net->flags), + ntohs(net->len)); + return mcast_send(m, net, len); } -int mcast_send_netmsg(struct mcast_sock *m, void *data) +static int __do_prepare(struct mcast_sock *m, void *data, int len) { - struct nlmsghdr *nlh = data + NETHDR_SIZ; - unsigned int len = nlh->nlmsg_len + NETHDR_SIZ; struct nethdr *net = data; - if (nlh_host2network(nlh) == -1) - return -1; + if (!seq_set) { + seq_set = 1; + cur_seq = time(NULL); + net->flags |= NET_F_HELLO; + } + net->len = len; + net->seq = cur_seq++; + HDR_HOST2NETWORK(net); - return send_netmsg(m, data, len); + return len; } -int mcast_resend_netmsg(struct mcast_sock *m, void *data) +static int __prepare_ctl(struct mcast_sock *m, void *data) { - struct nethdr *net = data; - struct nlmsghdr *nlh = data + NETHDR_SIZ; - unsigned int len; + struct nethdr_ack *nack = (struct nethdr_ack *) data; - net->flags = ntohs(net->flags); + return __do_prepare(m, data, NETHDR_ACK_SIZ); +} - if (net->flags & NET_F_NACK || net->flags & NET_F_ACK) - len = NETHDR_ACK_SIZ; - else - len = ntohl(nlh->nlmsg_len) + NETHDR_SIZ; +static int __prepare_data(struct mcast_sock *m, void *data) +{ + struct nethdr *net = (struct nethdr *) data; + struct netpld *pld = NETHDR_DATA(net); - return send_netmsg(m, data, len); + return __do_prepare(m, data, ntohs(pld->len) + NETPLD_SIZ + NETHDR_SIZ); } -int mcast_send_error(struct mcast_sock *m, void *data) +int prepare_send_netmsg(struct mcast_sock *m, void *data) { - struct nethdr *net = data; - unsigned int len = NETHDR_SIZ; + int ret = 0; + struct nethdr *net = (struct nethdr *) data; - if (net->flags & NET_F_NACK || net->flags & NET_F_ACK) { - struct nethdr_ack *nack = (struct nethdr_ack *) net; - nack->from = htonl(nack->from); - nack->to = htonl(nack->to); - len = NETHDR_ACK_SIZ; - } + if (IS_DATA(net)) + ret = __prepare_data(m, data); + else if (IS_CTL(net)) + ret = __prepare_ctl(m, data); - return send_netmsg(m, data, len); + return ret; } -#include "us-conntrack.h" -#include "sync.h" +static int tx_buflen = 0; +/* XXX: use buffer size of interface MTU */ +static char __tx_buf[1460], *tx_buf = __tx_buf; -static int __build_send(struct us_conntrack *u, int type, int query) +/* return 0 if it is not sent, otherwise return 1 */ +int mcast_buffered_send_netmsg(struct mcast_sock *m, void *data, int len) { - char __net[4096]; - struct nethdr *net = (struct nethdr *) __net; + int ret = 0; + struct nethdr *net = data; - if (!state_helper_verdict(type, u->ct)) - return 0; +retry: + if (tx_buflen + len < sizeof(__tx_buf)) { + memcpy(__tx_buf + tx_buflen, net, len); + tx_buflen += len; + } else { + __do_send(m, tx_buf, tx_buflen); + ret = 1; + tx_buflen = 0; + goto retry; + } - int ret = build_network_msg(query, - STATE(subsys_event), - u->ct, - __net, - sizeof(__net)); + return ret; +} - if (ret == -1) - return -1; +int mcast_buffered_pending_netmsg(struct mcast_sock *m) +{ + int ret; + + if (tx_buflen == 0) + return 0; - mcast_send_netmsg(STATE_SYNC(mcast_client), __net); - if (STATE_SYNC(sync)->send) - STATE_SYNC(sync)->send(type, net, u); + ret = __do_send(m, tx_buf, tx_buflen); + tx_buflen = 0; - return 0; + return ret; } -int mcast_build_send_update(struct us_conntrack *u) +int mcast_send_netmsg(struct mcast_sock *m, void *data) { - return __build_send(u, NFCT_T_UPDATE, NFCT_Q_UPDATE); + int ret; + int len = prepare_send_netmsg(m, data); + + ret = mcast_buffered_send_netmsg(m, data, len); + mcast_buffered_pending_netmsg(m); + + return ret; } -int mcast_build_send_destroy(struct us_conntrack *u) +void build_netmsg(struct nf_conntrack *ct, int query, struct nethdr *net) { - return __build_send(u, NFCT_T_DESTROY, NFCT_Q_DESTROY); + struct netpld *pld = NETHDR_DATA(net); + + build_netpld(ct, pld, query); } -int mcast_recv_netmsg(struct mcast_sock *m, void *data, int len) +int handle_netmsg(struct nethdr *net) { int ret; - struct nethdr *net = data; - struct nlmsghdr *nlh = data + NETHDR_SIZ; - struct nfgenmsg *nfhdr; - - ret = mcast_recv(m, net, len); - if (ret <= 0) - return ret; + struct netpld *pld = NETHDR_DATA(net); /* message too small: no room for the header */ - if (ret < NETHDR_SIZ) + if (ntohs(net->len) < NETHDR_ACK_SIZ) return -1; - if (ntohs(net->flags) & NET_F_HELLO) - STATE_SYNC(last_seq_recv) = ntohl(net->seq) - 1; + HDR_NETWORK2HOST(net); - if (ntohs(net->flags) & NET_F_NACK || ntohs(net->flags) & NET_F_ACK) { - struct nethdr_ack *nack = (struct nethdr_ack *) net; + if (IS_HELLO(net)) + STATE_SYNC(last_seq_recv) = net->seq - 1; - /* message too small: no room for the header */ - if (ret < NETHDR_ACK_SIZ) - return -1; - - /* host byte order conversion */ - net->flags = ntohs(net->flags); - net->seq = ntohl(net->seq); - - /* acknowledgement conversion */ - nack->from = ntohl(nack->from); - nack->to = ntohl(nack->to); - - return ret; - } - - if (ntohs(net->flags) & NET_F_RESYNC) { - /* host byte order conversion */ - net->flags = ntohs(net->flags); - net->seq = ntohl(net->seq); - - return ret; - } + if (IS_CTL(net)) + return 0; /* information received is too small */ - if (ret < NLMSG_SPACE(sizeof(struct nfgenmsg))) - return -1; - - /* information received and message length does not match */ - if (ret != ntohl(nlh->nlmsg_len) + NETHDR_SIZ) - return -1; - - /* this message does not come from ctnetlink */ - if (NFNL_SUBSYS_ID(ntohs(nlh->nlmsg_type)) != NFNL_SUBSYS_CTNETLINK) + if (net->len < sizeof(struct netpld)) return -1; - nfhdr = NLMSG_DATA(nlh); - - /* only AF_INET and AF_INET6 are supported */ - if (nfhdr->nfgen_family != AF_INET && - nfhdr->nfgen_family != AF_INET6) - return -1; - - /* only process message coming from nfnetlink v0 */ - if (nfhdr->version != NFNETLINK_V0) - return -1; - - /* host byte order conversion */ - net->flags = ntohs(net->flags); - net->seq = ntohl(net->seq); - - if (nlh_network2host(nlh) == -1) + /* size mismatch! */ + if (net->len < ntohs(pld->len) + NETHDR_SIZ) return -1; - return ret; + return 0; } int mcast_track_seq(u_int32_t seq, u_int32_t *exp_seq) @@ -238,30 +207,3 @@ out: return ret; } - -int build_network_msg(const int msg_type, - struct nfnl_subsys_handle *ssh, - struct nf_conntrack *ct, - void *buffer, - unsigned int size) -{ - memset(buffer, 0, size); - buffer += NETHDR_SIZ; - size -= NETHDR_SIZ; - return nfct_build_query(ssh, msg_type, ct, buffer, size); -} - -unsigned int parse_network_msg(struct nf_conntrack *ct, - const struct nlmsghdr *nlh) -{ - /* - * The parsing of netlink messages going through network is - * similar to the one that is done for messages coming from - * kernel, therefore do not replicate more code and use the - * function provided in the libraries. - * - * Yup, this is a hack 8) - */ - return nfct_parse_conntrack(NFCT_T_ALL, nlh, ct); -} - diff --git a/src/parse.c b/src/parse.c new file mode 100644 index 0000000..81b70c4 --- /dev/null +++ b/src/parse.c @@ -0,0 +1,76 @@ +/* + * (C) 2006-2007 by Pablo Neira Ayuso + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include "network.h" + +static int parse_u8(struct nf_conntrack *ct, int attr, void *data) +{ + u_int8_t *value = (u_int8_t *) data; + nfct_set_attr_u8(ct, attr, *value); +} + +static int parse_u16(struct nf_conntrack *ct, int attr, void *data) +{ + u_int16_t *value = (u_int16_t *) data; + nfct_set_attr_u16(ct, attr, ntohs(*value)); +} + +static int parse_u32(struct nf_conntrack *ct, int attr, void *data) +{ + u_int32_t *value = (u_int32_t *) data; + nfct_set_attr_u32(ct, attr, ntohl(*value)); +} + +typedef int (*parse)(struct nf_conntrack *ct, int attr, void *data); + +parse h[ATTR_MAX] = { + [ATTR_IPV4_SRC] = parse_u32, + [ATTR_IPV4_DST] = parse_u32, + [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, +}; + +void parse_netpld(struct nf_conntrack *ct, struct netpld *pld, int *query) +{ + int len; + struct netattr *attr; + + PLD_NETWORK2HOST(pld); + len = pld->len; + attr = PLD_DATA(pld); + + while (len > 0) { + ATTR_NETWORK2HOST(attr); + h[attr->nta_attr](ct, attr->nta_attr, NTA_DATA(attr)); + attr = NTA_NEXT(attr, len); + } + + *query = pld->query; +} diff --git a/src/proxy.c b/src/proxy.c deleted file mode 100644 index b9bb04e..0000000 --- a/src/proxy.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - * (C) 2006 by Pablo Neira Ayuso - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include - -#if 0 -#define dprintf printf -#else -#define dprintf -#endif - -int nlh_payload_host2network(struct nfattr *nfa, int len) -{ - struct nfattr *__nfa; - - while (NFA_OK(nfa, len)) { - - dprintf("type=%d nfalen=%d len=%d [%s]\n", - nfa->nfa_type & 0x7fff, - nfa->nfa_len, len, - nfa->nfa_type & NFNL_NFA_NEST ? "NEST":""); - - if (nfa->nfa_type & NFNL_NFA_NEST) { - if (NFA_PAYLOAD(nfa) > len) - return -1; - - if (nlh_payload_host2network(NFA_DATA(nfa), - NFA_PAYLOAD(nfa)) == -1) - return -1; - } - - __nfa = NFA_NEXT(nfa, len); - - nfa->nfa_type = htons(nfa->nfa_type); - nfa->nfa_len = htons(nfa->nfa_len); - - nfa = __nfa; - } - return 0; -} - -int nlh_host2network(struct nlmsghdr *nlh) -{ - struct nfgenmsg *nfhdr = NLMSG_DATA(nlh); - struct nfattr *cda[CTA_MAX]; - unsigned int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg)); - unsigned int len = nlh->nlmsg_len - NLMSG_ALIGN(min_len); - - nlh->nlmsg_len = htonl(nlh->nlmsg_len); - nlh->nlmsg_type = htons(nlh->nlmsg_type); - nlh->nlmsg_flags = htons(nlh->nlmsg_flags); - nlh->nlmsg_seq = htonl(nlh->nlmsg_seq); - nlh->nlmsg_pid = htonl(nlh->nlmsg_pid); - - nfhdr->res_id = htons(nfhdr->res_id); - - return nlh_payload_host2network(NFM_NFA(NLMSG_DATA(nlh)), len); -} - -int nlh_payload_network2host(struct nfattr *nfa, int len) -{ - nfa->nfa_type = ntohs(nfa->nfa_type); - nfa->nfa_len = ntohs(nfa->nfa_len); - - while(NFA_OK(nfa, len)) { - - dprintf("type=%d nfalen=%d len=%d [%s]\n", - nfa->nfa_type & 0x7fff, - nfa->nfa_len, len, - nfa->nfa_type & NFNL_NFA_NEST ? "NEST":""); - - if (nfa->nfa_type & NFNL_NFA_NEST) { - if (NFA_PAYLOAD(nfa) > len) - return -1; - - if (nlh_payload_network2host(NFA_DATA(nfa), - NFA_PAYLOAD(nfa)) == -1) - return -1; - } - - nfa = NFA_NEXT(nfa,len); - - if (len < NFA_LENGTH(0)) - break; - - nfa->nfa_type = ntohs(nfa->nfa_type); - nfa->nfa_len = ntohs(nfa->nfa_len); - } - return 0; -} - -int nlh_network2host(struct nlmsghdr *nlh) -{ - struct nfgenmsg *nfhdr = NLMSG_DATA(nlh); - struct nfattr *cda[CTA_MAX]; - unsigned int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg)); - unsigned int len = ntohl(nlh->nlmsg_len) - NLMSG_ALIGN(min_len); - - nlh->nlmsg_len = ntohl(nlh->nlmsg_len); - nlh->nlmsg_type = ntohs(nlh->nlmsg_type); - nlh->nlmsg_flags = ntohs(nlh->nlmsg_flags); - nlh->nlmsg_seq = ntohl(nlh->nlmsg_seq); - nlh->nlmsg_pid = ntohl(nlh->nlmsg_pid); - - nfhdr->res_id = ntohs(nfhdr->res_id); - - return nlh_payload_network2host(NFM_NFA(NLMSG_DATA(nlh)), len); -} diff --git a/src/run.c b/src/run.c index 0173c9f..644f82e 100644 --- a/src/run.c +++ b/src/run.c @@ -24,20 +24,21 @@ #include "us-conntrack.h" #include #include +#include +#include "timer.h" void killer(int foo) { /* no signals while handling signals */ sigprocmask(SIG_BLOCK, &STATE(block), NULL); - nfnl_subsys_close(STATE(subsys_event)); - nfnl_subsys_close(STATE(subsys_dump)); - nfnl_close(STATE(event)); - nfnl_close(STATE(dump)); + nfct_close(STATE(event)); + nfct_close(STATE(dump)); ignore_pool_destroy(STATE(ignore_pool)); local_server_destroy(STATE(local)); STATE(mode)->kill(); + destroy_alarm_scheduler(); unlink(CONFIG(lockfile)); dlog(STATE(log), "------- shutdown received ----"); close_log(STATE(log)); @@ -69,12 +70,16 @@ void local_handler(int fd, void *data) switch(type) { case FLUSH_MASTER: - dlog(STATE(log), "[REQ] flushing master table"); - nl_flush_master_conntrack_table(); + dlog(STATE(log), "[DEPRECATED] `conntrackd -F' is deprecated. " + "Use conntrack -F instead."); + if (fork() == 0) { + execlp("conntrack", "conntrack", "-F", NULL); + exit(EXIT_SUCCESS); + } return; case RESYNC_MASTER: dlog(STATE(log), "[REQ] resync with master table"); - nl_dump_conntrack_table(STATE(dump), STATE(subsys_dump)); + nl_dump_conntrack_table(); return; } @@ -104,6 +109,11 @@ int init(int mode) return -1; } + if (init_alarm_scheduler() == -1) { + dlog(STATE(log), "[FAIL] can't initialize alarm scheduler"); + return -1; + } + /* local UNIX socket */ STATE(local) = local_server_create(&CONFIG(local)); if (!STATE(local)) { @@ -147,22 +157,20 @@ int init(int mode) return 0; } -#define POLL_NSECS 1 - -static void __run(void) +static void __run(long credit, int step) { int max, ret; fd_set readfds; struct timeval tv = { - .tv_sec = POLL_NSECS, - .tv_usec = 0 + .tv_sec = 0, + .tv_usec = credit, }; FD_ZERO(&readfds); FD_SET(STATE(local), &readfds); - FD_SET(nfnl_fd(STATE(event)), &readfds); + FD_SET(nfct_fd(STATE(event)), &readfds); - max = MAX(STATE(local), nfnl_fd(STATE(event))); + max = MAX(STATE(local), nfct_fd(STATE(event))); if (STATE(mode)->add_fds_to_set) max = MAX(max, STATE(mode)->add_fds_to_set(&readfds)); @@ -185,8 +193,8 @@ static void __run(void) do_local_server_step(STATE(local), NULL, local_handler); /* conntrack event has happened */ - if (FD_ISSET(nfnl_fd(STATE(event)), &readfds)) { - ret = nfnl_catch(STATE(event)); + if (FD_ISSET(nfct_fd(STATE(event)), &readfds)) { + while ((ret = nfct_catch(STATE(event))) != -1); if (ret == -1) { switch(errno) { case ENOBUFS: @@ -197,6 +205,7 @@ static void __run(void) * size and resync with master conntrack table. */ nl_resize_socket_buffer(STATE(event)); + /* XXX: schedule overrun call via alarm */ STATE(mode)->overrun(); break; case ENOENT: @@ -206,6 +215,8 @@ static void __run(void) * interested in. Just ignore it. */ break; + case EAGAIN: + break; default: dlog(STATE(log), "event catch says: %s", strerror(errno)); @@ -214,14 +225,35 @@ static void __run(void) } } - if (STATE(mode)->step) - STATE(mode)->step(&readfds); + if (STATE(mode)->run) + STATE(mode)->run(&readfds, step); sigprocmask(SIG_UNBLOCK, &STATE(block), NULL); } void run(void) { - while(1) - __run(); + int step = 0; + struct timer timer; + + timer_init(&timer); + + while(1) { + timer_start(&timer); + __run(GET_CREDITS(timer), step); + timer_stop(&timer); + + if (timer_adjust_credit(&timer)) { + timer_start(&timer); + sigprocmask(SIG_BLOCK, &STATE(block), NULL); + do_alarm_run(step); + sigprocmask(SIG_UNBLOCK, &STATE(block), NULL); + timer_stop(&timer); + + if (timer_adjust_credit(&timer)) + dlog(STATE(log), "alarm run takes too long!"); + + step = (step + 1) < STEPS_PER_SECONDS ? step + 1 : 0; + } + } } diff --git a/src/state_helper.c b/src/state_helper.c index 81b0d09..eba9d8f 100644 --- a/src/state_helper.c +++ b/src/state_helper.c @@ -25,7 +25,7 @@ int state_helper_verdict(int type, struct nf_conntrack *ct) { u_int8_t l4proto; - if (type == NFCT_T_DESTROY) + if (type == NFCT_Q_DESTROY) return ST_H_REPLICATE; l4proto = nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO); diff --git a/src/stats-mode.c b/src/stats-mode.c index 92794cd..65bab1b 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -86,7 +86,7 @@ static int local_handler_stats(int fd, int type, void *data) return ret; } -static void dump_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh) +static void dump_stats(struct nf_conntrack *ct) { if (cache_update_force(STATE_STATS(cache), ct)) debug_ct(ct, "resync entry"); @@ -137,7 +137,7 @@ static void overrun_stats() nfct_close(h); } -static void event_new_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh) +static void event_new_stats(struct nf_conntrack *ct) { if (cache_add(STATE_STATS(cache), ct)) { debug_ct(ct, "cache new"); @@ -150,7 +150,7 @@ static void event_new_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh) } } -static void event_update_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh) +static void event_update_stats(struct nf_conntrack *ct) { if (!cache_update_force(STATE_STATS(cache), ct)) { debug_ct(ct, "can't update"); @@ -159,7 +159,7 @@ static void event_update_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh) debug_ct(ct, "update"); } -static int event_destroy_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh) +static int event_destroy_stats(struct nf_conntrack *ct) { if (cache_del(STATE_STATS(cache), ct)) { debug_ct(ct, "cache destroy"); @@ -173,7 +173,7 @@ static int event_destroy_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh) struct ct_mode stats_mode = { .init = init_stats, .add_fds_to_set = NULL, - .step = NULL, + .run = NULL, .local = local_handler_stats, .kill = kill_stats, .dump = dump_stats, diff --git a/src/sync-mode.c b/src/sync-mode.c index 38ab016..f30cb95 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -27,43 +27,27 @@ #include #include "sync.h" #include "network.h" +#include "buffer.h" +#include "debug.h" -/* handler for multicast messages received */ -static void mcast_handler() +static void do_mcast_handler_step(struct nethdr *net) { - int ret; - unsigned int type; - char __net[4096]; - struct nethdr *net = (struct nethdr *) __net; - struct nlmsghdr *nlh = (struct nlmsghdr *) (__net + NETHDR_SIZ); + unsigned int query; + struct netpld *pld = NETHDR_DATA(net); char __ct[nfct_maxsize()]; struct nf_conntrack *ct = (struct nf_conntrack *) __ct; struct us_conntrack *u = NULL; - ret = mcast_recv_netmsg(STATE_SYNC(mcast_server), net, sizeof(__net)); - if (ret <= 0) { - STATE(malformed)++; - return; - } - if (STATE_SYNC(sync)->recv(net)) return; memset(ct, 0, sizeof(__ct)); - if ((type = parse_network_msg(ct, nlh)) == NFCT_T_ERROR) { - STATE(malformed)++; - return; - } + /* XXX: check for malformed */ + parse_netpld(ct, pld, &query); - nfct_attr_unset(ct, ATTR_TIMEOUT); - nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES); - nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS); - nfct_attr_unset(ct, ATTR_REPL_COUNTER_BYTES); - nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS); - - switch(type) { - case NFCT_T_NEW: + switch(query) { + case NFCT_Q_CREATE: retry: if ((u = cache_add(STATE_SYNC(external), ct))) { debug_ct(u->ct, "external new"); @@ -80,24 +64,57 @@ retry: debug_ct(ct, "can't add"); } break; - case NFCT_T_UPDATE: + case NFCT_Q_UPDATE: if ((u = cache_update_force(STATE_SYNC(external), ct))) { debug_ct(u->ct, "external update"); } else debug_ct(ct, "can't update"); break; - case NFCT_T_DESTROY: + case NFCT_Q_DESTROY: if (cache_del(STATE_SYNC(external), ct)) debug_ct(ct, "external destroy"); else debug_ct(ct, "can't destroy"); break; default: - dlog(STATE(log), "mcast received unknown msg type %d\n", type); + dlog(STATE(log), "mcast received unknown query %d\n", query); break; } } +/* handler for multicast messages received */ +static void mcast_handler() +{ + int numbytes, remain; + char __net[4096], *ptr = __net; + + numbytes = mcast_recv(STATE_SYNC(mcast_server), __net, sizeof(__net)); + if (numbytes <= 0) + return; + + remain = numbytes; + while (remain > 0) { + struct nethdr *net = (struct nethdr *) ptr; + + if (ntohs(net->len) > remain) { + dlog(STATE(log), "fragmented messages"); + break; + } + + debug("recv sq: %u fl:%u len:%u (rem:%d)\n", + ntohl(net->seq), ntohs(net->flags), + ntohs(net->len), remain); + + if (handle_netmsg(net) == -1) { + STATE(malformed)++; + return; + } + do_mcast_handler_step(net); + ptr += net->len; + remain -= net->len; + } +} + static int init_sync(void) { int ret; @@ -159,11 +176,6 @@ static int init_sync(void) /* initialization of multicast sequence generation */ STATE_SYNC(last_seq_sent) = time(NULL); - if (create_alarm_thread() == -1) { - dlog(STATE(log), "[FAIL] can't initialize alarm thread"); - return -1; - } - return 0; } @@ -174,11 +186,17 @@ static int add_fds_to_set_sync(fd_set *readfds) return STATE_SYNC(mcast_server->fd); } -static void step_sync(fd_set *readfds) +static void run_sync(fd_set *readfds, int step) { /* multicast packet has been received */ if (FD_ISSET(STATE_SYNC(mcast_server->fd), readfds)) mcast_handler(); + + if (STATE_SYNC(sync)->run) + STATE_SYNC(sync)->run(step); + + /* flush pending messages */ + mcast_buffered_pending_netmsg(STATE_SYNC(mcast_client)); } static void kill_sync() @@ -189,8 +207,6 @@ static void kill_sync() mcast_server_destroy(STATE_SYNC(mcast_server)); mcast_client_destroy(STATE_SYNC(mcast_client)); - destroy_alarm_thread(); - if (STATE_SYNC(sync)->kill) STATE_SYNC(sync)->kill(); } @@ -267,10 +283,6 @@ static int local_handler_sync(int fd, int type, void *data) STATE_SYNC(mcast_server)); dump_stats_sync(fd); break; - case SEND_BULK: - dlog(STATE(log), "[REQ] sending bulk update"); - cache_bulk(STATE_SYNC(internal)); - break; default: if (STATE_SYNC(sync)->local) ret = STATE_SYNC(sync)->local(fd, type, data); @@ -280,7 +292,7 @@ static int local_handler_sync(int fd, int type, void *data) return ret; } -static void dump_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh) +static void dump_sync(struct nf_conntrack *ct) { /* This is required by kernels < 2.6.20 */ nfct_attr_unset(ct, ATTR_TIMEOUT); @@ -294,23 +306,21 @@ static void dump_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh) debug_ct(ct, "resync"); } -static void mcast_send_sync(struct nlmsghdr *nlh, - struct us_conntrack *u, +static void mcast_send_sync(struct us_conntrack *u, struct nf_conntrack *ct, - int type) + int query) { - char __net[4096]; - struct nethdr *net = (struct nethdr *) __net; - - memset(__net, 0, sizeof(__net)); + int len; + struct nethdr *net; - if (!state_helper_verdict(type, ct)) + if (!state_helper_verdict(query, ct)) return; - memcpy(__net + NETHDR_SIZ, nlh, nlh->nlmsg_len); - mcast_send_netmsg(STATE_SYNC(mcast_client), net); + net = BUILD_NETMSG(ct, query); + len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); + mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); if (STATE_SYNC(sync)->send) - STATE_SYNC(sync)->send(type, net, u); + STATE_SYNC(sync)->send(net, u); } static int overrun_cb(enum nf_conntrack_msg_type type, @@ -332,8 +342,16 @@ static int overrun_cb(enum nf_conntrack_msg_type type, if (!cache_test(STATE_SYNC(internal), ct)) { if ((u = cache_update_force(STATE_SYNC(internal), ct))) { + int len; + debug_ct(u->ct, "overrun resync"); - mcast_build_send_update(u); + + struct nethdr *net = BUILD_NETMSG(u->ct, NFCT_Q_UPDATE); + len = prepare_send_netmsg(STATE_SYNC(mcast_client),net); + mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), + net, len); + if (STATE_SYNC(sync)->send) + STATE_SYNC(sync)->send(net, u); } } @@ -348,9 +366,17 @@ static int overrun_purge_step(void *data1, void *data2) ret = nfct_query(h, NFCT_Q_GET, u->ct); if (ret == -1 && errno == ENOENT) { + int len; + struct nethdr *net = BUILD_NETMSG(u->ct, NFCT_Q_DESTROY); + debug_ct(u->ct, "overrun purge resync"); - mcast_build_send_destroy(u); - __cache_del(STATE_SYNC(internal), u->ct); + + len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); + mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); + if (STATE_SYNC(sync)->send) + STATE_SYNC(sync)->send(net, u); + + cache_del(STATE_SYNC(internal), u->ct); } return 0; @@ -382,7 +408,7 @@ static void overrun_sync() nfct_close(h); } -static void event_new_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh) +static void event_new_sync(struct nf_conntrack *ct) { struct us_conntrack *u; @@ -394,12 +420,12 @@ static void event_new_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh) nfct_attr_unset(ct, ATTR_TIMEOUT); retry: if ((u = cache_add(STATE_SYNC(internal), ct))) { - mcast_send_sync(nlh, u, ct, NFCT_T_NEW); + mcast_send_sync(u, ct, NFCT_Q_CREATE); debug_ct(u->ct, "internal new"); } else { if (errno == EEXIST) { cache_del(STATE_SYNC(internal), ct); - mcast_send_sync(nlh, NULL, ct, NFCT_T_DESTROY); + mcast_send_sync(NULL, ct, NFCT_Q_DESTROY); goto retry; } @@ -409,7 +435,7 @@ retry: } } -static void event_update_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh) +static void event_update_sync(struct nf_conntrack *ct) { struct us_conntrack *u; @@ -420,15 +446,15 @@ static void event_update_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh) return; } debug_ct(u->ct, "internal update"); - mcast_send_sync(nlh, u, ct, NFCT_T_UPDATE); + mcast_send_sync(u, ct, NFCT_Q_UPDATE); } -static int event_destroy_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh) +static int event_destroy_sync(struct nf_conntrack *ct) { nfct_attr_unset(ct, ATTR_TIMEOUT); if (cache_del(STATE_SYNC(internal), ct)) { - mcast_send_sync(nlh, NULL, ct, NFCT_T_DESTROY); + mcast_send_sync(NULL, ct, NFCT_Q_DESTROY); debug_ct(ct, "internal destroy"); } else debug_ct(ct, "can't destroy"); @@ -437,7 +463,7 @@ static int event_destroy_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh) struct ct_mode sync_mode = { .init = init_sync, .add_fds_to_set = add_fds_to_set_sync, - .step = step_sync, + .run = run_sync, .local = local_handler_sync, .kill = kill_sync, .dump = dump_sync, diff --git a/src/sync-nack.c b/src/sync-nack.c index 20ad1f4..dbda0a7 100644 --- a/src/sync-nack.c +++ b/src/sync-nack.c @@ -24,6 +24,7 @@ #include "buffer.h" #include "debug.h" #include "network.h" +#include "alarm.h" #include #include @@ -33,28 +34,34 @@ #define dp #endif -static LIST_HEAD(queue); +static LIST_HEAD(rs_list); +static LIST_HEAD(tx_list); +static unsigned int tx_list_len; +static struct buffer *rs_queue; +static struct buffer *tx_queue; struct cache_nack { - struct list_head head; + struct list_head rs_list; + struct list_head tx_list; u_int32_t seq; }; static void cache_nack_add(struct us_conntrack *u, void *data) { struct cache_nack *cn = data; - INIT_LIST_HEAD(&cn->head); + INIT_LIST_HEAD(&cn->rs_list); + INIT_LIST_HEAD(&cn->tx_list); } static void cache_nack_del(struct us_conntrack *u, void *data) { struct cache_nack *cn = data; - if (cn->head.next == &cn->head && - cn->head.prev == &cn->head) + if (cn->rs_list.next == &cn->rs_list && + cn->rs_list.prev == &cn->rs_list) return; - list_del(&cn->head); + list_del(&cn->rs_list); } static struct cache_extra cache_nack_extra = { @@ -65,19 +72,31 @@ static struct cache_extra cache_nack_extra = { static int nack_init() { - STATE_SYNC(buffer) = buffer_create(CONFIG(resend_buffer_size)); - if (STATE_SYNC(buffer) == NULL) + tx_queue = buffer_create(CONFIG(resend_buffer_size)); + if (tx_queue == NULL) { + dlog(STATE(log), "[FAIL] cannot create tx buffer"); return -1; + } + + rs_queue = buffer_create(CONFIG(resend_buffer_size)); + if (rs_queue == NULL) { + dlog(STATE(log), "[FAIL] cannot create rs buffer"); + return -1; + } + + INIT_LIST_HEAD(&tx_list); + INIT_LIST_HEAD(&rs_list); return 0; } static void nack_kill() { - buffer_destroy(STATE_SYNC(buffer)); + buffer_destroy(rs_queue); + buffer_destroy(tx_queue); } -static void mcast_send_control(u_int32_t flags, u_int32_t from, u_int32_t to) +static void tx_queue_add_ctlmsg(u_int32_t flags, u_int32_t from, u_int32_t to) { struct nethdr_ack ack = { .flags = flags, @@ -85,8 +104,19 @@ static void mcast_send_control(u_int32_t flags, u_int32_t from, u_int32_t to) .to = to, }; - mcast_send_error(STATE_SYNC(mcast_client), &ack); - buffer_add(STATE_SYNC(buffer), &ack, NETHDR_ACK_SIZ); + buffer_add(tx_queue, &ack, NETHDR_ACK_SIZ); +} + +static int do_cache_to_tx(void *data1, void *data2) +{ + struct us_conntrack *u = data2; + struct cache_nack *cn = cache_get_extra(STATE_SYNC(internal), u); + + /* add to tx list */ + list_add(&cn->tx_list, &tx_list); + tx_list_len++; + + return 0; } static int nack_local(int fd, int type, void *data) @@ -94,85 +124,78 @@ static int nack_local(int fd, int type, void *data) int ret = 1; switch(type) { - case REQUEST_DUMP: - mcast_send_control(NET_F_RESYNC, 0, 0); - dlog(STATE(log), "[REQ] request resync"); - break; - default: - ret = 0; - break; + case REQUEST_DUMP: + dlog(STATE(log), "[REQ] request resync"); + tx_queue_add_ctlmsg(NET_F_RESYNC, 0, 0); + break; + case SEND_BULK: + dlog(STATE(log), "[REQ] sending bulk update"); + cache_iterate(STATE_SYNC(internal), NULL, do_cache_to_tx); + break; + default: + ret = 0; + break; } return ret; } -static int buffer_compare(void *data1, void *data2) +static int rs_queue_to_tx(void *data1, void *data2) { struct nethdr *net = data1; struct nethdr_ack *nack = data2; - struct nlmsghdr *nlh = data1 + NETHDR_SIZ; - - unsigned old_seq = ntohl(net->seq); - if (between(ntohl(net->seq), nack->from, nack->to)) { - if (mcast_resend_netmsg(STATE_SYNC(mcast_client), net)) - dp("resend destroy (old seq=%u) (seq=%u)\n", - old_seq, ntohl(net->seq)); + if (between(net->seq, nack->from, nack->to)) { + dp("rs_queue_to_tx sq: %u fl:%u len:%u\n", + net->seq, net->flags, net->len); + buffer_add(tx_queue, net, net->len); } return 0; } -static int buffer_remove(void *data1, void *data2) +static int rs_queue_empty(void *data1, void *data2) { struct nethdr *net = data1; struct nethdr_ack *h = data2; - if (between(ntohl(net->seq), h->from, h->to)) { - dp("remove from buffer (seq=%u)\n", ntohl(net->seq)); - __buffer_del(STATE_SYNC(buffer), data1); + if (between(net->seq, h->from, h->to)) { + dp("remove from buffer (seq=%u)\n", net->seq); + buffer_del(rs_queue, data1); } return 0; } -static void queue_resend(struct cache *c, unsigned int from, unsigned int to) +static void rs_list_to_tx(struct cache *c, unsigned int from, unsigned int to) { struct list_head *n; struct us_conntrack *u; - list_for_each(n, &queue) { + list_for_each(n, &rs_list) { struct cache_nack *cn = (struct cache_nack *) n; struct us_conntrack *u; u = cache_get_conntrack(STATE_SYNC(internal), cn); - if (between(cn->seq, from, to)) { - debug_ct(u->ct, "resend nack"); - dp("resending nack'ed (oldseq=%u) ", cn->seq); - - if (mcast_build_send_update(u) == -1) - continue; - - dp("(newseq=%u)\n", cn->seq); + dp("resending nack'ed (oldseq=%u)\n", cn->seq); + list_add(&cn->tx_list, &tx_list); + tx_list_len++; } } } -static void queue_empty(struct cache *c, unsigned int from, unsigned int to) +static void rs_list_empty(struct cache *c, unsigned int from, unsigned int to) { struct list_head *n, *tmp; - struct us_conntrack *u; - dp("ACK from %u to %u\n", from, to); - list_for_each_safe(n, tmp, &queue) { + list_for_each_safe(n, tmp, &rs_list) { struct cache_nack *cn = (struct cache_nack *) n; + struct us_conntrack *u; u = cache_get_conntrack(STATE_SYNC(internal), cn); if (between(cn->seq, from, to)) { - dp("remove %u\n", cn->seq); - debug_ct(u->ct, "ack received: empty queue"); dp("queue: deleting from queue (seq=%u)\n", cn->seq); - list_del(&cn->head); - INIT_LIST_HEAD(&cn->head); + list_del(&cn->rs_list); + INIT_LIST_HEAD(&cn->rs_list); } } } @@ -187,73 +210,149 @@ static int nack_recv(const struct nethdr *net) if (!mcast_track_seq(net->seq, &exp_seq)) { dp("OOS: sending nack (seq=%u)\n", exp_seq); - mcast_send_control(NET_F_NACK, exp_seq, net->seq - 1); + tx_queue_add_ctlmsg(NET_F_NACK, exp_seq, net->seq-1); window = CONFIG(window_size); } else { /* received a window, send an acknowledgement */ if (--window == 0) { dp("sending ack (seq=%u)\n", net->seq); - mcast_send_control(NET_F_ACK, - net->seq - CONFIG(window_size), - net->seq); + tx_queue_add_ctlmsg(NET_F_ACK, + net->seq - CONFIG(window_size), + net->seq); } } - if (net->flags & NET_F_NACK) { + if (IS_NACK(net)) { struct nethdr_ack *nack = (struct nethdr_ack *) net; dp("NACK: from seq=%u to seq=%u\n", nack->from, nack->to); - queue_resend(STATE_SYNC(internal), nack->from, nack->to); - buffer_iterate(STATE_SYNC(buffer), nack, buffer_compare); + rs_list_to_tx(STATE_SYNC(internal), nack->from, nack->to); + buffer_iterate(rs_queue, nack, rs_queue_to_tx); return 1; - } else if (net->flags & NET_F_RESYNC) { + } else if (IS_RESYNC(net)) { dp("RESYNC ALL\n"); - cache_bulk(STATE_SYNC(internal)); + cache_iterate(STATE_SYNC(internal), NULL, do_cache_to_tx); return 1; - } else if (net->flags & NET_F_ACK) { + } else if (IS_ACK(net)) { struct nethdr_ack *h = (struct nethdr_ack *) net; dp("ACK: from seq=%u to seq=%u\n", h->from, h->to); - queue_empty(STATE_SYNC(internal), h->from, h->to); - buffer_iterate(STATE_SYNC(buffer), h, buffer_remove); + rs_list_empty(STATE_SYNC(internal), h->from, h->to); + buffer_iterate(rs_queue, h, rs_queue_empty); + return 1; + } else if (IS_ALIVE(net)) return 1; - } return 0; } -static void nack_send(int type, - const struct nethdr *net, - struct us_conntrack *u) +static void nack_send(struct nethdr *net, struct us_conntrack *u) { - int size = NETHDR_SIZ; - struct nlmsghdr *nlh = (struct nlmsghdr *) ((void *) net + size); + struct netpld *pld = NETHDR_DATA(net); struct cache_nack *cn; - - size += ntohl(nlh->nlmsg_len); - switch(type) { - case NFCT_T_NEW: - case NFCT_T_UPDATE: + HDR_NETWORK2HOST(net); + + switch(ntohs(pld->query)) { + case NFCT_Q_CREATE: + case NFCT_Q_UPDATE: cn = (struct cache_nack *) cache_get_extra(STATE_SYNC(internal), u); - if (cn->head.next == &cn->head && - cn->head.prev == &cn->head) + if (cn->rs_list.next == &cn->rs_list && + cn->rs_list.prev == &cn->rs_list) goto insert; - list_del(&cn->head); - INIT_LIST_HEAD(&cn->head); + list_del(&cn->rs_list); + INIT_LIST_HEAD(&cn->rs_list); insert: - cn->seq = ntohl(net->seq); - list_add(&cn->head, &queue); + cn->seq = net->seq; + list_add(&cn->rs_list, &rs_list); break; - case NFCT_T_DESTROY: - buffer_add(STATE_SYNC(buffer), net, size); + case NFCT_Q_DESTROY: + buffer_add(rs_queue, net, net->len); break; } } +static int tx_queue_xmit(void *data1, void *data2) +{ + struct nethdr *net = data1; + int len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); + + dp("tx_queue sq: %u fl:%u len:%u\n", + ntohl(net->seq), ntohs(net->flags), ntohs(net->len)); + + mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); + HDR_NETWORK2HOST(net); + + if (IS_DATA(net) || IS_ACK(net) || IS_NACK(net)) { + dp("-> back_to_tx_queue sq: %u fl:%u len:%u\n", + net->seq, net->flags, net->len); + buffer_add(rs_queue, net, net->len); + } + buffer_del(tx_queue, net); + + return 0; +} + +static int tx_list_xmit(struct list_head *i, struct us_conntrack *u) +{ + int ret; + struct nethdr *net = BUILD_NETMSG(u->ct, NFCT_Q_UPDATE); + int len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); + + dp("tx_list sq: %u fl:%u len:%u\n", + ntohl(net->seq), ntohs(net->flags), + ntohs(net->len)); + + list_del(i); + INIT_LIST_HEAD(i); + tx_list_len--; + + ret = mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); + if (STATE_SYNC(sync)->send) + STATE_SYNC(sync)->send(net, u); + + return ret; +} + +static struct alarm_list alive_alarm; + +static void do_alive_alarm(struct alarm_list *a, void *data) +{ + del_alarm(a); + tx_queue_add_ctlmsg(NET_F_ALIVE, 0, 0); +} + +static void nack_run(int step) +{ + struct list_head *i, *tmp; + + /* send messages in the tx_queue */ + buffer_iterate(tx_queue, NULL, tx_queue_xmit); + + /* send conntracks in the tx_list */ + list_for_each_safe(i, tmp, &tx_list) { + struct cache_nack *cn; + struct us_conntrack *u; + + cn = container_of(i, struct cache_nack, tx_list); + u = cache_get_conntrack(STATE_SYNC(internal), cn); + tx_list_xmit(i, u); + } + + if (alive_alarm.expires > 0) + mod_alarm(&alive_alarm, 1); + else { + init_alarm(&alive_alarm); + /* XXX: alive message expiration configurable */ + set_alarm_expiration(&alive_alarm, 1); + set_alarm_function(&alive_alarm, do_alive_alarm); + add_alarm(&alive_alarm); + } +} + struct sync_mode nack = { .internal_cache_flags = LIFETIME, .external_cache_flags = LIFETIME, @@ -263,4 +362,5 @@ struct sync_mode nack = { .local = nack_local, .recv = nack_recv, .send = nack_send, + .run = nack_run, }; diff --git a/src/sync-notrack.c b/src/sync-notrack.c index 1d6eba8..8588ecf 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -24,12 +24,16 @@ static void refresher(struct alarm_list *a, void *data) { + int len; + struct nethdr *net; struct us_conntrack *u = data; debug_ct(u->ct, "persistence update"); a->expires = random() % CONFIG(refresh) + 1; - mcast_build_send_update(u); + net = BUILD_NETMSG(u->ct, NFCT_Q_UPDATE); + len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); + mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); } static void cache_notrack_add(struct us_conntrack *u, void *data) diff --git a/src/timer.c b/src/timer.c new file mode 100644 index 0000000..b85c286 --- /dev/null +++ b/src/timer.c @@ -0,0 +1,75 @@ +/* + * (C) 2006-2007 by Pablo Neira Ayuso + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include "conntrackd.h" +#include "timer.h" + +#define TIMESLICE_CREDIT (1000000 / STEPS_PER_SECONDS) /* 200 ms timeslice */ + +void timer_init(struct timer *timer) +{ + memset(timer, 0, sizeof(struct timer)); + timer->credits = TIMESLICE_CREDIT; +} + +void timer_start(struct timer *timer) +{ + gettimeofday(&timer->start, NULL); +} + +static int timeval_subtract(struct timeval *diff, + struct timeval *start, + struct timeval *stop) +{ + diff->tv_sec = stop->tv_sec - start->tv_sec; + diff->tv_usec = stop->tv_usec - start->tv_usec; + + if (diff->tv_usec < 0) { + diff->tv_usec += 1000000; + diff->tv_sec--; + } + + /* Return 1 if result is negative. */ + return diff->tv_sec < 0; +} + +void timer_stop(struct timer *timer) +{ + gettimeofday(&timer->stop, NULL); + timeval_subtract(&timer->diff, &timer->start, &timer->stop); +} + +int timer_adjust_credit(struct timer *timer) +{ + if (timer->diff.tv_sec != 0) { + timer->credits = TIMESLICE_CREDIT; + return 1; + } + + timer->credits -= timer->diff.tv_usec; + + if (timer->credits < 0) { + timer->credits += TIMESLICE_CREDIT; + if (timer->credits < 0) + timer->credits = TIMESLICE_CREDIT; + return 1; + } + return 0; +} -- cgit v1.2.3 From 5bac4f06e8ebc81ed16ec93a0db8682e6a359608 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Fri, 21 Dec 2007 18:04:49 +0000 Subject: o Use more appropriate names for the existing synchronization modes: o rename `persistent' mode to `alarm' o rename `nack' mode to `ftfw' o Now default synchronization mode is ftfw instead of alarm --- ChangeLog | 4 + examples/sync/alarm/README | 1 + examples/sync/alarm/node1/conntrackd.conf | 140 ++++++++++ examples/sync/alarm/node1/keepalived.conf | 39 +++ examples/sync/alarm/node2/conntrackd.conf | 140 ++++++++++ examples/sync/alarm/node2/keepalived.conf | 39 +++ examples/sync/alarm/script_backup.sh | 3 + examples/sync/alarm/script_master.sh | 4 + examples/sync/ftfw/README | 1 + examples/sync/ftfw/node1/conntrackd.conf | 135 +++++++++ examples/sync/ftfw/node1/keepalived.conf | 39 +++ examples/sync/ftfw/node2/conntrackd.conf | 134 +++++++++ examples/sync/ftfw/node2/keepalived.conf | 39 +++ examples/sync/ftfw/script_backup.sh | 3 + examples/sync/ftfw/script_master.sh | 5 + examples/sync/nack/README | 1 - examples/sync/nack/node1/conntrackd.conf | 135 --------- examples/sync/nack/node1/keepalived.conf | 39 --- examples/sync/nack/node2/conntrackd.conf | 134 --------- examples/sync/nack/node2/keepalived.conf | 39 --- examples/sync/nack/script_backup.sh | 3 - examples/sync/nack/script_master.sh | 5 - examples/sync/persistent/README | 1 - examples/sync/persistent/node1/conntrackd.conf | 140 ---------- examples/sync/persistent/node1/keepalived.conf | 39 --- examples/sync/persistent/node2/conntrackd.conf | 140 ---------- examples/sync/persistent/node2/keepalived.conf | 39 --- examples/sync/persistent/script_backup.sh | 3 - examples/sync/persistent/script_master.sh | 4 - include/conntrackd.h | 10 +- include/sync.h | 4 +- src/Makefile.am | 2 +- src/main.c | 2 +- src/read_config_lex.l | 14 +- src/read_config_yy.y | 10 +- src/sync-alarm.c | 104 +++++++ src/sync-ftfw.c | 366 +++++++++++++++++++++++++ src/sync-mode.c | 8 +- src/sync-nack.c | 366 ------------------------- src/sync-notrack.c | 104 ------- 40 files changed, 1226 insertions(+), 1212 deletions(-) create mode 100644 examples/sync/alarm/README create mode 100644 examples/sync/alarm/node1/conntrackd.conf create mode 100644 examples/sync/alarm/node1/keepalived.conf create mode 100644 examples/sync/alarm/node2/conntrackd.conf create mode 100644 examples/sync/alarm/node2/keepalived.conf create mode 100755 examples/sync/alarm/script_backup.sh create mode 100755 examples/sync/alarm/script_master.sh create mode 100644 examples/sync/ftfw/README create mode 100644 examples/sync/ftfw/node1/conntrackd.conf create mode 100644 examples/sync/ftfw/node1/keepalived.conf create mode 100644 examples/sync/ftfw/node2/conntrackd.conf create mode 100644 examples/sync/ftfw/node2/keepalived.conf create mode 100755 examples/sync/ftfw/script_backup.sh create mode 100755 examples/sync/ftfw/script_master.sh delete mode 100644 examples/sync/nack/README delete mode 100644 examples/sync/nack/node1/conntrackd.conf delete mode 100644 examples/sync/nack/node1/keepalived.conf delete mode 100644 examples/sync/nack/node2/conntrackd.conf delete mode 100644 examples/sync/nack/node2/keepalived.conf delete mode 100755 examples/sync/nack/script_backup.sh delete mode 100755 examples/sync/nack/script_master.sh delete mode 100644 examples/sync/persistent/README delete mode 100644 examples/sync/persistent/node1/conntrackd.conf delete mode 100644 examples/sync/persistent/node1/keepalived.conf delete mode 100644 examples/sync/persistent/node2/conntrackd.conf delete mode 100644 examples/sync/persistent/node2/keepalived.conf delete mode 100755 examples/sync/persistent/script_backup.sh delete mode 100755 examples/sync/persistent/script_master.sh create mode 100644 src/sync-alarm.c create mode 100644 src/sync-ftfw.c delete mode 100644 src/sync-nack.c delete mode 100644 src/sync-notrack.c (limited to 'src/sync-notrack.c') diff --git a/ChangeLog b/ChangeLog index 74f0bc5..272b078 100644 --- a/ChangeLog +++ b/ChangeLog @@ -17,6 +17,10 @@ o add CacheWriteThrough clause: external cache write through policy o add support for secmark (requires Linux kernel >= 2.6.25) o add conntrackd (8) manpage o raise ignorepool maximum limit from 1024 to INT_MAX +o Use more appropriate names for the existing synchronization modes: + o rename `persistent' mode to `alarm' + o rename `nack' mode to `ftfw' +o Now default synchronization mode is ftfw instead of alarm version 0.9.5 (2007/07/29) ------------------------------ diff --git a/examples/sync/alarm/README b/examples/sync/alarm/README new file mode 100644 index 0000000..dfd8474 --- /dev/null +++ b/examples/sync/alarm/README @@ -0,0 +1 @@ +This directory contains the files for the ALARM based protocol diff --git a/examples/sync/alarm/node1/conntrackd.conf b/examples/sync/alarm/node1/conntrackd.conf new file mode 100644 index 0000000..3004d07 --- /dev/null +++ b/examples/sync/alarm/node1/conntrackd.conf @@ -0,0 +1,140 @@ +# +# Synchronizer settings +# +Sync { + Mode ALARM { + # + # If a conntrack entry is not modified in <= 15 seconds, then + # a message is broadcasted. This mechanism is used to + # resynchronize nodes that just joined the multicast group + # + RefreshTime 15 + + # + # If we don't receive a notification about the state of + # an entry in the external cache after N seconds, then + # remove it. + # + CacheTimeout 180 + + # + # Entries committed to the connection tracking table + # starts with a limited timeout of N seconds until the + # takeover process is completed. + # + CommitTimeout 180 + } + + # + # Multicast IP and interface where messages are + # broadcasted (dedicated link). IMPORTANT: Make sure + # that iptables accepts traffic for destination + # 225.0.0.50, eg: + # + # iptables -I INPUT -d 225.0.0.50 -j ACCEPT + # iptables -I OUTPUT -d 225.0.0.50 -j ACCEPT + # + Multicast { + IPv4_address 225.0.0.50 + IPv4_interface 192.168.100.100 # IP of dedicated link + Interface eth2 + Group 3780 + } + + # Enable/Disable message checksumming + Checksum on + + # Uncomment this if you want to replicate just certain TCP states. + # This option introduces a tradeoff in the replication: it reduces + # CPU consumption and lost messages rate at the cost of having + # backup replicas that don't contain the current state that the active + # replica holds. TCP states are: SYN_SENT, SYN_RECV, ESTABLISHED, + # FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE, LISTEN. + # + # Replicate ESTABLISHED TIME_WAIT for TCP + + # If you have a multiprimary setup (active-active) without connection + # persistency, ie. you can't know which firewall handles a packet + # that is part of a connection, then you need direct commit of + # conntrack entries to the kernel conntrack table. OSPF setups must + # set on this option. Default is Off. + # + # CacheWriteThrough On +} + +# +# General settings +# +General { + # + # Number of buckets in the caches: hash table + # + HashSize 8192 + + # + # Maximum number of conntracks: + # it must be >= $ cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max + # + HashLimit 65535 + + # + # Logfile: on, off, or a filename + # Default: on (/var/log/conntrackd.log) + # + #LogFile off + + # + # Syslog: on, off or a facility name (daemon (default) or local0..7) + # Default: off + # + #Syslog on + + # + # Lockfile + # + LockFile /var/lock/conntrack.lock + + # + # Unix socket configuration + # + UNIX { + Path /tmp/sync.sock + Backlog 20 + } + + # + # Netlink socket buffer size + # + SocketBufferSize 262142 + + # + # Increase the socket buffer up to maximum if required + # + SocketBufferSizeMaxGrown 655355 +} + +# +# Ignore traffic for a certain set of IP's: Usually +# all the IP assigned to the firewall since local +# traffic must be ignored, just forwarded connections +# are worth to replicate +# +IgnoreTrafficFor { + IPv4_address 127.0.0.1 # loopback + IPv4_address 192.168.0.1 + IPv4_address 192.168.1.1 + IPv4_address 192.168.100.100 # dedicated link ip + IPv4_address 192.168.0.100 # virtual IP 1 + IPv4_address 192.168.1.100 # virtual IP 2 +} + +# +# Do not replicate certain protocol traffic +# +IgnoreProtocol { + UDP + ICMP + IGMP + VRRP + # numeric numbers also valid +} diff --git a/examples/sync/alarm/node1/keepalived.conf b/examples/sync/alarm/node1/keepalived.conf new file mode 100644 index 0000000..f937467 --- /dev/null +++ b/examples/sync/alarm/node1/keepalived.conf @@ -0,0 +1,39 @@ +vrrp_sync_group G1 { # must be before vrrp_instance declaration + group { + VI_1 + VI_2 + } + notify_master /etc/conntrackd/script_master.sh + notify_backup /etc/conntrackd/script_backup.sh +# notify_fault /etc/conntrackd/script_fault.sh +} + +vrrp_instance VI_1 { + interface eth1 + state SLAVE + virtual_router_id 61 + priority 80 + advert_int 3 + authentication { + auth_type PASS + auth_pass papas_con_tomate + } + virtual_ipaddress { + 192.168.0.100 # default CIDR mask is /32 + } +} + +vrrp_instance VI_2 { + interface eth0 + state SLAVE + virtual_router_id 62 + priority 80 + advert_int 3 + authentication { + auth_type PASS + auth_pass papas_con_tomate + } + virtual_ipaddress { + 192.168.1.100 + } +} diff --git a/examples/sync/alarm/node2/conntrackd.conf b/examples/sync/alarm/node2/conntrackd.conf new file mode 100644 index 0000000..fb12130 --- /dev/null +++ b/examples/sync/alarm/node2/conntrackd.conf @@ -0,0 +1,140 @@ +# +# Synchronizer settings +# +Sync { + Mode ALARM { + # + # If a conntrack entry is not modified in <= 15 seconds, then + # a message is broadcasted. This mechanism is used to + # resynchronize nodes that just joined the multicast group + # + RefreshTime 15 + + # + # If we don't receive a notification about the state of + # an entry in the external cache after N seconds, then + # remove it. + # + CacheTimeout 180 + + # + # Entries committed to the connection tracking table + # starts with a limited timeout of N seconds until the + # takeover process is completed. + # + CommitTimeout 180 + } + + # + # Multicast IP and interface where messages are + # broadcasted (dedicated link). IMPORTANT: Make sure + # that iptables accepts traffic for destination + # 225.0.0.50, eg: + # + # iptables -I INPUT -d 225.0.0.50 -j ACCEPT + # iptables -I OUTPUT -d 225.0.0.50 -j ACCEPT + # + Multicast { + IPv4_address 225.0.0.50 + IPv4_interface 192.168.100.200 # IP of dedicated link + Interface eth2 + Group 3780 + } + + # Enable/Disable message checksumming + Checksum on + + # Uncomment this if you want to replicate just certain TCP states. + # This option introduces a tradeoff in the replication: it reduces + # CPU consumption and lost messages rate at the cost of having + # backup replicas that don't contain the current state that the active + # replica holds. TCP states are: SYN_SENT, SYN_RECV, ESTABLISHED, + # FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE, LISTEN. + # + # Replicate ESTABLISHED TIME_WAIT for TCP + + # If you have a multiprimary setup (active-active) without connection + # persistency, ie. you can't know which firewall handles a packet + # that is part of a connection, then you need direct commit of + # conntrack entries to the kernel conntrack table. OSPF setups must + # set on this option. Default is Off. + # + # CacheWriteThrough On +} + +# +# General settings +# +General { + # + # Number of buckets in the caches: hash table + # + HashSize 8192 + + # + # Maximum number of conntracks: + # it must be >= $ cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max + # + HashLimit 65535 + + # + # Logfile: on, off, or a filename + # Default: on (/var/log/conntrackd.log) + # + #LogFile off + + # + # Syslog: on, off or a facility name (daemon (default) or local0..7) + # Default: off + # + #Syslog on + + # + # Lockfile + # + LockFile /var/lock/conntrack.lock + + # + # Unix socket configuration + # + UNIX { + Path /tmp/sync.sock + Backlog 20 + } + + # + # Netlink socket buffer size + # + SocketBufferSize 262142 + + # + # Increase the socket buffer up to maximum if required + # + SocketBufferSizeMaxGrown 655355 +} + +# +# Ignore traffic for a certain set of IP's: Usually +# all the IP assigned to the firewall since local +# traffic must be ignored, just forwarded connections +# are worth to replicate +# +IgnoreTrafficFor { + IPv4_address 127.0.0.1 # loopback + IPv4_address 192.168.0.2 + IPv4_address 192.168.1.2 + IPv4_address 192.168.100.200 # dedicated link ip + IPv4_address 192.168.0.200 # virtual IP 1 + IPv4_address 192.168.1.200 # virtual IP 2 +} + +# +# Do not replicate certain protocol traffic +# +IgnoreProtocol { + UDP + ICMP + IGMP + VRRP + # numeric numbers also valid +} diff --git a/examples/sync/alarm/node2/keepalived.conf b/examples/sync/alarm/node2/keepalived.conf new file mode 100644 index 0000000..f937467 --- /dev/null +++ b/examples/sync/alarm/node2/keepalived.conf @@ -0,0 +1,39 @@ +vrrp_sync_group G1 { # must be before vrrp_instance declaration + group { + VI_1 + VI_2 + } + notify_master /etc/conntrackd/script_master.sh + notify_backup /etc/conntrackd/script_backup.sh +# notify_fault /etc/conntrackd/script_fault.sh +} + +vrrp_instance VI_1 { + interface eth1 + state SLAVE + virtual_router_id 61 + priority 80 + advert_int 3 + authentication { + auth_type PASS + auth_pass papas_con_tomate + } + virtual_ipaddress { + 192.168.0.100 # default CIDR mask is /32 + } +} + +vrrp_instance VI_2 { + interface eth0 + state SLAVE + virtual_router_id 62 + priority 80 + advert_int 3 + authentication { + auth_type PASS + auth_pass papas_con_tomate + } + virtual_ipaddress { + 192.168.1.100 + } +} diff --git a/examples/sync/alarm/script_backup.sh b/examples/sync/alarm/script_backup.sh new file mode 100755 index 0000000..8ea2ad8 --- /dev/null +++ b/examples/sync/alarm/script_backup.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +/usr/sbin/conntrackd -B diff --git a/examples/sync/alarm/script_master.sh b/examples/sync/alarm/script_master.sh new file mode 100755 index 0000000..70c26c9 --- /dev/null +++ b/examples/sync/alarm/script_master.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +/usr/sbin/conntrackd -c +/usr/sbin/conntrackd -R diff --git a/examples/sync/ftfw/README b/examples/sync/ftfw/README new file mode 100644 index 0000000..a09db10 --- /dev/null +++ b/examples/sync/ftfw/README @@ -0,0 +1 @@ +This directory contains the files for the FT-FW based protocol diff --git a/examples/sync/ftfw/node1/conntrackd.conf b/examples/sync/ftfw/node1/conntrackd.conf new file mode 100644 index 0000000..fadeb9d --- /dev/null +++ b/examples/sync/ftfw/node1/conntrackd.conf @@ -0,0 +1,135 @@ +# +# Synchronizer settings +# +Sync { + Mode FTFW { + # + # Size of the buffer that hold destroy messages for + # possible resends (in bytes) + # + ResendBufferSize 262144 + + # + # Entries committed to the connection tracking table + # starts with a limited timeout of N seconds until the + # takeover process is completed. + # + CommitTimeout 180 + + # Set Acknowledgement window size + ACKWindowSize 20 + } + + # + # Multicast IP and interface where messages are + # broadcasted (dedicated link). IMPORTANT: Make sure + # that iptables accepts traffic for destination + # 225.0.0.50, eg: + # + # iptables -I INPUT -d 225.0.0.50 -j ACCEPT + # iptables -I OUTPUT -d 225.0.0.50 -j ACCEPT + # + Multicast { + IPv4_address 225.0.0.50 + IPv4_interface 192.168.100.100 # IP of dedicated link + Interface eth2 + Group 3780 + } + + # Enable/Disable message checksumming + Checksum on + + # Uncomment this if you want to replicate just certain TCP states. + # This option introduces a tradeoff in the replication: it reduces + # CPU consumption and lost messages rate at the cost of having + # backup replicas that don't contain the current state that the active + # replica holds. TCP states are: SYN_SENT, SYN_RECV, ESTABLISHED, + # FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE, LISTEN. + # + # Replicate ESTABLISHED TIME_WAIT for TCP + + # If you have a multiprimary setup (active-active) without connection + # persistency, ie. you can't know which firewall handles a packet + # that is part of a connection, then you need direct commit of + # conntrack entries to the kernel conntrack table. OSPF setups must + # set on this option. Default is Off. + # + # CacheWriteThrough On +} + +# +# General settings +# +General { + # + # Number of buckets in the caches: hash table + # + HashSize 8192 + + # + # Maximum number of conntracks: + # it must be >= $ cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max + # + HashLimit 65535 + + # + # Logfile: on, off, or a filename + # Default: on (/var/log/conntrackd.log) + # + #LogFile off + + # + # Syslog: on, off or a facility name (daemon (default) or local0..7) + # Default: off + # + #Syslog on + + # + # Lockfile + # + LockFile /var/lock/conntrack.lock + + # + # Unix socket configuration + # + UNIX { + Path /tmp/sync.sock + Backlog 20 + } + + # + # Netlink socket buffer size + # + SocketBufferSize 262142 + + # + # Increase the socket buffer up to maximum if required + # + SocketBufferSizeMaxGrown 655355 +} + +# +# Ignore traffic for a certain set of IP's: Usually +# all the IP assigned to the firewall since local +# traffic must be ignored, just forwarded connections +# are worth to replicate +# +IgnoreTrafficFor { + IPv4_address 127.0.0.1 # loopback + IPv4_address 192.168.0.1 + IPv4_address 192.168.1.1 + IPv4_address 192.168.100.100 # dedicated link ip + IPv4_address 192.168.0.100 # virtual IP 1 + IPv4_address 192.168.1.100 # virtual IP 2 +} + +# +# Do not replicate certain protocol traffic +# +IgnoreProtocol { + UDP + ICMP + IGMP + VRRP + # numeric numbers also valid +} diff --git a/examples/sync/ftfw/node1/keepalived.conf b/examples/sync/ftfw/node1/keepalived.conf new file mode 100644 index 0000000..f937467 --- /dev/null +++ b/examples/sync/ftfw/node1/keepalived.conf @@ -0,0 +1,39 @@ +vrrp_sync_group G1 { # must be before vrrp_instance declaration + group { + VI_1 + VI_2 + } + notify_master /etc/conntrackd/script_master.sh + notify_backup /etc/conntrackd/script_backup.sh +# notify_fault /etc/conntrackd/script_fault.sh +} + +vrrp_instance VI_1 { + interface eth1 + state SLAVE + virtual_router_id 61 + priority 80 + advert_int 3 + authentication { + auth_type PASS + auth_pass papas_con_tomate + } + virtual_ipaddress { + 192.168.0.100 # default CIDR mask is /32 + } +} + +vrrp_instance VI_2 { + interface eth0 + state SLAVE + virtual_router_id 62 + priority 80 + advert_int 3 + authentication { + auth_type PASS + auth_pass papas_con_tomate + } + virtual_ipaddress { + 192.168.1.100 + } +} diff --git a/examples/sync/ftfw/node2/conntrackd.conf b/examples/sync/ftfw/node2/conntrackd.conf new file mode 100644 index 0000000..59ffc4f --- /dev/null +++ b/examples/sync/ftfw/node2/conntrackd.conf @@ -0,0 +1,134 @@ +# +# Synchronizer settings +# +Sync { + Mode FTFW { + # + # Size of the buffer that hold destroy messages for + # possible resends (in bytes) + # + ResendBufferSize 262144 + + # Entries committed to the connection tracking table + # starts with a limited timeout of N seconds until the + # takeover process is completed. + # + CommitTimeout 180 + + # Set Acknowledgement window size + ACKWindowSize 20 + } + + # + # Multicast IP and interface where messages are + # broadcasted (dedicated link). IMPORTANT: Make sure + # that iptables accepts traffic for destination + # 225.0.0.50, eg: + # + # iptables -I INPUT -d 225.0.0.50 -j ACCEPT + # iptables -I OUTPUT -d 225.0.0.50 -j ACCEPT + # + Multicast { + IPv4_address 225.0.0.50 + IPv4_interface 192.168.100.200 # IP of dedicated link + Interface eth2 + Group 3780 + } + + # Enable/Disable message checksumming + Checksum on + + # Uncomment this if you want to replicate just certain TCP states. + # This option introduces a tradeoff in the replication: it reduces + # CPU consumption and lost messages rate at the cost of having + # backup replicas that don't contain the current state that the active + # replica holds. TCP states are: SYN_SENT, SYN_RECV, ESTABLISHED, + # FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE, LISTEN. + # + # Replicate ESTABLISHED TIME_WAIT for TCP + + # If you have a multiprimary setup (active-active) without connection + # persistency, ie. you can't know which firewall handles a packet + # that is part of a connection, then you need direct commit of + # conntrack entries to the kernel conntrack table. OSPF setups must + # set on this option. Default is Off. + # + # CacheWriteThrough On +} + +# +# General settings +# +General { + # + # Number of buckets in the caches: hash table + # + HashSize 8192 + + # + # Maximum number of conntracks: + # it must be >= $ cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max + # + HashLimit 65535 + + # + # Logfile: on, off, or a filename + # Default: on (/var/log/conntrackd.log) + # + #LogFile off + + # + # Syslog: on, off or a facility name (daemon (default) or local0..7) + # Default: off + # + #Syslog on + + # + # Lockfile + # + LockFile /var/lock/conntrack.lock + + # + # Unix socket configuration + # + UNIX { + Path /tmp/sync.sock + Backlog 20 + } + + # + # Netlink socket buffer size + # + SocketBufferSize 262142 + + # + # Increase the socket buffer up to maximum if required + # + SocketBufferSizeMaxGrown 655355 +} + +# +# Ignore traffic for a certain set of IP's: Usually +# all the IP assigned to the firewall since local +# traffic must be ignored, just forwarded connections +# are worth to replicate +# +IgnoreTrafficFor { + IPv4_address 127.0.0.1 # loopback + IPv4_address 192.168.0.2 + IPv4_address 192.168.1.2 + IPv4_address 192.168.100.200 # dedicated link ip + IPv4_address 192.168.0.200 # virtual IP 1 + IPv4_address 192.168.1.200 # virtual IP 2 +} + +# +# Do not replicate certain protocol traffic +# +IgnoreProtocol { + UDP + ICMP + IGMP + VRRP + # numeric numbers also valid +} diff --git a/examples/sync/ftfw/node2/keepalived.conf b/examples/sync/ftfw/node2/keepalived.conf new file mode 100644 index 0000000..f937467 --- /dev/null +++ b/examples/sync/ftfw/node2/keepalived.conf @@ -0,0 +1,39 @@ +vrrp_sync_group G1 { # must be before vrrp_instance declaration + group { + VI_1 + VI_2 + } + notify_master /etc/conntrackd/script_master.sh + notify_backup /etc/conntrackd/script_backup.sh +# notify_fault /etc/conntrackd/script_fault.sh +} + +vrrp_instance VI_1 { + interface eth1 + state SLAVE + virtual_router_id 61 + priority 80 + advert_int 3 + authentication { + auth_type PASS + auth_pass papas_con_tomate + } + virtual_ipaddress { + 192.168.0.100 # default CIDR mask is /32 + } +} + +vrrp_instance VI_2 { + interface eth0 + state SLAVE + virtual_router_id 62 + priority 80 + advert_int 3 + authentication { + auth_type PASS + auth_pass papas_con_tomate + } + virtual_ipaddress { + 192.168.1.100 + } +} diff --git a/examples/sync/ftfw/script_backup.sh b/examples/sync/ftfw/script_backup.sh new file mode 100755 index 0000000..813e375 --- /dev/null +++ b/examples/sync/ftfw/script_backup.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +/usr/sbin/conntrackd -n # request a resync from other nodes via multicast diff --git a/examples/sync/ftfw/script_master.sh b/examples/sync/ftfw/script_master.sh new file mode 100755 index 0000000..ff1dbc0 --- /dev/null +++ b/examples/sync/ftfw/script_master.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +/usr/sbin/conntrackd -c # commit the cache +/usr/sbin/conntrackd -f # flush the caches +/usr/sbin/conntrackd -R # resync with kernel conntrack table diff --git a/examples/sync/nack/README b/examples/sync/nack/README deleted file mode 100644 index 66987f7..0000000 --- a/examples/sync/nack/README +++ /dev/null @@ -1 +0,0 @@ -This directory contains the files for the NACK based protocol diff --git a/examples/sync/nack/node1/conntrackd.conf b/examples/sync/nack/node1/conntrackd.conf deleted file mode 100644 index 4fc8f22..0000000 --- a/examples/sync/nack/node1/conntrackd.conf +++ /dev/null @@ -1,135 +0,0 @@ -# -# Synchronizer settings -# -Sync { - Mode NACK { - # - # Size of the buffer that hold destroy messages for - # possible resends (in bytes) - # - ResendBufferSize 262144 - - # - # Entries committed to the connection tracking table - # starts with a limited timeout of N seconds until the - # takeover process is completed. - # - CommitTimeout 180 - - # Set Acknowledgement window size - ACKWindowSize 20 - } - - # - # Multicast IP and interface where messages are - # broadcasted (dedicated link). IMPORTANT: Make sure - # that iptables accepts traffic for destination - # 225.0.0.50, eg: - # - # iptables -I INPUT -d 225.0.0.50 -j ACCEPT - # iptables -I OUTPUT -d 225.0.0.50 -j ACCEPT - # - Multicast { - IPv4_address 225.0.0.50 - IPv4_interface 192.168.100.100 # IP of dedicated link - Interface eth2 - Group 3780 - } - - # Enable/Disable message checksumming - Checksum on - - # Uncomment this if you want to replicate just certain TCP states. - # This option introduces a tradeoff in the replication: it reduces - # CPU consumption and lost messages rate at the cost of having - # backup replicas that don't contain the current state that the active - # replica holds. TCP states are: SYN_SENT, SYN_RECV, ESTABLISHED, - # FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE, LISTEN. - # - # Replicate ESTABLISHED TIME_WAIT for TCP - - # If you have a multiprimary setup (active-active) without connection - # persistency, ie. you can't know which firewall handles a packet - # that is part of a connection, then you need direct commit of - # conntrack entries to the kernel conntrack table. OSPF setups must - # set on this option. Default is Off. - # - # CacheWriteThrough On -} - -# -# General settings -# -General { - # - # Number of buckets in the caches: hash table - # - HashSize 8192 - - # - # Maximum number of conntracks: - # it must be >= $ cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max - # - HashLimit 65535 - - # - # Logfile: on, off, or a filename - # Default: on (/var/log/conntrackd.log) - # - #LogFile off - - # - # Syslog: on, off or a facility name (daemon (default) or local0..7) - # Default: off - # - #Syslog on - - # - # Lockfile - # - LockFile /var/lock/conntrack.lock - - # - # Unix socket configuration - # - UNIX { - Path /tmp/sync.sock - Backlog 20 - } - - # - # Netlink socket buffer size - # - SocketBufferSize 262142 - - # - # Increase the socket buffer up to maximum if required - # - SocketBufferSizeMaxGrown 655355 -} - -# -# Ignore traffic for a certain set of IP's: Usually -# all the IP assigned to the firewall since local -# traffic must be ignored, just forwarded connections -# are worth to replicate -# -IgnoreTrafficFor { - IPv4_address 127.0.0.1 # loopback - IPv4_address 192.168.0.1 - IPv4_address 192.168.1.1 - IPv4_address 192.168.100.100 # dedicated link ip - IPv4_address 192.168.0.100 # virtual IP 1 - IPv4_address 192.168.1.100 # virtual IP 2 -} - -# -# Do not replicate certain protocol traffic -# -IgnoreProtocol { - UDP - ICMP - IGMP - VRRP - # numeric numbers also valid -} diff --git a/examples/sync/nack/node1/keepalived.conf b/examples/sync/nack/node1/keepalived.conf deleted file mode 100644 index f937467..0000000 --- a/examples/sync/nack/node1/keepalived.conf +++ /dev/null @@ -1,39 +0,0 @@ -vrrp_sync_group G1 { # must be before vrrp_instance declaration - group { - VI_1 - VI_2 - } - notify_master /etc/conntrackd/script_master.sh - notify_backup /etc/conntrackd/script_backup.sh -# notify_fault /etc/conntrackd/script_fault.sh -} - -vrrp_instance VI_1 { - interface eth1 - state SLAVE - virtual_router_id 61 - priority 80 - advert_int 3 - authentication { - auth_type PASS - auth_pass papas_con_tomate - } - virtual_ipaddress { - 192.168.0.100 # default CIDR mask is /32 - } -} - -vrrp_instance VI_2 { - interface eth0 - state SLAVE - virtual_router_id 62 - priority 80 - advert_int 3 - authentication { - auth_type PASS - auth_pass papas_con_tomate - } - virtual_ipaddress { - 192.168.1.100 - } -} diff --git a/examples/sync/nack/node2/conntrackd.conf b/examples/sync/nack/node2/conntrackd.conf deleted file mode 100644 index 43ebd77..0000000 --- a/examples/sync/nack/node2/conntrackd.conf +++ /dev/null @@ -1,134 +0,0 @@ -# -# Synchronizer settings -# -Sync { - Mode NACK { - # - # Size of the buffer that hold destroy messages for - # possible resends (in bytes) - # - ResendBufferSize 262144 - - # Entries committed to the connection tracking table - # starts with a limited timeout of N seconds until the - # takeover process is completed. - # - CommitTimeout 180 - - # Set Acknowledgement window size - ACKWindowSize 20 - } - - # - # Multicast IP and interface where messages are - # broadcasted (dedicated link). IMPORTANT: Make sure - # that iptables accepts traffic for destination - # 225.0.0.50, eg: - # - # iptables -I INPUT -d 225.0.0.50 -j ACCEPT - # iptables -I OUTPUT -d 225.0.0.50 -j ACCEPT - # - Multicast { - IPv4_address 225.0.0.50 - IPv4_interface 192.168.100.200 # IP of dedicated link - Interface eth2 - Group 3780 - } - - # Enable/Disable message checksumming - Checksum on - - # Uncomment this if you want to replicate just certain TCP states. - # This option introduces a tradeoff in the replication: it reduces - # CPU consumption and lost messages rate at the cost of having - # backup replicas that don't contain the current state that the active - # replica holds. TCP states are: SYN_SENT, SYN_RECV, ESTABLISHED, - # FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE, LISTEN. - # - # Replicate ESTABLISHED TIME_WAIT for TCP - - # If you have a multiprimary setup (active-active) without connection - # persistency, ie. you can't know which firewall handles a packet - # that is part of a connection, then you need direct commit of - # conntrack entries to the kernel conntrack table. OSPF setups must - # set on this option. Default is Off. - # - # CacheWriteThrough On -} - -# -# General settings -# -General { - # - # Number of buckets in the caches: hash table - # - HashSize 8192 - - # - # Maximum number of conntracks: - # it must be >= $ cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max - # - HashLimit 65535 - - # - # Logfile: on, off, or a filename - # Default: on (/var/log/conntrackd.log) - # - #LogFile off - - # - # Syslog: on, off or a facility name (daemon (default) or local0..7) - # Default: off - # - #Syslog on - - # - # Lockfile - # - LockFile /var/lock/conntrack.lock - - # - # Unix socket configuration - # - UNIX { - Path /tmp/sync.sock - Backlog 20 - } - - # - # Netlink socket buffer size - # - SocketBufferSize 262142 - - # - # Increase the socket buffer up to maximum if required - # - SocketBufferSizeMaxGrown 655355 -} - -# -# Ignore traffic for a certain set of IP's: Usually -# all the IP assigned to the firewall since local -# traffic must be ignored, just forwarded connections -# are worth to replicate -# -IgnoreTrafficFor { - IPv4_address 127.0.0.1 # loopback - IPv4_address 192.168.0.2 - IPv4_address 192.168.1.2 - IPv4_address 192.168.100.200 # dedicated link ip - IPv4_address 192.168.0.200 # virtual IP 1 - IPv4_address 192.168.1.200 # virtual IP 2 -} - -# -# Do not replicate certain protocol traffic -# -IgnoreProtocol { - UDP - ICMP - IGMP - VRRP - # numeric numbers also valid -} diff --git a/examples/sync/nack/node2/keepalived.conf b/examples/sync/nack/node2/keepalived.conf deleted file mode 100644 index f937467..0000000 --- a/examples/sync/nack/node2/keepalived.conf +++ /dev/null @@ -1,39 +0,0 @@ -vrrp_sync_group G1 { # must be before vrrp_instance declaration - group { - VI_1 - VI_2 - } - notify_master /etc/conntrackd/script_master.sh - notify_backup /etc/conntrackd/script_backup.sh -# notify_fault /etc/conntrackd/script_fault.sh -} - -vrrp_instance VI_1 { - interface eth1 - state SLAVE - virtual_router_id 61 - priority 80 - advert_int 3 - authentication { - auth_type PASS - auth_pass papas_con_tomate - } - virtual_ipaddress { - 192.168.0.100 # default CIDR mask is /32 - } -} - -vrrp_instance VI_2 { - interface eth0 - state SLAVE - virtual_router_id 62 - priority 80 - advert_int 3 - authentication { - auth_type PASS - auth_pass papas_con_tomate - } - virtual_ipaddress { - 192.168.1.100 - } -} diff --git a/examples/sync/nack/script_backup.sh b/examples/sync/nack/script_backup.sh deleted file mode 100755 index 813e375..0000000 --- a/examples/sync/nack/script_backup.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -/usr/sbin/conntrackd -n # request a resync from other nodes via multicast diff --git a/examples/sync/nack/script_master.sh b/examples/sync/nack/script_master.sh deleted file mode 100755 index ff1dbc0..0000000 --- a/examples/sync/nack/script_master.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh - -/usr/sbin/conntrackd -c # commit the cache -/usr/sbin/conntrackd -f # flush the caches -/usr/sbin/conntrackd -R # resync with kernel conntrack table diff --git a/examples/sync/persistent/README b/examples/sync/persistent/README deleted file mode 100644 index 36b5989..0000000 --- a/examples/sync/persistent/README +++ /dev/null @@ -1 +0,0 @@ -This directory contains the files for the PERSISTENT based protocol diff --git a/examples/sync/persistent/node1/conntrackd.conf b/examples/sync/persistent/node1/conntrackd.conf deleted file mode 100644 index a55608b..0000000 --- a/examples/sync/persistent/node1/conntrackd.conf +++ /dev/null @@ -1,140 +0,0 @@ -# -# Synchronizer settings -# -Sync { - Mode PERSISTENT { - # - # If a conntrack entry is not modified in <= 15 seconds, then - # a message is broadcasted. This mechanism is used to - # resynchronize nodes that just joined the multicast group - # - RefreshTime 15 - - # - # If we don't receive a notification about the state of - # an entry in the external cache after N seconds, then - # remove it. - # - CacheTimeout 180 - - # - # Entries committed to the connection tracking table - # starts with a limited timeout of N seconds until the - # takeover process is completed. - # - CommitTimeout 180 - } - - # - # Multicast IP and interface where messages are - # broadcasted (dedicated link). IMPORTANT: Make sure - # that iptables accepts traffic for destination - # 225.0.0.50, eg: - # - # iptables -I INPUT -d 225.0.0.50 -j ACCEPT - # iptables -I OUTPUT -d 225.0.0.50 -j ACCEPT - # - Multicast { - IPv4_address 225.0.0.50 - IPv4_interface 192.168.100.100 # IP of dedicated link - Interface eth2 - Group 3780 - } - - # Enable/Disable message checksumming - Checksum on - - # Uncomment this if you want to replicate just certain TCP states. - # This option introduces a tradeoff in the replication: it reduces - # CPU consumption and lost messages rate at the cost of having - # backup replicas that don't contain the current state that the active - # replica holds. TCP states are: SYN_SENT, SYN_RECV, ESTABLISHED, - # FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE, LISTEN. - # - # Replicate ESTABLISHED TIME_WAIT for TCP - - # If you have a multiprimary setup (active-active) without connection - # persistency, ie. you can't know which firewall handles a packet - # that is part of a connection, then you need direct commit of - # conntrack entries to the kernel conntrack table. OSPF setups must - # set on this option. Default is Off. - # - # CacheWriteThrough On -} - -# -# General settings -# -General { - # - # Number of buckets in the caches: hash table - # - HashSize 8192 - - # - # Maximum number of conntracks: - # it must be >= $ cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max - # - HashLimit 65535 - - # - # Logfile: on, off, or a filename - # Default: on (/var/log/conntrackd.log) - # - #LogFile off - - # - # Syslog: on, off or a facility name (daemon (default) or local0..7) - # Default: off - # - #Syslog on - - # - # Lockfile - # - LockFile /var/lock/conntrack.lock - - # - # Unix socket configuration - # - UNIX { - Path /tmp/sync.sock - Backlog 20 - } - - # - # Netlink socket buffer size - # - SocketBufferSize 262142 - - # - # Increase the socket buffer up to maximum if required - # - SocketBufferSizeMaxGrown 655355 -} - -# -# Ignore traffic for a certain set of IP's: Usually -# all the IP assigned to the firewall since local -# traffic must be ignored, just forwarded connections -# are worth to replicate -# -IgnoreTrafficFor { - IPv4_address 127.0.0.1 # loopback - IPv4_address 192.168.0.1 - IPv4_address 192.168.1.1 - IPv4_address 192.168.100.100 # dedicated link ip - IPv4_address 192.168.0.100 # virtual IP 1 - IPv4_address 192.168.1.100 # virtual IP 2 -} - -# -# Do not replicate certain protocol traffic -# -IgnoreProtocol { - UDP - ICMP - IGMP - VRRP - # numeric numbers also valid -} diff --git a/examples/sync/persistent/node1/keepalived.conf b/examples/sync/persistent/node1/keepalived.conf deleted file mode 100644 index f937467..0000000 --- a/examples/sync/persistent/node1/keepalived.conf +++ /dev/null @@ -1,39 +0,0 @@ -vrrp_sync_group G1 { # must be before vrrp_instance declaration - group { - VI_1 - VI_2 - } - notify_master /etc/conntrackd/script_master.sh - notify_backup /etc/conntrackd/script_backup.sh -# notify_fault /etc/conntrackd/script_fault.sh -} - -vrrp_instance VI_1 { - interface eth1 - state SLAVE - virtual_router_id 61 - priority 80 - advert_int 3 - authentication { - auth_type PASS - auth_pass papas_con_tomate - } - virtual_ipaddress { - 192.168.0.100 # default CIDR mask is /32 - } -} - -vrrp_instance VI_2 { - interface eth0 - state SLAVE - virtual_router_id 62 - priority 80 - advert_int 3 - authentication { - auth_type PASS - auth_pass papas_con_tomate - } - virtual_ipaddress { - 192.168.1.100 - } -} diff --git a/examples/sync/persistent/node2/conntrackd.conf b/examples/sync/persistent/node2/conntrackd.conf deleted file mode 100644 index 32416d0..0000000 --- a/examples/sync/persistent/node2/conntrackd.conf +++ /dev/null @@ -1,140 +0,0 @@ -# -# Synchronizer settings -# -Sync { - Mode PERSISTENT { - # - # If a conntrack entry is not modified in <= 15 seconds, then - # a message is broadcasted. This mechanism is used to - # resynchronize nodes that just joined the multicast group - # - RefreshTime 15 - - # - # If we don't receive a notification about the state of - # an entry in the external cache after N seconds, then - # remove it. - # - CacheTimeout 180 - - # - # Entries committed to the connection tracking table - # starts with a limited timeout of N seconds until the - # takeover process is completed. - # - CommitTimeout 180 - } - - # - # Multicast IP and interface where messages are - # broadcasted (dedicated link). IMPORTANT: Make sure - # that iptables accepts traffic for destination - # 225.0.0.50, eg: - # - # iptables -I INPUT -d 225.0.0.50 -j ACCEPT - # iptables -I OUTPUT -d 225.0.0.50 -j ACCEPT - # - Multicast { - IPv4_address 225.0.0.50 - IPv4_interface 192.168.100.200 # IP of dedicated link - Interface eth2 - Group 3780 - } - - # Enable/Disable message checksumming - Checksum on - - # Uncomment this if you want to replicate just certain TCP states. - # This option introduces a tradeoff in the replication: it reduces - # CPU consumption and lost messages rate at the cost of having - # backup replicas that don't contain the current state that the active - # replica holds. TCP states are: SYN_SENT, SYN_RECV, ESTABLISHED, - # FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE, LISTEN. - # - # Replicate ESTABLISHED TIME_WAIT for TCP - - # If you have a multiprimary setup (active-active) without connection - # persistency, ie. you can't know which firewall handles a packet - # that is part of a connection, then you need direct commit of - # conntrack entries to the kernel conntrack table. OSPF setups must - # set on this option. Default is Off. - # - # CacheWriteThrough On -} - -# -# General settings -# -General { - # - # Number of buckets in the caches: hash table - # - HashSize 8192 - - # - # Maximum number of conntracks: - # it must be >= $ cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max - # - HashLimit 65535 - - # - # Logfile: on, off, or a filename - # Default: on (/var/log/conntrackd.log) - # - #LogFile off - - # - # Syslog: on, off or a facility name (daemon (default) or local0..7) - # Default: off - # - #Syslog on - - # - # Lockfile - # - LockFile /var/lock/conntrack.lock - - # - # Unix socket configuration - # - UNIX { - Path /tmp/sync.sock - Backlog 20 - } - - # - # Netlink socket buffer size - # - SocketBufferSize 262142 - - # - # Increase the socket buffer up to maximum if required - # - SocketBufferSizeMaxGrown 655355 -} - -# -# Ignore traffic for a certain set of IP's: Usually -# all the IP assigned to the firewall since local -# traffic must be ignored, just forwarded connections -# are worth to replicate -# -IgnoreTrafficFor { - IPv4_address 127.0.0.1 # loopback - IPv4_address 192.168.0.2 - IPv4_address 192.168.1.2 - IPv4_address 192.168.100.200 # dedicated link ip - IPv4_address 192.168.0.200 # virtual IP 1 - IPv4_address 192.168.1.200 # virtual IP 2 -} - -# -# Do not replicate certain protocol traffic -# -IgnoreProtocol { - UDP - ICMP - IGMP - VRRP - # numeric numbers also valid -} diff --git a/examples/sync/persistent/node2/keepalived.conf b/examples/sync/persistent/node2/keepalived.conf deleted file mode 100644 index f937467..0000000 --- a/examples/sync/persistent/node2/keepalived.conf +++ /dev/null @@ -1,39 +0,0 @@ -vrrp_sync_group G1 { # must be before vrrp_instance declaration - group { - VI_1 - VI_2 - } - notify_master /etc/conntrackd/script_master.sh - notify_backup /etc/conntrackd/script_backup.sh -# notify_fault /etc/conntrackd/script_fault.sh -} - -vrrp_instance VI_1 { - interface eth1 - state SLAVE - virtual_router_id 61 - priority 80 - advert_int 3 - authentication { - auth_type PASS - auth_pass papas_con_tomate - } - virtual_ipaddress { - 192.168.0.100 # default CIDR mask is /32 - } -} - -vrrp_instance VI_2 { - interface eth0 - state SLAVE - virtual_router_id 62 - priority 80 - advert_int 3 - authentication { - auth_type PASS - auth_pass papas_con_tomate - } - virtual_ipaddress { - 192.168.1.100 - } -} diff --git a/examples/sync/persistent/script_backup.sh b/examples/sync/persistent/script_backup.sh deleted file mode 100755 index 8ea2ad8..0000000 --- a/examples/sync/persistent/script_backup.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -/usr/sbin/conntrackd -B diff --git a/examples/sync/persistent/script_master.sh b/examples/sync/persistent/script_master.sh deleted file mode 100755 index 70c26c9..0000000 --- a/examples/sync/persistent/script_master.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -/usr/sbin/conntrackd -c -/usr/sbin/conntrackd -R diff --git a/include/conntrackd.h b/include/conntrackd.h index 2722f00..1bb3879 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -34,11 +34,11 @@ #define DEFAULT_SYSLOG_FACILITY LOG_DAEMON enum { - SYNC_MODE_PERSISTENT_BIT = 0, - SYNC_MODE_PERSISTENT = (1 << SYNC_MODE_PERSISTENT_BIT), + SYNC_MODE_ALARM_BIT = 0, + SYNC_MODE_ALARM = (1 << SYNC_MODE_ALARM_BIT), - SYNC_MODE_NACK_BIT = 1, - SYNC_MODE_NACK = (1 << SYNC_MODE_NACK_BIT), + SYNC_MODE_FTFW_BIT = 1, + SYNC_MODE_FTFW = (1 << SYNC_MODE_FTFW_BIT), DONT_CHECKSUM_BIT = 2, DONT_CHECKSUM = (1 << DONT_CHECKSUM_BIT), @@ -84,7 +84,7 @@ struct ct_conf { unsigned int listen_to_len; unsigned int flags; int family; /* protocol family */ - unsigned int resend_buffer_size;/* NACK protocol */ + unsigned int resend_buffer_size;/* FTFW protocol */ unsigned int window_size; int cache_write_through; }; diff --git a/include/sync.h b/include/sync.h index 6345513..a27fb93 100644 --- a/include/sync.h +++ b/include/sync.h @@ -18,7 +18,7 @@ struct sync_mode { void (*run)(int step); }; -extern struct sync_mode notrack; -extern struct sync_mode nack; +extern struct sync_mode alarm; +extern struct sync_mode ftfw; #endif diff --git a/src/Makefile.am b/src/Makefile.am index 8f5c620..1fac3dc 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -15,7 +15,7 @@ conntrackd_SOURCES = alarm.c main.c run.c hash.c buffer.c \ ignore_pool.c \ cache.c cache_iterators.c \ cache_lifetime.c cache_timer.c cache_wt.c \ - sync-mode.c sync-notrack.c sync-nack.c \ + sync-mode.c sync-alarm.c sync-ftfw.c \ traffic_stats.c stats-mode.c \ network.c \ state_helper.c state_helper_tcp.c \ diff --git a/src/main.c b/src/main.c index 712b572..a3164a6 100644 --- a/src/main.c +++ b/src/main.c @@ -46,7 +46,7 @@ static const char usage_client_commands[] = " -k, kill conntrack daemon\n" " -s, dump statistics\n" " -R, resync with kernel conntrack table\n" - " -n, request resync with other node (only NACK mode)\n" + " -n, request resync with other node (only FT-FW mode)\n" " -x, dump cache in XML format (requires -i or -e)"; static const char usage_options[] = diff --git a/src/read_config_lex.l b/src/read_config_lex.l index 844cae1..55794a8 100644 --- a/src/read_config_lex.l +++ b/src/read_config_lex.l @@ -45,6 +45,8 @@ ip6 {ip6_form1}|{ip6_form2} string [a-zA-Z][a-zA-Z0-9]* persistent [P|p][E|e][R|r][S|s][I|i][S|s][T|t][E|e][N|n][T|T] nack [N|n][A|a][C|c][K|k] +alarm [A|a][L|l][A|a][R|r][M|m] +ftfw [F|f][T|t][F|f][W|w] %% "UNIX" { return T_UNIX; } @@ -107,8 +109,16 @@ nack [N|n][A|a][C|c][K|k] {ip4} { yylval.string = strdup(yytext); return T_IP; } {ip6} { yylval.string = strdup(yytext); return T_IP; } {path} { yylval.string = strdup(yytext); return T_PATH_VAL; } -{persistent} { return T_PERSISTENT; } -{nack} { return T_NACK; } +{alarm} { return T_ALARM; } +{persistent} { printf("WARNING: Now `persistent' mode is called " + "`alarm'. Please, update your " + "your conntrackd.conf file.\n"); + return T_ALARM; } +{ftfw} { return T_FTFW; } +{nack} { printf("WARNING: Now `nack' mode is called " + "`ftfw'. Please, update your " + "your conntrackd.conf file.\n"); + return T_FTFW; } {string} { yylval.string = strdup(yytext); return T_STRING; } {comment} ; diff --git a/src/read_config_yy.y b/src/read_config_yy.y index e5ce195..795aae9 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -45,7 +45,7 @@ struct ct_conf conf; %token T_LOCK T_STRIP_NAT T_BUFFER_SIZE_MAX_GROWN T_EXPIRE T_TIMEOUT %token T_GENERAL T_SYNC T_STATS T_RELAX_TRANSITIONS T_BUFFER_SIZE T_DELAY %token T_SYNC_MODE T_LISTEN_TO T_FAMILY T_RESEND_BUFFER_SIZE -%token T_PERSISTENT T_NACK T_CHECKSUM T_WINDOWSIZE T_ON T_OFF +%token T_ALARM T_FTFW T_CHECKSUM T_WINDOWSIZE T_ON T_OFF %token T_REPLICATE T_FOR T_IFACE %token T_ESTABLISHED T_SYN_SENT T_SYN_RECV T_FIN_WAIT %token T_CLOSE_WAIT T_LAST_ACK T_TIME_WAIT T_CLOSE T_LISTEN @@ -369,14 +369,14 @@ sync_line: refreshtime | cache_writethrough ; -sync_mode_persistent: T_SYNC_MODE T_PERSISTENT '{' sync_mode_persistent_list '}' +sync_mode_persistent: T_SYNC_MODE T_ALARM '{' sync_mode_persistent_list '}' { - conf.flags |= SYNC_MODE_PERSISTENT; + conf.flags |= SYNC_MODE_ALARM; }; -sync_mode_nack: T_SYNC_MODE T_NACK '{' sync_mode_nack_list '}' +sync_mode_nack: T_SYNC_MODE T_FTFW '{' sync_mode_nack_list '}' { - conf.flags |= SYNC_MODE_NACK; + conf.flags |= SYNC_MODE_FTFW; }; sync_mode_persistent_list: diff --git a/src/sync-alarm.c b/src/sync-alarm.c new file mode 100644 index 0000000..a0791ac --- /dev/null +++ b/src/sync-alarm.c @@ -0,0 +1,104 @@ +/* + * (C) 2006-2007 by Pablo Neira Ayuso + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "conntrackd.h" +#include "sync.h" +#include "network.h" +#include "us-conntrack.h" +#include "alarm.h" + +static void refresher(struct alarm_list *a, void *data) +{ + int len; + struct nethdr *net; + struct us_conntrack *u = data; + + debug_ct(u->ct, "persistence update"); + + a->expires = random() % CONFIG(refresh) + 1; + net = BUILD_NETMSG(u->ct, NFCT_Q_UPDATE); + len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); + mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); +} + +static void cache_alarm_add(struct us_conntrack *u, void *data) +{ + struct alarm_list *alarm = data; + + init_alarm(alarm); + set_alarm_expiration(alarm, (random() % conf.refresh) + 1); + set_alarm_data(alarm, u); + set_alarm_function(alarm, refresher); + add_alarm(alarm); +} + +static void cache_alarm_update(struct us_conntrack *u, void *data) +{ + struct alarm_list *alarm = data; + mod_alarm(alarm, (random() % conf.refresh) + 1); +} + +static void cache_alarm_destroy(struct us_conntrack *u, void *data) +{ + struct alarm_list *alarm = data; + del_alarm(alarm); +} + +static struct cache_extra cache_alarm_extra = { + .size = sizeof(struct alarm_list), + .add = cache_alarm_add, + .update = cache_alarm_update, + .destroy = cache_alarm_destroy +}; + +static int alarm_recv(const struct nethdr *net) +{ + unsigned int exp_seq; + + /* + * Ignore error messages: Although this message type is not ever + * generated in alarm mode, we don't want to crash the daemon + * if someone nuts mixes ftfw and alarm. + */ + if (net->flags) + return 1; + + /* + * Multicast sequence tracking: we keep track of multicast messages + * although we don't do any explicit message recovery. So, why do + * we do sequence tracking? Just to let know the sysadmin. + * + * Let t be 1 < t < RefreshTime. To ensure consistency, conntrackd + * retransmit every t seconds a message with the state of a certain + * entry even if such entry did not change. This mechanism also + * provides passive resynchronization, in other words, there is + * no facility to request a full synchronization from new nodes that + * just joined the cluster, instead they just get resynchronized in + * RefreshTime seconds at worst case. + */ + mcast_track_seq(net->seq, &exp_seq); + + return 0; +} + +struct sync_mode alarm = { + .internal_cache_flags = LIFETIME, + .external_cache_flags = TIMER | LIFETIME, + .internal_cache_extra = &cache_alarm_extra, + .recv = alarm_recv, +}; diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c new file mode 100644 index 0000000..2f27fe6 --- /dev/null +++ b/src/sync-ftfw.c @@ -0,0 +1,366 @@ +/* + * (C) 2006-2007 by Pablo Neira Ayuso + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include "conntrackd.h" +#include "sync.h" +#include "linux_list.h" +#include "us-conntrack.h" +#include "buffer.h" +#include "debug.h" +#include "network.h" +#include "alarm.h" +#include +#include + +#if 0 +#define dp printf +#else +#define dp +#endif + +static LIST_HEAD(rs_list); +static LIST_HEAD(tx_list); +static unsigned int tx_list_len; +static struct buffer *rs_queue; +static struct buffer *tx_queue; + +struct cache_ftfw { + struct list_head rs_list; + struct list_head tx_list; + u_int32_t seq; +}; + +static void cache_ftfw_add(struct us_conntrack *u, void *data) +{ + struct cache_ftfw *cn = data; + INIT_LIST_HEAD(&cn->rs_list); + INIT_LIST_HEAD(&cn->tx_list); +} + +static void cache_ftfw_del(struct us_conntrack *u, void *data) +{ + struct cache_ftfw *cn = data; + + if (cn->rs_list.next == &cn->rs_list && + cn->rs_list.prev == &cn->rs_list) + return; + + list_del(&cn->rs_list); +} + +static struct cache_extra cache_ftfw_extra = { + .size = sizeof(struct cache_ftfw), + .add = cache_ftfw_add, + .destroy = cache_ftfw_del +}; + +static int ftfw_init() +{ + tx_queue = buffer_create(CONFIG(resend_buffer_size)); + if (tx_queue == NULL) { + dlog(STATE(log), LOG_ERR, "cannot create tx buffer"); + return -1; + } + + rs_queue = buffer_create(CONFIG(resend_buffer_size)); + if (rs_queue == NULL) { + dlog(STATE(log), LOG_ERR, "cannot create rs buffer"); + return -1; + } + + INIT_LIST_HEAD(&tx_list); + INIT_LIST_HEAD(&rs_list); + + return 0; +} + +static void ftfw_kill() +{ + buffer_destroy(rs_queue); + buffer_destroy(tx_queue); +} + +static void tx_queue_add_ctlmsg(u_int32_t flags, u_int32_t from, u_int32_t to) +{ + struct nethdr_ack ack = { + .flags = flags, + .from = from, + .to = to, + }; + + buffer_add(tx_queue, &ack, NETHDR_ACK_SIZ); +} + +static int do_cache_to_tx(void *data1, void *data2) +{ + struct us_conntrack *u = data2; + struct cache_ftfw *cn = cache_get_extra(STATE_SYNC(internal), u); + + /* add to tx list */ + list_add(&cn->tx_list, &tx_list); + tx_list_len++; + + return 0; +} + +static int ftfw_local(int fd, int type, void *data) +{ + int ret = 1; + + switch(type) { + case REQUEST_DUMP: + dlog(STATE(log), LOG_NOTICE, "request resync"); + tx_queue_add_ctlmsg(NET_F_RESYNC, 0, 0); + break; + case SEND_BULK: + dlog(STATE(log), LOG_NOTICE, "sending bulk update"); + cache_iterate(STATE_SYNC(internal), NULL, do_cache_to_tx); + break; + default: + ret = 0; + break; + } + + return ret; +} + +static int rs_queue_to_tx(void *data1, void *data2) +{ + struct nethdr *net = data1; + struct nethdr_ack *nack = data2; + + if (between(net->seq, nack->from, nack->to)) { + dp("rs_queue_to_tx sq: %u fl:%u len:%u\n", + net->seq, net->flags, net->len); + buffer_add(tx_queue, net, net->len); + } + return 0; +} + +static int rs_queue_empty(void *data1, void *data2) +{ + struct nethdr *net = data1; + struct nethdr_ack *h = data2; + + if (between(net->seq, h->from, h->to)) { + dp("remove from buffer (seq=%u)\n", net->seq); + buffer_del(rs_queue, data1); + } + return 0; +} + +static void rs_list_to_tx(struct cache *c, unsigned int from, unsigned int to) +{ + struct list_head *n; + struct us_conntrack *u; + + list_for_each(n, &rs_list) { + struct cache_ftfw *cn = (struct cache_ftfw *) n; + struct us_conntrack *u; + + u = cache_get_conntrack(STATE_SYNC(internal), cn); + if (between(cn->seq, from, to)) { + dp("resending nack'ed (oldseq=%u)\n", cn->seq); + list_add(&cn->tx_list, &tx_list); + tx_list_len++; + } + } +} + +static void rs_list_empty(struct cache *c, unsigned int from, unsigned int to) +{ + struct list_head *n, *tmp; + + list_for_each_safe(n, tmp, &rs_list) { + struct cache_ftfw *cn = (struct cache_ftfw *) n; + struct us_conntrack *u; + + u = cache_get_conntrack(STATE_SYNC(internal), cn); + if (between(cn->seq, from, to)) { + dp("queue: deleting from queue (seq=%u)\n", cn->seq); + list_del(&cn->rs_list); + INIT_LIST_HEAD(&cn->rs_list); + } + } +} + +static int ftfw_recv(const struct nethdr *net) +{ + static unsigned int window = 0; + unsigned int exp_seq; + + if (window == 0) + window = CONFIG(window_size); + + if (!mcast_track_seq(net->seq, &exp_seq)) { + dp("OOS: sending nack (seq=%u)\n", exp_seq); + tx_queue_add_ctlmsg(NET_F_NACK, exp_seq, net->seq-1); + window = CONFIG(window_size); + } else { + /* received a window, send an acknowledgement */ + if (--window == 0) { + dp("sending ack (seq=%u)\n", net->seq); + tx_queue_add_ctlmsg(NET_F_ACK, + net->seq - CONFIG(window_size), + net->seq); + } + } + + if (IS_NACK(net)) { + struct nethdr_ack *nack = (struct nethdr_ack *) net; + + dp("NACK: from seq=%u to seq=%u\n", nack->from, nack->to); + rs_list_to_tx(STATE_SYNC(internal), nack->from, nack->to); + buffer_iterate(rs_queue, nack, rs_queue_to_tx); + return 1; + } else if (IS_RESYNC(net)) { + dp("RESYNC ALL\n"); + cache_iterate(STATE_SYNC(internal), NULL, do_cache_to_tx); + return 1; + } else if (IS_ACK(net)) { + struct nethdr_ack *h = (struct nethdr_ack *) net; + + dp("ACK: from seq=%u to seq=%u\n", h->from, h->to); + rs_list_empty(STATE_SYNC(internal), h->from, h->to); + buffer_iterate(rs_queue, h, rs_queue_empty); + return 1; + } else if (IS_ALIVE(net)) + return 1; + + return 0; +} + +static void ftfw_send(struct nethdr *net, struct us_conntrack *u) +{ + struct netpld *pld = NETHDR_DATA(net); + struct cache_ftfw *cn; + + HDR_NETWORK2HOST(net); + + switch(ntohs(pld->query)) { + case NFCT_Q_CREATE: + case NFCT_Q_UPDATE: + cn = (struct cache_ftfw *) + cache_get_extra(STATE_SYNC(internal), u); + + if (cn->rs_list.next == &cn->rs_list && + cn->rs_list.prev == &cn->rs_list) + goto insert; + + list_del(&cn->rs_list); + INIT_LIST_HEAD(&cn->rs_list); +insert: + cn->seq = net->seq; + list_add(&cn->rs_list, &rs_list); + break; + case NFCT_Q_DESTROY: + buffer_add(rs_queue, net, net->len); + break; + } +} + +static int tx_queue_xmit(void *data1, void *data2) +{ + struct nethdr *net = data1; + int len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); + + dp("tx_queue sq: %u fl:%u len:%u\n", + ntohl(net->seq), ntohs(net->flags), ntohs(net->len)); + + mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); + HDR_NETWORK2HOST(net); + + if (IS_DATA(net) || IS_ACK(net) || IS_NACK(net)) { + dp("-> back_to_tx_queue sq: %u fl:%u len:%u\n", + net->seq, net->flags, net->len); + buffer_add(rs_queue, net, net->len); + } + buffer_del(tx_queue, net); + + return 0; +} + +static int tx_list_xmit(struct list_head *i, struct us_conntrack *u) +{ + int ret; + struct nethdr *net = BUILD_NETMSG(u->ct, NFCT_Q_UPDATE); + int len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); + + dp("tx_list sq: %u fl:%u len:%u\n", + ntohl(net->seq), ntohs(net->flags), + ntohs(net->len)); + + list_del(i); + INIT_LIST_HEAD(i); + tx_list_len--; + + ret = mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); + if (STATE_SYNC(sync)->send) + STATE_SYNC(sync)->send(net, u); + + return ret; +} + +static struct alarm_list alive_alarm; + +static void do_alive_alarm(struct alarm_list *a, void *data) +{ + del_alarm(a); + tx_queue_add_ctlmsg(NET_F_ALIVE, 0, 0); +} + +static void ftfw_run(int step) +{ + struct list_head *i, *tmp; + + /* send messages in the tx_queue */ + buffer_iterate(tx_queue, NULL, tx_queue_xmit); + + /* send conntracks in the tx_list */ + list_for_each_safe(i, tmp, &tx_list) { + struct cache_ftfw *cn; + struct us_conntrack *u; + + cn = container_of(i, struct cache_ftfw, tx_list); + u = cache_get_conntrack(STATE_SYNC(internal), cn); + tx_list_xmit(i, u); + } + + if (alive_alarm.expires > 0) + mod_alarm(&alive_alarm, 1); + else { + init_alarm(&alive_alarm); + /* XXX: alive message expiration configurable */ + set_alarm_expiration(&alive_alarm, 1); + set_alarm_function(&alive_alarm, do_alive_alarm); + add_alarm(&alive_alarm); + } +} + +struct sync_mode ftfw = { + .internal_cache_flags = LIFETIME, + .external_cache_flags = LIFETIME, + .internal_cache_extra = &cache_ftfw_extra, + .init = ftfw_init, + .kill = ftfw_kill, + .local = ftfw_local, + .recv = ftfw_recv, + .send = ftfw_send, + .run = ftfw_run, +}; diff --git a/src/sync-mode.c b/src/sync-mode.c index 8a19ac5..7cd2b84 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -126,11 +126,11 @@ static int init_sync(void) } memset(state.sync, 0, sizeof(struct ct_sync_state)); - if (CONFIG(flags) & SYNC_MODE_NACK) - STATE_SYNC(sync) = &nack; + if (CONFIG(flags) & SYNC_MODE_FTFW) + STATE_SYNC(sync) = &ftfw; else - /* default to persistent mode */ - STATE_SYNC(sync) = ¬rack; + /* default to ftfw mode */ + STATE_SYNC(sync) = &ftfw; if (STATE_SYNC(sync)->init) STATE_SYNC(sync)->init(); diff --git a/src/sync-nack.c b/src/sync-nack.c deleted file mode 100644 index fa61be4..0000000 --- a/src/sync-nack.c +++ /dev/null @@ -1,366 +0,0 @@ -/* - * (C) 2006-2007 by Pablo Neira Ayuso - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include "conntrackd.h" -#include "sync.h" -#include "linux_list.h" -#include "us-conntrack.h" -#include "buffer.h" -#include "debug.h" -#include "network.h" -#include "alarm.h" -#include -#include - -#if 0 -#define dp printf -#else -#define dp -#endif - -static LIST_HEAD(rs_list); -static LIST_HEAD(tx_list); -static unsigned int tx_list_len; -static struct buffer *rs_queue; -static struct buffer *tx_queue; - -struct cache_nack { - struct list_head rs_list; - struct list_head tx_list; - u_int32_t seq; -}; - -static void cache_nack_add(struct us_conntrack *u, void *data) -{ - struct cache_nack *cn = data; - INIT_LIST_HEAD(&cn->rs_list); - INIT_LIST_HEAD(&cn->tx_list); -} - -static void cache_nack_del(struct us_conntrack *u, void *data) -{ - struct cache_nack *cn = data; - - if (cn->rs_list.next == &cn->rs_list && - cn->rs_list.prev == &cn->rs_list) - return; - - list_del(&cn->rs_list); -} - -static struct cache_extra cache_nack_extra = { - .size = sizeof(struct cache_nack), - .add = cache_nack_add, - .destroy = cache_nack_del -}; - -static int nack_init() -{ - tx_queue = buffer_create(CONFIG(resend_buffer_size)); - if (tx_queue == NULL) { - dlog(STATE(log), LOG_ERR, "cannot create tx buffer"); - return -1; - } - - rs_queue = buffer_create(CONFIG(resend_buffer_size)); - if (rs_queue == NULL) { - dlog(STATE(log), LOG_ERR, "cannot create rs buffer"); - return -1; - } - - INIT_LIST_HEAD(&tx_list); - INIT_LIST_HEAD(&rs_list); - - return 0; -} - -static void nack_kill() -{ - buffer_destroy(rs_queue); - buffer_destroy(tx_queue); -} - -static void tx_queue_add_ctlmsg(u_int32_t flags, u_int32_t from, u_int32_t to) -{ - struct nethdr_ack ack = { - .flags = flags, - .from = from, - .to = to, - }; - - buffer_add(tx_queue, &ack, NETHDR_ACK_SIZ); -} - -static int do_cache_to_tx(void *data1, void *data2) -{ - struct us_conntrack *u = data2; - struct cache_nack *cn = cache_get_extra(STATE_SYNC(internal), u); - - /* add to tx list */ - list_add(&cn->tx_list, &tx_list); - tx_list_len++; - - return 0; -} - -static int nack_local(int fd, int type, void *data) -{ - int ret = 1; - - switch(type) { - case REQUEST_DUMP: - dlog(STATE(log), LOG_NOTICE, "request resync"); - tx_queue_add_ctlmsg(NET_F_RESYNC, 0, 0); - break; - case SEND_BULK: - dlog(STATE(log), LOG_NOTICE, "sending bulk update"); - cache_iterate(STATE_SYNC(internal), NULL, do_cache_to_tx); - break; - default: - ret = 0; - break; - } - - return ret; -} - -static int rs_queue_to_tx(void *data1, void *data2) -{ - struct nethdr *net = data1; - struct nethdr_ack *nack = data2; - - if (between(net->seq, nack->from, nack->to)) { - dp("rs_queue_to_tx sq: %u fl:%u len:%u\n", - net->seq, net->flags, net->len); - buffer_add(tx_queue, net, net->len); - } - return 0; -} - -static int rs_queue_empty(void *data1, void *data2) -{ - struct nethdr *net = data1; - struct nethdr_ack *h = data2; - - if (between(net->seq, h->from, h->to)) { - dp("remove from buffer (seq=%u)\n", net->seq); - buffer_del(rs_queue, data1); - } - return 0; -} - -static void rs_list_to_tx(struct cache *c, unsigned int from, unsigned int to) -{ - struct list_head *n; - struct us_conntrack *u; - - list_for_each(n, &rs_list) { - struct cache_nack *cn = (struct cache_nack *) n; - struct us_conntrack *u; - - u = cache_get_conntrack(STATE_SYNC(internal), cn); - if (between(cn->seq, from, to)) { - dp("resending nack'ed (oldseq=%u)\n", cn->seq); - list_add(&cn->tx_list, &tx_list); - tx_list_len++; - } - } -} - -static void rs_list_empty(struct cache *c, unsigned int from, unsigned int to) -{ - struct list_head *n, *tmp; - - list_for_each_safe(n, tmp, &rs_list) { - struct cache_nack *cn = (struct cache_nack *) n; - struct us_conntrack *u; - - u = cache_get_conntrack(STATE_SYNC(internal), cn); - if (between(cn->seq, from, to)) { - dp("queue: deleting from queue (seq=%u)\n", cn->seq); - list_del(&cn->rs_list); - INIT_LIST_HEAD(&cn->rs_list); - } - } -} - -static int nack_recv(const struct nethdr *net) -{ - static unsigned int window = 0; - unsigned int exp_seq; - - if (window == 0) - window = CONFIG(window_size); - - if (!mcast_track_seq(net->seq, &exp_seq)) { - dp("OOS: sending nack (seq=%u)\n", exp_seq); - tx_queue_add_ctlmsg(NET_F_NACK, exp_seq, net->seq-1); - window = CONFIG(window_size); - } else { - /* received a window, send an acknowledgement */ - if (--window == 0) { - dp("sending ack (seq=%u)\n", net->seq); - tx_queue_add_ctlmsg(NET_F_ACK, - net->seq - CONFIG(window_size), - net->seq); - } - } - - if (IS_NACK(net)) { - struct nethdr_ack *nack = (struct nethdr_ack *) net; - - dp("NACK: from seq=%u to seq=%u\n", nack->from, nack->to); - rs_list_to_tx(STATE_SYNC(internal), nack->from, nack->to); - buffer_iterate(rs_queue, nack, rs_queue_to_tx); - return 1; - } else if (IS_RESYNC(net)) { - dp("RESYNC ALL\n"); - cache_iterate(STATE_SYNC(internal), NULL, do_cache_to_tx); - return 1; - } else if (IS_ACK(net)) { - struct nethdr_ack *h = (struct nethdr_ack *) net; - - dp("ACK: from seq=%u to seq=%u\n", h->from, h->to); - rs_list_empty(STATE_SYNC(internal), h->from, h->to); - buffer_iterate(rs_queue, h, rs_queue_empty); - return 1; - } else if (IS_ALIVE(net)) - return 1; - - return 0; -} - -static void nack_send(struct nethdr *net, struct us_conntrack *u) -{ - struct netpld *pld = NETHDR_DATA(net); - struct cache_nack *cn; - - HDR_NETWORK2HOST(net); - - switch(ntohs(pld->query)) { - case NFCT_Q_CREATE: - case NFCT_Q_UPDATE: - cn = (struct cache_nack *) - cache_get_extra(STATE_SYNC(internal), u); - - if (cn->rs_list.next == &cn->rs_list && - cn->rs_list.prev == &cn->rs_list) - goto insert; - - list_del(&cn->rs_list); - INIT_LIST_HEAD(&cn->rs_list); -insert: - cn->seq = net->seq; - list_add(&cn->rs_list, &rs_list); - break; - case NFCT_Q_DESTROY: - buffer_add(rs_queue, net, net->len); - break; - } -} - -static int tx_queue_xmit(void *data1, void *data2) -{ - struct nethdr *net = data1; - int len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); - - dp("tx_queue sq: %u fl:%u len:%u\n", - ntohl(net->seq), ntohs(net->flags), ntohs(net->len)); - - mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); - HDR_NETWORK2HOST(net); - - if (IS_DATA(net) || IS_ACK(net) || IS_NACK(net)) { - dp("-> back_to_tx_queue sq: %u fl:%u len:%u\n", - net->seq, net->flags, net->len); - buffer_add(rs_queue, net, net->len); - } - buffer_del(tx_queue, net); - - return 0; -} - -static int tx_list_xmit(struct list_head *i, struct us_conntrack *u) -{ - int ret; - struct nethdr *net = BUILD_NETMSG(u->ct, NFCT_Q_UPDATE); - int len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); - - dp("tx_list sq: %u fl:%u len:%u\n", - ntohl(net->seq), ntohs(net->flags), - ntohs(net->len)); - - list_del(i); - INIT_LIST_HEAD(i); - tx_list_len--; - - ret = mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); - if (STATE_SYNC(sync)->send) - STATE_SYNC(sync)->send(net, u); - - return ret; -} - -static struct alarm_list alive_alarm; - -static void do_alive_alarm(struct alarm_list *a, void *data) -{ - del_alarm(a); - tx_queue_add_ctlmsg(NET_F_ALIVE, 0, 0); -} - -static void nack_run(int step) -{ - struct list_head *i, *tmp; - - /* send messages in the tx_queue */ - buffer_iterate(tx_queue, NULL, tx_queue_xmit); - - /* send conntracks in the tx_list */ - list_for_each_safe(i, tmp, &tx_list) { - struct cache_nack *cn; - struct us_conntrack *u; - - cn = container_of(i, struct cache_nack, tx_list); - u = cache_get_conntrack(STATE_SYNC(internal), cn); - tx_list_xmit(i, u); - } - - if (alive_alarm.expires > 0) - mod_alarm(&alive_alarm, 1); - else { - init_alarm(&alive_alarm); - /* XXX: alive message expiration configurable */ - set_alarm_expiration(&alive_alarm, 1); - set_alarm_function(&alive_alarm, do_alive_alarm); - add_alarm(&alive_alarm); - } -} - -struct sync_mode nack = { - .internal_cache_flags = LIFETIME, - .external_cache_flags = LIFETIME, - .internal_cache_extra = &cache_nack_extra, - .init = nack_init, - .kill = nack_kill, - .local = nack_local, - .recv = nack_recv, - .send = nack_send, - .run = nack_run, -}; diff --git a/src/sync-notrack.c b/src/sync-notrack.c deleted file mode 100644 index 8588ecf..0000000 --- a/src/sync-notrack.c +++ /dev/null @@ -1,104 +0,0 @@ -/* - * (C) 2006-2007 by Pablo Neira Ayuso - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "conntrackd.h" -#include "sync.h" -#include "network.h" -#include "us-conntrack.h" -#include "alarm.h" - -static void refresher(struct alarm_list *a, void *data) -{ - int len; - struct nethdr *net; - struct us_conntrack *u = data; - - debug_ct(u->ct, "persistence update"); - - a->expires = random() % CONFIG(refresh) + 1; - net = BUILD_NETMSG(u->ct, NFCT_Q_UPDATE); - len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); - mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); -} - -static void cache_notrack_add(struct us_conntrack *u, void *data) -{ - struct alarm_list *alarm = data; - - init_alarm(alarm); - set_alarm_expiration(alarm, (random() % conf.refresh) + 1); - set_alarm_data(alarm, u); - set_alarm_function(alarm, refresher); - add_alarm(alarm); -} - -static void cache_notrack_update(struct us_conntrack *u, void *data) -{ - struct alarm_list *alarm = data; - mod_alarm(alarm, (random() % conf.refresh) + 1); -} - -static void cache_notrack_destroy(struct us_conntrack *u, void *data) -{ - struct alarm_list *alarm = data; - del_alarm(alarm); -} - -static struct cache_extra cache_notrack_extra = { - .size = sizeof(struct alarm_list), - .add = cache_notrack_add, - .update = cache_notrack_update, - .destroy = cache_notrack_destroy -}; - -static int notrack_recv(const struct nethdr *net) -{ - unsigned int exp_seq; - - /* - * Ignore error messages: Although this message type is not ever - * generated in notrack mode, we don't want to crash the daemon - * if someone nuts mixes nack and notrack. - */ - if (net->flags) - return 1; - - /* - * Multicast sequence tracking: we keep track of multicast messages - * although we don't do any explicit message recovery. So, why do - * we do sequence tracking? Just to let know the sysadmin. - * - * Let t be 1 < t < RefreshTime. To ensure consistency, conntrackd - * retransmit every t seconds a message with the state of a certain - * entry even if such entry did not change. This mechanism also - * provides passive resynchronization, in other words, there is - * no facility to request a full synchronization from new nodes that - * just joined the cluster, instead they just get resynchronized in - * RefreshTime seconds at worst case. - */ - mcast_track_seq(net->seq, &exp_seq); - - return 0; -} - -struct sync_mode notrack = { - .internal_cache_flags = LIFETIME, - .external_cache_flags = TIMER | LIFETIME, - .internal_cache_extra = &cache_notrack_extra, - .recv = notrack_recv, -}; -- cgit v1.2.3 From f152340a26912d090b5fd15be10208605929816b Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 25 May 2008 20:36:54 +0200 Subject: add best effort replication protocol (aka NOTRACK) --- ChangeLog | 1 + doc/sync/notrack/README | 2 + doc/sync/notrack/node1/conntrackd.conf | 150 +++++++++++++++++++++++++++ doc/sync/notrack/node1/keepalived.conf | 39 +++++++ doc/sync/notrack/node2/conntrackd.conf | 149 ++++++++++++++++++++++++++ doc/sync/notrack/node2/keepalived.conf | 39 +++++++ doc/sync/notrack/script_backup.sh | 3 + doc/sync/notrack/script_master.sh | 5 + include/conntrackd.h | 1 + src/Makefile.am | 2 +- src/read_config_lex.l | 2 + src/read_config_yy.y | 15 ++- src/sync-mode.c | 2 + src/sync-notrack.c | 184 +++++++++++++++++++++++++++++++++ 14 files changed, 592 insertions(+), 2 deletions(-) create mode 100644 doc/sync/notrack/README create mode 100644 doc/sync/notrack/node1/conntrackd.conf create mode 100644 doc/sync/notrack/node1/keepalived.conf create mode 100644 doc/sync/notrack/node2/conntrackd.conf create mode 100644 doc/sync/notrack/node2/keepalived.conf create mode 100644 doc/sync/notrack/script_backup.sh create mode 100644 doc/sync/notrack/script_master.sh create mode 100644 src/sync-notrack.c (limited to 'src/sync-notrack.c') diff --git a/ChangeLog b/ChangeLog index dec7537..597206a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -35,6 +35,7 @@ o improve network message sanity checkings o add Mcast[Snd|Rcv]SocketBuffer clauses to tune multicast socket buffers o add missing string.h required by strdup in config parsing o add eventfd emulation to communicate receiver -> sender +o add best effort replication protocol (aka NOTRACK) version 0.9.6 (2008/03/08) ------------------------------ diff --git a/doc/sync/notrack/README b/doc/sync/notrack/README new file mode 100644 index 0000000..99b2f33 --- /dev/null +++ b/doc/sync/notrack/README @@ -0,0 +1,2 @@ +This directory contains the files for the NOTRACK replication protocol. This +protocol provides best effort delivery. Therefore, it is unreliable. diff --git a/doc/sync/notrack/node1/conntrackd.conf b/doc/sync/notrack/node1/conntrackd.conf new file mode 100644 index 0000000..1185351 --- /dev/null +++ b/doc/sync/notrack/node1/conntrackd.conf @@ -0,0 +1,150 @@ +# +# Synchronizer settings +# +Sync { + Mode NOTRACK { + # + # Entries committed to the connection tracking table + # starts with a limited timeout of N seconds until the + # takeover process is completed. + # + CommitTimeout 180 + } + + # + # Multicast IP and interface where messages are + # broadcasted (dedicated link). IMPORTANT: Make sure + # that iptables accepts traffic for destination + # 225.0.0.50, eg: + # + # iptables -I INPUT -d 225.0.0.50 -j ACCEPT + # iptables -I OUTPUT -d 225.0.0.50 -j ACCEPT + # + Multicast { + IPv4_address 225.0.0.50 + IPv4_interface 192.168.100.100 # IP of dedicated link + Interface eth2 + Group 3780 + + # The multicast sender uses a buffer to enqueue the packets + # that are going to be transmitted. The default size of this + # socket buffer is available at /proc/sys/net/core/wmem_default. + # This value determines the chances to have an overrun in the + # sender queue. The overrun results packet loss, thus, losing + # state information that would have to be retransmitted. If you + # notice some packet loss, you may want to increase the size + # of the sender buffer. Note: This protocol is best effort, + # really recommended to increase the buffer size. + + McastSndSocketBuffer 1249280 + + # The multicast receiver uses a buffer to enqueue the packets + # that the socket is pending to handle. The default size of this + # socket buffer is available at /proc/sys/net/core/rmem_default. + # This value determines the chances to have an overrun in the + # receiver queue. The overrun results packet loss, thus, losing + # state information that would have to be retransmitted. If you + # notice some packet loss, you may want to increase the size of + # the receiver buffer. Note: This protocol is best effort, + # really recommended to increase the buffer size. + + McastRcvSocketBuffer 1249280 + } + + # Enable/Disable message checksumming + Checksum on + + # Uncomment this if you want to replicate just certain TCP states. + # This option introduces a tradeoff in the replication: it reduces + # CPU consumption and lost messages rate at the cost of having + # backup replicas that don't contain the current state that the active + # replica holds. TCP states are: SYN_SENT, SYN_RECV, ESTABLISHED, + # FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE, LISTEN. + # + # Replicate ESTABLISHED TIME_WAIT for TCP + + # If you have a multiprimary setup (active-active) without connection + # persistency, ie. you can't know which firewall handles a packet + # that is part of a connection, then you need direct commit of + # conntrack entries to the kernel conntrack table. OSPF setups must + # set on this option. Default is Off. + # + # CacheWriteThrough On +} + +# +# General settings +# +General { + # + # Number of buckets in the caches: hash table + # + HashSize 8192 + + # + # Maximum number of conntracks: + # it must be >= $ cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max + # + HashLimit 65535 + + # + # Logfile: on, off, or a filename + # Default: on (/var/log/conntrackd.log) + # + #LogFile off + + # + # Syslog: on, off or a facility name (daemon (default) or local0..7) + # Default: off + # + #Syslog on + + # + # Lockfile + # + LockFile /var/lock/conntrack.lock + + # + # Unix socket configuration + # + UNIX { + Path /tmp/sync.sock + Backlog 20 + } + + # + # Netlink socket buffer size + # + SocketBufferSize 262142 + + # + # Increase the socket buffer up to maximum if required + # + SocketBufferSizeMaxGrown 655355 +} + +# +# Ignore traffic for a certain set of IP's: Usually +# all the IP assigned to the firewall since local +# traffic must be ignored, just forwarded connections +# are worth to replicate +# +IgnoreTrafficFor { + IPv4_address 127.0.0.1 # loopback + IPv4_address 192.168.0.1 + IPv4_address 192.168.1.1 + IPv4_address 192.168.100.100 # dedicated link ip + IPv4_address 192.168.0.100 # virtual IP 1 + IPv4_address 192.168.1.100 # virtual IP 2 +} + +# +# Do not replicate certain protocol traffic +# +IgnoreProtocol { + UDP + ICMP + IGMP + VRRP + # numeric numbers also valid +} diff --git a/doc/sync/notrack/node1/keepalived.conf b/doc/sync/notrack/node1/keepalived.conf new file mode 100644 index 0000000..f937467 --- /dev/null +++ b/doc/sync/notrack/node1/keepalived.conf @@ -0,0 +1,39 @@ +vrrp_sync_group G1 { # must be before vrrp_instance declaration + group { + VI_1 + VI_2 + } + notify_master /etc/conntrackd/script_master.sh + notify_backup /etc/conntrackd/script_backup.sh +# notify_fault /etc/conntrackd/script_fault.sh +} + +vrrp_instance VI_1 { + interface eth1 + state SLAVE + virtual_router_id 61 + priority 80 + advert_int 3 + authentication { + auth_type PASS + auth_pass papas_con_tomate + } + virtual_ipaddress { + 192.168.0.100 # default CIDR mask is /32 + } +} + +vrrp_instance VI_2 { + interface eth0 + state SLAVE + virtual_router_id 62 + priority 80 + advert_int 3 + authentication { + auth_type PASS + auth_pass papas_con_tomate + } + virtual_ipaddress { + 192.168.1.100 + } +} diff --git a/doc/sync/notrack/node2/conntrackd.conf b/doc/sync/notrack/node2/conntrackd.conf new file mode 100644 index 0000000..7881d46 --- /dev/null +++ b/doc/sync/notrack/node2/conntrackd.conf @@ -0,0 +1,149 @@ +# +# Synchronizer settings +# +Sync { + Mode NOTRACK { + # Entries committed to the connection tracking table + # starts with a limited timeout of N seconds until the + # takeover process is completed. + # + CommitTimeout 180 + } + + # + # Multicast IP and interface where messages are + # broadcasted (dedicated link). IMPORTANT: Make sure + # that iptables accepts traffic for destination + # 225.0.0.50, eg: + # + # iptables -I INPUT -d 225.0.0.50 -j ACCEPT + # iptables -I OUTPUT -d 225.0.0.50 -j ACCEPT + # + Multicast { + IPv4_address 225.0.0.50 + IPv4_interface 192.168.100.200 # IP of dedicated link + Interface eth2 + Group 3780 + + # The multicast sender uses a buffer to enqueue the packets + # that are going to be transmitted. The default size of this + # socket buffer is available at /proc/sys/net/core/wmem_default. + # This value determines the chances to have an overrun in the + # sender queue. The overrun results packet loss, thus, losing + # state information that would have to be retransmitted. If you + # notice some packet loss, you may want to increase the size + # of the sender buffer. Note: This protocol is best effort, + # really recommended to increase the buffer size. + + McastSndSocketBuffer 1249280 + + # The multicast receiver uses a buffer to enqueue the packets + # that the socket is pending to handle. The default size of this + # socket buffer is available at /proc/sys/net/core/rmem_default. + # This value determines the chances to have an overrun in the + # receiver queue. The overrun results packet loss, thus, losing + # state information that would have to be retransmitted. If you + # notice some packet loss, you may want to increase the size of + # the receiver buffer. Note: This protocol is best effort, + # really recommended to increase the buffer size. + + McastRcvSocketBuffer 1249280 + } + + # Enable/Disable message checksumming + Checksum on + + # Uncomment this if you want to replicate just certain TCP states. + # This option introduces a tradeoff in the replication: it reduces + # CPU consumption and lost messages rate at the cost of having + # backup replicas that don't contain the current state that the active + # replica holds. TCP states are: SYN_SENT, SYN_RECV, ESTABLISHED, + # FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE, LISTEN. + # + # Replicate ESTABLISHED TIME_WAIT for TCP + + # If you have a multiprimary setup (active-active) without connection + # persistency, ie. you can't know which firewall handles a packet + # that is part of a connection, then you need direct commit of + # conntrack entries to the kernel conntrack table. OSPF setups must + # set on this option. Default is Off. + # + # CacheWriteThrough On +} + +# +# General settings +# +General { + # + # Number of buckets in the caches: hash table + # + HashSize 8192 + + # + # Maximum number of conntracks: + # it must be >= $ cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max + # + HashLimit 65535 + + # + # Logfile: on, off, or a filename + # Default: on (/var/log/conntrackd.log) + # + #LogFile off + + # + # Syslog: on, off or a facility name (daemon (default) or local0..7) + # Default: off + # + #Syslog on + + # + # Lockfile + # + LockFile /var/lock/conntrack.lock + + # + # Unix socket configuration + # + UNIX { + Path /tmp/sync.sock + Backlog 20 + } + + # + # Netlink socket buffer size + # + SocketBufferSize 262142 + + # + # Increase the socket buffer up to maximum if required + # + SocketBufferSizeMaxGrown 655355 +} + +# +# Ignore traffic for a certain set of IP's: Usually +# all the IP assigned to the firewall since local +# traffic must be ignored, just forwarded connections +# are worth to replicate +# +IgnoreTrafficFor { + IPv4_address 127.0.0.1 # loopback + IPv4_address 192.168.0.2 + IPv4_address 192.168.1.2 + IPv4_address 192.168.100.200 # dedicated link ip + IPv4_address 192.168.0.200 # virtual IP 1 + IPv4_address 192.168.1.200 # virtual IP 2 +} + +# +# Do not replicate certain protocol traffic +# +IgnoreProtocol { + UDP + ICMP + IGMP + VRRP + # numeric numbers also valid +} diff --git a/doc/sync/notrack/node2/keepalived.conf b/doc/sync/notrack/node2/keepalived.conf new file mode 100644 index 0000000..f937467 --- /dev/null +++ b/doc/sync/notrack/node2/keepalived.conf @@ -0,0 +1,39 @@ +vrrp_sync_group G1 { # must be before vrrp_instance declaration + group { + VI_1 + VI_2 + } + notify_master /etc/conntrackd/script_master.sh + notify_backup /etc/conntrackd/script_backup.sh +# notify_fault /etc/conntrackd/script_fault.sh +} + +vrrp_instance VI_1 { + interface eth1 + state SLAVE + virtual_router_id 61 + priority 80 + advert_int 3 + authentication { + auth_type PASS + auth_pass papas_con_tomate + } + virtual_ipaddress { + 192.168.0.100 # default CIDR mask is /32 + } +} + +vrrp_instance VI_2 { + interface eth0 + state SLAVE + virtual_router_id 62 + priority 80 + advert_int 3 + authentication { + auth_type PASS + auth_pass papas_con_tomate + } + virtual_ipaddress { + 192.168.1.100 + } +} diff --git a/doc/sync/notrack/script_backup.sh b/doc/sync/notrack/script_backup.sh new file mode 100644 index 0000000..813e375 --- /dev/null +++ b/doc/sync/notrack/script_backup.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +/usr/sbin/conntrackd -n # request a resync from other nodes via multicast diff --git a/doc/sync/notrack/script_master.sh b/doc/sync/notrack/script_master.sh new file mode 100644 index 0000000..ff1dbc0 --- /dev/null +++ b/doc/sync/notrack/script_master.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +/usr/sbin/conntrackd -c # commit the cache +/usr/sbin/conntrackd -f # flush the caches +/usr/sbin/conntrackd -R # resync with kernel conntrack table diff --git a/include/conntrackd.h b/include/conntrackd.h index c7a65be..8a6e8d2 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -51,6 +51,7 @@ enum { #define CTD_STATS_MODE (1UL << 1) #define CTD_SYNC_FTFW (1UL << 2) #define CTD_SYNC_ALARM (1UL << 3) +#define CTD_SYNC_NOTRACK (1UL << 4) /* FILENAME_MAX is 4096 on my system, perhaps too much? */ #ifndef FILENAME_MAXLEN diff --git a/src/Makefile.am b/src/Makefile.am index 554074f..69ddcfd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -15,7 +15,7 @@ conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c rbtree.c \ ignore_pool.c fds.c event.c \ cache.c cache_iterators.c \ cache_lifetime.c cache_timer.c cache_wt.c \ - sync-mode.c sync-alarm.c sync-ftfw.c \ + sync-mode.c sync-alarm.c sync-ftfw.c sync-notrack.c \ traffic_stats.c stats-mode.c \ network.c \ state_helper.c state_helper_tcp.c \ diff --git a/src/read_config_lex.l b/src/read_config_lex.l index 7daaeab..bdde3b6 100644 --- a/src/read_config_lex.l +++ b/src/read_config_lex.l @@ -49,6 +49,7 @@ persistent [P|p][E|e][R|r][S|s][I|i][S|s][T|t][E|e][N|n][T|T] nack [N|n][A|a][C|c][K|k] alarm [A|a][L|l][A|a][R|r][M|m] ftfw [F|f][T|t][F|f][W|w] +notrack [N|n][O|o][T|t][R|r][A|a][C|c][K|k] %% "UNIX" { return T_UNIX; } @@ -125,6 +126,7 @@ ftfw [F|f][T|t][F|f][W|w] "is called `ftfw'. Please, update " "your conntrackd.conf file.\n"); return T_FTFW; } +{notrack} { return T_NOTRACK; } {string} { yylval.string = strdup(yytext); return T_STRING; } {comment} ; diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 7fb3d5b..b9c53be 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -53,7 +53,7 @@ struct ct_conf conf; %token T_ESTABLISHED T_SYN_SENT T_SYN_RECV T_FIN_WAIT %token T_CLOSE_WAIT T_LAST_ACK T_TIME_WAIT T_CLOSE T_LISTEN %token T_SYSLOG T_WRITE_THROUGH T_STAT_BUFFER_SIZE T_DESTROY_TIMEOUT -%token T_MCAST_RCVBUFF T_MCAST_SNDBUFF +%token T_MCAST_RCVBUFF T_MCAST_SNDBUFF T_NOTRACK %token T_IP T_PATH_VAL %token T_NUMBER @@ -436,6 +436,7 @@ sync_line: refreshtime | delay_destroy_msgs | sync_mode_alarm | sync_mode_ftfw + | sync_mode_notrack | listen_to | state_replication | cache_writethrough @@ -452,6 +453,11 @@ sync_mode_ftfw: T_SYNC_MODE T_FTFW '{' sync_mode_ftfw_list '}' conf.flags |= CTD_SYNC_FTFW; }; +sync_mode_notrack: T_SYNC_MODE T_NOTRACK '{' sync_mode_notrack_list '}' +{ + conf.flags |= CTD_SYNC_NOTRACK; +}; + sync_mode_alarm_list: | sync_mode_alarm_list sync_mode_alarm_line; @@ -470,6 +476,13 @@ sync_mode_ftfw_line: resend_queue_size | window_size ; +sync_mode_notrack_list: + | sync_mode_notrack_list sync_mode_notrack_line; + +sync_mode_notrack_line: timeout + ; + + resend_queue_size: T_RESEND_BUFFER_SIZE T_NUMBER { conf.resend_queue_size = $2; diff --git a/src/sync-mode.c b/src/sync-mode.c index 2fe7406..16cc70d 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -169,6 +169,8 @@ static int init_sync(void) STATE_SYNC(sync) = &sync_ftfw; else if (CONFIG(flags) & CTD_SYNC_ALARM) STATE_SYNC(sync) = &sync_alarm; + else if (CONFIG(flags) & CTD_SYNC_NOTRACK) + STATE_SYNC(sync) = &sync_notrack; else { fprintf(stderr, "WARNING: No synchronization mode specified. " "Defaulting to FT-FW mode.\n"); diff --git a/src/sync-notrack.c b/src/sync-notrack.c new file mode 100644 index 0000000..2b1bc13 --- /dev/null +++ b/src/sync-notrack.c @@ -0,0 +1,184 @@ +/* + * (C) 2008 by Pablo Neira Ayuso + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "conntrackd.h" +#include "sync.h" +#include "us-conntrack.h" +#include "queue.h" +#include "debug.h" +#include "network.h" +#include "log.h" +#include "cache.h" +#include "event.h" + +#include + +static LIST_HEAD(tx_list); +static unsigned int tx_list_len; +static struct queue *tx_queue; + +struct cache_notrack { + struct list_head tx_list; +}; + +static struct cache_extra cache_notrack_extra = { + .size = sizeof(struct cache_notrack), +}; + +static void tx_queue_add_ctlmsg(uint32_t flags, uint32_t from, uint32_t to) +{ + struct nethdr_ack ack = { + .flags = flags, + .from = from, + .to = to, + }; + + queue_add(tx_queue, &ack, NETHDR_ACK_SIZ); + write_evfd(STATE_SYNC(evfd)); +} + +static int notrack_init(void) +{ + tx_queue = queue_create(~0U); + if (tx_queue == NULL) { + dlog(LOG_ERR, "cannot create tx queue"); + return -1; + } + + return 0; +} + +static void notrack_kill(void) +{ + queue_destroy(tx_queue); +} + +static int do_cache_to_tx(void *data1, void *data2) +{ + struct us_conntrack *u = data2; + struct cache_notrack *cn = cache_get_extra(STATE_SYNC(internal), u); + + /* add to tx list */ + list_add_tail(&cn->tx_list, &tx_list); + tx_list_len++; + + write_evfd(STATE_SYNC(evfd)); + + return 0; +} + +static int notrack_local(int fd, int type, void *data) +{ + int ret = 1; + + switch(type) { + case REQUEST_DUMP: + dlog(LOG_NOTICE, "request resync"); + tx_queue_add_ctlmsg(NET_F_RESYNC, 0, 0); + break; + case SEND_BULK: + dlog(LOG_NOTICE, "sending bulk update"); + cache_iterate(STATE_SYNC(internal), NULL, do_cache_to_tx); + break; + default: + ret = 0; + break; + } + + return ret; +} + +static int digest_msg(const struct nethdr *net) +{ + if (IS_DATA(net)) + return MSG_DATA; + + if (IS_RESYNC(net)) { + cache_iterate(STATE_SYNC(internal), NULL, do_cache_to_tx); + return MSG_CTL; + } + + return MSG_BAD; +} + +static int notrack_recv(const struct nethdr *net) +{ + int ret; + unsigned int exp_seq; + + mcast_track_seq(net->seq, &exp_seq); + + ret = digest_msg(net); + + if (ret != MSG_BAD) + mcast_track_update_seq(net->seq); + + return ret; +} + +static int tx_queue_xmit(void *data1, const void *data2) +{ + struct nethdr *net = data1; + size_t len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); + + mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); + queue_del(tx_queue, net); + + return 0; +} + +static int tx_list_xmit(struct list_head *i, struct us_conntrack *u, int type) +{ + int ret; + struct nethdr *net = BUILD_NETMSG(u->ct, type); + size_t len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); + + list_del_init(i); + tx_list_len--; + + ret = mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); + + return ret; +} + +static void notrack_run(void) +{ + struct cache_notrack *cn, *tmp; + + /* send messages in the tx_queue */ + queue_iterate(tx_queue, NULL, tx_queue_xmit); + + /* send conntracks in the tx_list */ + list_for_each_entry_safe(cn, tmp, &tx_list, tx_list) { + struct us_conntrack *u; + + u = cache_get_conntrack(STATE_SYNC(internal), cn); + tx_list_xmit(&cn->tx_list, u, NFCT_Q_UPDATE); + } +} + +struct sync_mode sync_notrack = { + .internal_cache_flags = LIFETIME, + .external_cache_flags = LIFETIME, + .internal_cache_extra = &cache_notrack_extra, + .init = notrack_init, + .kill = notrack_kill, + .local = notrack_local, + .recv = notrack_recv, + .run = notrack_run, +}; -- cgit v1.2.3 From 5000afe7e1a3ae4a14995e051d3ee716d8a6c784 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 20 Oct 2008 14:17:13 +0200 Subject: notrack: fix double receival of resync requests This patch fixes double insertion in the tx_list if we receive two (or more) consecutive resync request in short time. Signed-off-by: Pablo Neira Ayuso --- src/sync-notrack.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'src/sync-notrack.c') diff --git a/src/sync-notrack.c b/src/sync-notrack.c index 2b1bc13..c7ac9b5 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -36,8 +36,26 @@ struct cache_notrack { struct list_head tx_list; }; +static void cache_notrack_add(struct us_conntrack *u, void *data) +{ + struct cache_notrack *cn = data; + INIT_LIST_HEAD(&cn->tx_list); +} + +static void cache_notrack_del(struct us_conntrack *u, void *data) +{ + struct cache_notrack *cn = data; + + if (!list_empty(&cn->tx_list)) { + list_del(&cn->tx_list); + tx_list_len--; + } +} + static struct cache_extra cache_notrack_extra = { .size = sizeof(struct cache_notrack), + .add = cache_notrack_add, + .destroy = cache_notrack_del }; static void tx_queue_add_ctlmsg(uint32_t flags, uint32_t from, uint32_t to) @@ -73,6 +91,9 @@ static int do_cache_to_tx(void *data1, void *data2) struct us_conntrack *u = data2; struct cache_notrack *cn = cache_get_extra(STATE_SYNC(internal), u); + if (!list_empty(&cn->tx_list)) + return 0; + /* add to tx list */ list_add_tail(&cn->tx_list, &tx_list); tx_list_len++; -- cgit v1.2.3 From bf6cfeb1dc6652eaff1b7c4edda45e15f5abf361 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 8 Dec 2008 11:09:02 +0100 Subject: network: remove length parameter of mcast_buffered_send_netmsg() This patch simplifies mcast_buffered_send_netmsg() by removing the length parameter. Instead, we use the length field in the nethdr to know the message size to be sent. Signed-off-by: Pablo Neira Ayuso --- include/network.h | 2 +- src/network.c | 5 ++--- src/sync-alarm.c | 2 +- src/sync-ftfw.c | 4 ++-- src/sync-mode.c | 2 +- src/sync-notrack.c | 4 ++-- 6 files changed, 9 insertions(+), 10 deletions(-) (limited to 'src/sync-notrack.c') diff --git a/include/network.h b/include/network.h index b64753c..1195303 100644 --- a/include/network.h +++ b/include/network.h @@ -76,7 +76,7 @@ struct mcast_conf; int mcast_buffered_init(int mtu); void mcast_buffered_destroy(void); -int mcast_buffered_send_netmsg(struct mcast_sock *m, void *data, size_t len); +int mcast_buffered_send_netmsg(struct mcast_sock *m, const struct nethdr *net); ssize_t mcast_buffered_pending_netmsg(struct mcast_sock *m); #define IS_DATA(x) ((x->flags & ~(NET_F_HELLO | NET_F_HELLO_BACK)) == 0) diff --git a/src/network.c b/src/network.c index 2f83d3b..a6ecb7e 100644 --- a/src/network.c +++ b/src/network.c @@ -108,10 +108,9 @@ void mcast_buffered_destroy(void) } /* return 0 if it is not sent, otherwise return 1 */ -int mcast_buffered_send_netmsg(struct mcast_sock *m, void *data, size_t len) +int mcast_buffered_send_netmsg(struct mcast_sock *m, const struct nethdr *net) { - int ret = 0; - struct nethdr *net = data; + int ret = 0, len = ntohs(net->len); retry: if (tx_buflen + len < tx_buflenmax) { diff --git a/src/sync-alarm.c b/src/sync-alarm.c index 4473af2..377af16 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -41,7 +41,7 @@ static void refresher(struct alarm_block *a, void *data) net = BUILD_NETMSG(u->ct, NFCT_Q_UPDATE); len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); - mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); + mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); } static void cache_alarm_add(struct us_conntrack *u, void *data) diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index abba1fe..293f9ab 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -495,7 +495,7 @@ static int tx_queue_xmit(void *data1, const void *data2) dp("tx_queue sq: %u fl:%u len:%u\n", ntohl(net->seq), net->flags, ntohs(net->len)); - mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); + mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); HDR_NETWORK2HOST(net); if (IS_DATA(net) || IS_ACK(net) || IS_NACK(net)) @@ -518,7 +518,7 @@ static int tx_list_xmit(struct list_head *i, struct us_conntrack *u, int type) list_del_init(i); tx_list_len--; - ret = mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); + ret = mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); ftfw_send(net, u); return ret; diff --git a/src/sync-mode.c b/src/sync-mode.c index 98867b2..ac9d3f3 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -406,7 +406,7 @@ static void mcast_send_sync(struct us_conntrack *u, int query) if (STATE_SYNC(sync)->send) STATE_SYNC(sync)->send(net, u); - mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); + mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); } static int purge_step(void *data1, void *data2) diff --git a/src/sync-notrack.c b/src/sync-notrack.c index c7ac9b5..c5ea1e6 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -157,7 +157,7 @@ static int tx_queue_xmit(void *data1, const void *data2) struct nethdr *net = data1; size_t len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); - mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); + mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); queue_del(tx_queue, net); return 0; @@ -172,7 +172,7 @@ static int tx_list_xmit(struct list_head *i, struct us_conntrack *u, int type) list_del_init(i); tx_list_len--; - ret = mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); + ret = mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); return ret; } -- cgit v1.2.3 From a516e5f8e550a6073aae96491372c45ce340da88 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 8 Dec 2008 11:10:47 +0100 Subject: network: remove the netpld header from the messages This patch simplifies the message format of the replication messages. As a result, we save four bytes. The netpld header was introduced in the early protocol design. Today, it does not have any reason to exist. Signed-off-by: Pablo Neira Ayuso --- include/network.h | 47 +++++++++++++++++------------------ src/build.c | 72 ++++++++++++++++++++++++++---------------------------- src/network.c | 55 +++++++++++++++-------------------------- src/parse.c | 23 +++-------------- src/sync-alarm.c | 2 -- src/sync-ftfw.c | 8 +++--- src/sync-mode.c | 11 +++------ src/sync-notrack.c | 5 ++-- 8 files changed, 90 insertions(+), 133 deletions(-) (limited to 'src/sync-notrack.c') diff --git a/include/network.h b/include/network.h index 1195303..11e65c7 100644 --- a/include/network.h +++ b/include/network.h @@ -9,25 +9,34 @@ struct nf_conntrack; struct nethdr { - uint8_t version; + uint8_t version:4, + type:4; uint8_t flags; uint16_t len; uint32_t seq; }; -#define NETHDR_SIZ sizeof(struct nethdr) +#define NETHDR_SIZ nethdr_align(sizeof(struct nethdr)) + +int nethdr_align(int len); +int nethdr_size(int len); +void nethdr_set(struct nethdr *net, int type); +void nethdr_set_ack(struct nethdr *net); #define NETHDR_DATA(x) \ - (struct netpld *)(((char *)x) + sizeof(struct nethdr)) + (struct netattr *)(((char *)x) + NETHDR_SIZ) +#define NETHDR_TAIL(x) \ + (struct netattr *)(((char *)x) + x->len) struct nethdr_ack { - uint8_t version; + uint8_t version:4, + type:4; uint8_t flags; uint16_t len; uint32_t seq; uint32_t from; uint32_t to; }; -#define NETHDR_ACK_SIZ sizeof(struct nethdr_ack) +#define NETHDR_ACK_SIZ nethdr_align(sizeof(struct nethdr_ack)) enum { NET_F_UNUSED = (1 << 0), @@ -49,17 +58,17 @@ enum { #define BUILD_NETMSG(ct, query) \ ({ \ char __net[4096]; \ - memset(__net, 0, NETHDR_SIZ + NETPLD_SIZ); \ - build_netmsg(ct, query, (struct nethdr *) __net); \ - (struct nethdr *) __net; \ + struct nethdr *__hdr = (struct nethdr *) __net; \ + memset(__hdr, 0, NETHDR_SIZ); \ + nethdr_set(__hdr, query); \ + build_payload(ct, __hdr); \ + HDR_HOST2NETWORK(__hdr); \ + __hdr; \ }) struct us_conntrack; struct mcast_sock; -void build_netmsg(struct nf_conntrack *ct, int query, struct nethdr *net); -size_t prepare_send_netmsg(struct mcast_sock *m, void *data); - enum { SEQ_UNKNOWN, SEQ_UNSET, @@ -129,12 +138,6 @@ static inline int between(uint32_t seq1, uint32_t seq2, uint32_t seq3) return seq3 - seq2 >= seq1 - seq2; } -struct netpld { - uint16_t len; - uint16_t query; -}; -#define NETPLD_SIZ sizeof(struct netpld) - #define PLD_NETWORK2HOST(x) \ ({ \ x->len = ntohs(x->len); \ @@ -158,12 +161,6 @@ struct netattr { x->nta_attr = ntohs(x->nta_attr); \ }) -#define PLD_DATA(x) \ - (struct netattr *)(((char *)x) + sizeof(struct netpld)) - -#define PLD_TAIL(x) \ - (struct netattr *)(((char *)x) + sizeof(struct netpld) + x->len) - #define NTA_DATA(x) \ (void *)(((char *)x) + sizeof(struct netattr)) @@ -207,8 +204,8 @@ struct nta_attr_natseqadj { uint32_t repl_seq_offset_after; }; -void build_netpld(struct nf_conntrack *ct, struct netpld *pld, int query); +void build_payload(const struct nf_conntrack *ct, struct nethdr *n); -int parse_netpld(struct nf_conntrack *ct, struct nethdr *net, int *query, size_t remain); +int parse_payload(struct nf_conntrack *ct, struct nethdr *n, size_t remain); #endif diff --git a/src/build.c b/src/build.c index 84515cf..e094aa0 100644 --- a/src/build.c +++ b/src/build.c @@ -21,12 +21,12 @@ #include "network.h" static inline void * -put_header(struct netpld *pld, int attr, size_t len) +put_header(struct nethdr *n, int attr, size_t len) { - struct netattr *nta = PLD_TAIL(pld); + struct netattr *nta = NETHDR_TAIL(n); int total_size = NTA_ALIGN(NTA_LENGTH(len)); int attr_size = NTA_LENGTH(len); - pld->len += total_size; + n->len += total_size; nta->nta_attr = htons(attr); nta->nta_len = htons(attr_size); memset((unsigned char *)nta + attr_size, 0, total_size - attr_size); @@ -34,45 +34,45 @@ put_header(struct netpld *pld, int attr, size_t len) } static inline void -addattr(struct netpld *pld, int attr, const void *data, size_t len) +addattr(struct nethdr *n, int attr, const void *data, size_t len) { - void *ptr = put_header(pld, attr, len); + void *ptr = put_header(n, attr, len); memcpy(ptr, data, len); } static inline void -__build_u8(const struct nf_conntrack *ct, int a, struct netpld *pld, int b) +__build_u8(const struct nf_conntrack *ct, int a, struct nethdr *n, int b) { - void *ptr = put_header(pld, b, sizeof(uint8_t)); + void *ptr = put_header(n, b, sizeof(uint8_t)); memcpy(ptr, nfct_get_attr(ct, a), sizeof(uint8_t)); } static inline void -__build_u16(const struct nf_conntrack *ct, int a, struct netpld *pld, int b) +__build_u16(const struct nf_conntrack *ct, int a, struct nethdr *n, int b) { uint32_t data = nfct_get_attr_u16(ct, a); data = htons(data); - addattr(pld, b, &data, sizeof(uint16_t)); + addattr(n, b, &data, sizeof(uint16_t)); } static inline void -__build_u32(const struct nf_conntrack *ct, int a, struct netpld *pld, int b) +__build_u32(const struct nf_conntrack *ct, int a, struct nethdr *n, int b) { uint32_t data = nfct_get_attr_u32(ct, a); data = htonl(data); - addattr(pld, b, &data, sizeof(uint32_t)); + addattr(n, b, &data, sizeof(uint32_t)); } static inline void -__build_group(const struct nf_conntrack *ct, int a, struct netpld *pld, +__build_group(const struct nf_conntrack *ct, int a, struct nethdr *n, int b, int size) { - void *ptr = put_header(pld, b, size); + void *ptr = put_header(n, b, size); nfct_get_attr_grp(ct, a, ptr); } static inline void -__build_natseqadj(const struct nf_conntrack *ct, struct netpld *pld) +__build_natseqadj(const struct nf_conntrack *ct, struct nethdr *n) { struct nta_attr_natseqadj data = { .orig_seq_correction_pos = @@ -88,7 +88,7 @@ __build_natseqadj(const struct nf_conntrack *ct, struct netpld *pld) .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)); + addattr(n, NTA_NAT_SEQ_ADJ, &data, sizeof(struct nta_attr_natseqadj)); } static enum nf_conntrack_attr nat_type[] = @@ -97,65 +97,61 @@ static enum nf_conntrack_attr nat_type[] = 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) +void build_payload(const struct nf_conntrack *ct, struct nethdr *n) { if (nfct_attr_grp_is_set(ct, ATTR_GRP_ORIG_IPV4)) { - __build_group(ct, ATTR_GRP_ORIG_IPV4, pld, NTA_IPV4, + __build_group(ct, ATTR_GRP_ORIG_IPV4, n, 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, + __build_group(ct, ATTR_GRP_ORIG_IPV6, n, NTA_IPV6, sizeof(struct nfct_attr_grp_ipv6)); } - __build_u8(ct, ATTR_L4PROTO, pld, NTA_L4PROTO); + __build_u8(ct, ATTR_L4PROTO, n, NTA_L4PROTO); if (nfct_attr_grp_is_set(ct, ATTR_GRP_ORIG_PORT)) { - __build_group(ct, ATTR_GRP_ORIG_PORT, pld, NTA_PORT, + __build_group(ct, ATTR_GRP_ORIG_PORT, n, NTA_PORT, sizeof(struct nfct_attr_grp_port)); } - __build_u32(ct, ATTR_STATUS, pld, NTA_STATUS); + __build_u32(ct, ATTR_STATUS, n, NTA_STATUS); if (nfct_attr_is_set(ct, ATTR_TCP_STATE)) - __build_u8(ct, ATTR_TCP_STATE, pld, NTA_STATE); + __build_u8(ct, ATTR_TCP_STATE, n, NTA_STATE); if (nfct_attr_is_set(ct, ATTR_MARK)) - __build_u32(ct, ATTR_MARK, pld, NTA_MARK); + __build_u32(ct, ATTR_MARK, n, NTA_MARK); /* setup the master conntrack */ if (nfct_attr_grp_is_set(ct, ATTR_GRP_MASTER_IPV4)) { - __build_group(ct, ATTR_GRP_MASTER_IPV4, pld, NTA_MASTER_IPV4, + __build_group(ct, ATTR_GRP_MASTER_IPV4, n, NTA_MASTER_IPV4, sizeof(struct nfct_attr_grp_ipv4)); - __build_u8(ct, ATTR_MASTER_L4PROTO, pld, NTA_MASTER_L4PROTO); + __build_u8(ct, ATTR_MASTER_L4PROTO, n, 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, + n, 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, + __build_group(ct, ATTR_GRP_MASTER_IPV6, n, NTA_MASTER_IPV6, sizeof(struct nfct_attr_grp_ipv6)); - __build_u8(ct, ATTR_MASTER_L4PROTO, pld, NTA_MASTER_L4PROTO); + __build_u8(ct, ATTR_MASTER_L4PROTO, n, 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, + n, NTA_MASTER_PORT, sizeof(struct nfct_attr_grp_port)); } } /* NAT */ if (nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) - __build_u32(ct, ATTR_REPL_IPV4_DST, pld, NTA_SNAT_IPV4); + __build_u32(ct, ATTR_REPL_IPV4_DST, n, NTA_SNAT_IPV4); if (nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) - __build_u32(ct, ATTR_REPL_IPV4_SRC, pld, NTA_DNAT_IPV4); + __build_u32(ct, ATTR_REPL_IPV4_SRC, n, NTA_DNAT_IPV4); if (nfct_getobjopt(ct, NFCT_GOPT_IS_SPAT)) - __build_u16(ct, ATTR_REPL_PORT_DST, pld, NTA_SPAT_PORT); + __build_u16(ct, ATTR_REPL_PORT_DST, n, NTA_SPAT_PORT); if (nfct_getobjopt(ct, NFCT_GOPT_IS_DPAT)) - __build_u16(ct, ATTR_REPL_PORT_SRC, pld, NTA_DPAT_PORT); + __build_u16(ct, ATTR_REPL_PORT_SRC, n, NTA_DPAT_PORT); /* NAT sequence adjustment */ if (nfct_attr_is_set_array(ct, nat_type, 6)) - __build_natseqadj(ct, pld); - - pld->query = query; - - PLD_HOST2NETWORK(pld); + __build_natseqadj(ct, n); } diff --git a/src/network.c b/src/network.c index ca00881..34992ec 100644 --- a/src/network.c +++ b/src/network.c @@ -25,48 +25,40 @@ #include #include +#define NETHDR_ALIGNTO 4 + static unsigned int seq_set, cur_seq; -static size_t __do_prepare(struct mcast_sock *m, void *data, size_t len) +int nethdr_align(int value) { - struct nethdr *net = data; + return (value + NETHDR_ALIGNTO - 1) & ~(NETHDR_ALIGNTO - 1); +} +int nethdr_size(int len) +{ + return NETHDR_SIZ + len; +} + +static inline void __nethdr_set(struct nethdr *net, int len, int type) +{ if (!seq_set) { seq_set = 1; cur_seq = time(NULL); } - net->version = CONNTRACKD_PROTOCOL_VERSION; - net->len = len; - net->seq = cur_seq++; - HDR_HOST2NETWORK(net); - - return len; + net->version = CONNTRACKD_PROTOCOL_VERSION; + net->type = type; + net->len = len; + net->seq = cur_seq++; } -static size_t __prepare_ctl(struct mcast_sock *m, void *data) +void nethdr_set(struct nethdr *net, int type) { - return __do_prepare(m, data, NETHDR_ACK_SIZ); + __nethdr_set(net, NETHDR_SIZ, type); } -static size_t __prepare_data(struct mcast_sock *m, void *data) +void nethdr_set_ack(struct nethdr *net) { - struct nethdr *net = (struct nethdr *) data; - struct netpld *pld = NETHDR_DATA(net); - - return __do_prepare(m, data, ntohs(pld->len) + NETPLD_SIZ + NETHDR_SIZ); -} - -size_t prepare_send_netmsg(struct mcast_sock *m, void *data) -{ - int ret = 0; - struct nethdr *net = (struct nethdr *) data; - - if (IS_DATA(net)) - ret = __prepare_data(m, data); - else if (IS_CTL(net)) - ret = __prepare_ctl(m, data); - - return ret; + __nethdr_set(net, NETHDR_ACK_SIZ, 0); } static size_t tx_buflenmax; @@ -129,13 +121,6 @@ ssize_t mcast_buffered_pending_netmsg(struct mcast_sock *m) return ret; } -void build_netmsg(struct nf_conntrack *ct, int query, struct nethdr *net) -{ - struct netpld *pld = NETHDR_DATA(net); - - build_netpld(ct, pld, query); -} - static int local_seq_set = 0; /* this function only tracks, it does not update the last sequence received */ diff --git a/src/parse.c b/src/parse.c index 4eb74b2..17a0107 100644 --- a/src/parse.c +++ b/src/parse.c @@ -150,30 +150,16 @@ parse_nat_seq_adj(struct nf_conntrack *ct, int attr, void *data) ntohl(this->orig_seq_correction_pos)); } -int -parse_netpld(struct nf_conntrack *ct, - struct nethdr *net, - int *query, - size_t remain) +int parse_payload(struct nf_conntrack *ct, struct nethdr *net, size_t remain) { int len; struct netattr *attr; - struct netpld *pld; - if (remain < NETHDR_SIZ + sizeof(struct netpld)) + if (remain < net->len) return -1; - pld = NETHDR_DATA(net); - - if (remain < NETHDR_SIZ + sizeof(struct netpld) + ntohs(pld->len)) - return -1; - - if (net->len < NETHDR_SIZ + sizeof(struct netpld) + ntohs(pld->len)) - return -1; - - PLD_NETWORK2HOST(pld); - len = pld->len; - attr = PLD_DATA(pld); + len = net->len - NETHDR_SIZ; + attr = NETHDR_DATA(net); while (len > ssizeof(struct netattr)) { ATTR_NETWORK2HOST(attr); @@ -187,6 +173,5 @@ parse_netpld(struct nf_conntrack *ct, attr = NTA_NEXT(attr, len); } - *query = pld->query; return 0; } diff --git a/src/sync-alarm.c b/src/sync-alarm.c index 377af16..fe3d9af 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -29,7 +29,6 @@ static void refresher(struct alarm_block *a, void *data) { - size_t len; struct nethdr *net; struct us_conntrack *u = data; @@ -40,7 +39,6 @@ static void refresher(struct alarm_block *a, void *data) ((random() % 5 + 1) * 200000) - 1); net = BUILD_NETMSG(u->ct, NFCT_Q_UPDATE); - len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); } diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 293f9ab..a4895d4 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -451,10 +451,9 @@ out: static void ftfw_send(struct nethdr *net, struct us_conntrack *u) { - struct netpld *pld = NETHDR_DATA(net); struct cache_ftfw *cn; - switch(ntohs(pld->query)) { + switch(net->type) { case NFCT_Q_CREATE: case NFCT_Q_UPDATE: case NFCT_Q_DESTROY: @@ -490,7 +489,9 @@ static void ftfw_send(struct nethdr *net, struct us_conntrack *u) static int tx_queue_xmit(void *data1, const void *data2) { struct nethdr *net = data1; - size_t len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); + + nethdr_set_ack(net); + HDR_HOST2NETWORK(net); dp("tx_queue sq: %u fl:%u len:%u\n", ntohl(net->seq), net->flags, ntohs(net->len)); @@ -510,7 +511,6 @@ static int tx_list_xmit(struct list_head *i, struct us_conntrack *u, int type) { int ret; struct nethdr *net = BUILD_NETMSG(u->ct, type); - size_t len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); dp("tx_list sq: %u fl:%u len:%u\n", ntohl(net->seq), net->flags, ntohs(net->len)); diff --git a/src/sync-mode.c b/src/sync-mode.c index ac9d3f3..cfed7f4 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -36,7 +36,6 @@ static void do_mcast_handler_step(struct nethdr *net, size_t remain) { - int query; char __ct[nfct_maxsize()]; struct nf_conntrack *ct = (struct nf_conntrack *)(void*) __ct; struct us_conntrack *u; @@ -62,13 +61,13 @@ static void do_mcast_handler_step(struct nethdr *net, size_t remain) memset(ct, 0, sizeof(__ct)); - if (parse_netpld(ct, net, &query, remain) == -1) { + if (parse_payload(ct, net, remain) == -1) { STATE(malformed)++; dlog(LOG_ERR, "parsing failed: malformed message"); return; } - switch(query) { + switch(net->type) { case NFCT_Q_CREATE: retry: if ((u = cache_add(STATE_SYNC(external), ct))) { @@ -100,7 +99,7 @@ retry: break; default: STATE(malformed)++; - dlog(LOG_ERR, "mcast unknown query %d\n", query); + dlog(LOG_ERR, "mcast unknown query %d\n", net->type); break; } } @@ -109,7 +108,7 @@ retry: static void mcast_handler(void) { ssize_t numbytes; - size_t remain; + ssize_t remain; char __net[65536], *ptr = __net; /* XXX: maximum MTU for IPv4 */ numbytes = mcast_recv(STATE_SYNC(mcast_server), __net, sizeof(__net)); @@ -397,11 +396,9 @@ static void dump_sync(struct nf_conntrack *ct) static void mcast_send_sync(struct us_conntrack *u, int query) { - size_t len; struct nethdr *net; net = BUILD_NETMSG(u->ct, query); - len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); if (STATE_SYNC(sync)->send) STATE_SYNC(sync)->send(net, u); diff --git a/src/sync-notrack.c b/src/sync-notrack.c index c5ea1e6..fdb0c43 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -155,8 +155,8 @@ static int notrack_recv(const struct nethdr *net) static int tx_queue_xmit(void *data1, const void *data2) { struct nethdr *net = data1; - size_t len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); - + nethdr_set_ack(net); + HDR_HOST2NETWORK(net); mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); queue_del(tx_queue, net); @@ -167,7 +167,6 @@ static int tx_list_xmit(struct list_head *i, struct us_conntrack *u, int type) { int ret; struct nethdr *net = BUILD_NETMSG(u->ct, type); - size_t len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); list_del_init(i); tx_list_len--; -- cgit v1.2.3 From 8d6efef0daed05925bf9b13c21948afa651482a5 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 13 Dec 2008 16:15:18 +0100 Subject: network: use NET_T_* instead of NFCT_Q_* This patch replaces the use of NFCT_Q_* in the message type by specific network message type NET_T_*. The query types are reserved for libnetfilter_conntrack operations. Signed-off-by: Pablo Neira Ayuso --- include/network.h | 7 +++++++ src/sync-alarm.c | 2 +- src/sync-ftfw.c | 10 +++++----- src/sync-mode.c | 16 ++++++++-------- src/sync-notrack.c | 2 +- 5 files changed, 22 insertions(+), 15 deletions(-) (limited to 'src/sync-notrack.c') diff --git a/include/network.h b/include/network.h index 9098e5c..b6722bd 100644 --- a/include/network.h +++ b/include/network.h @@ -17,6 +17,13 @@ struct nethdr { }; #define NETHDR_SIZ nethdr_align(sizeof(struct nethdr)) +enum nethdr_type { + NET_T_STATE_NEW = 0, + NET_T_STATE_UPD, + NET_T_STATE_DEL, + NET_T_STATE_MAX = NET_T_STATE_DEL, +}; + int nethdr_align(int len); int nethdr_size(int len); void nethdr_set(struct nethdr *net, int type); diff --git a/src/sync-alarm.c b/src/sync-alarm.c index fe3d9af..d871b75 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -38,7 +38,7 @@ static void refresher(struct alarm_block *a, void *data) random() % CONFIG(refresh) + 1, ((random() % 5 + 1) * 200000) - 1); - net = BUILD_NETMSG(u->ct, NFCT_Q_UPDATE); + net = BUILD_NETMSG(u->ct, NET_T_STATE_UPD); mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); } diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index a4895d4..05475ab 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -454,9 +454,9 @@ static void ftfw_send(struct nethdr *net, struct us_conntrack *u) struct cache_ftfw *cn; switch(net->type) { - case NFCT_Q_CREATE: - case NFCT_Q_UPDATE: - case NFCT_Q_DESTROY: + case NET_T_STATE_NEW: + case NET_T_STATE_UPD: + case NET_T_STATE_DEL: cn = (struct cache_ftfw *) cache_get_extra(STATE_SYNC(internal), u); @@ -537,9 +537,9 @@ static void ftfw_run(void) u = cache_get_conntrack(STATE_SYNC(internal), cn); if (alarm_pending(&u->alarm)) - tx_list_xmit(&cn->tx_list, u, NFCT_Q_DESTROY); + tx_list_xmit(&cn->tx_list, u, NET_T_STATE_DEL); else - tx_list_xmit(&cn->tx_list, u, NFCT_Q_UPDATE); + tx_list_xmit(&cn->tx_list, u, NET_T_STATE_UPD); } /* reset alive alarm */ diff --git a/src/sync-mode.c b/src/sync-mode.c index cfed7f4..d5355a7 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -68,7 +68,7 @@ static void do_mcast_handler_step(struct nethdr *net, size_t remain) } switch(net->type) { - case NFCT_Q_CREATE: + case NET_T_STATE_NEW: retry: if ((u = cache_add(STATE_SYNC(external), ct))) { debug_ct(u->ct, "external new"); @@ -85,13 +85,13 @@ retry: debug_ct(ct, "can't add"); } break; - case NFCT_Q_UPDATE: + case NET_T_STATE_UPD: if ((u = cache_update_force(STATE_SYNC(external), ct))) { debug_ct(u->ct, "external update"); } else debug_ct(ct, "can't update"); break; - case NFCT_Q_DESTROY: + case NET_T_STATE_DEL: if (cache_del(STATE_SYNC(external), ct)) debug_ct(ct, "external destroy"); else @@ -415,7 +415,7 @@ static int purge_step(void *data1, void *data2) ret = nfct_query(h, NFCT_Q_GET, u->ct); if (ret == -1 && errno == ENOENT) { debug_ct(u->ct, "overrun purge resync"); - mcast_send_sync(u, NFCT_Q_DESTROY); + mcast_send_sync(u, NET_T_STATE_DEL); __cache_del_timer(STATE_SYNC(internal), u, CONFIG(del_timeout)); } @@ -448,7 +448,7 @@ static int overrun_sync(enum nf_conntrack_msg_type type, if (!cache_test(STATE_SYNC(internal), ct)) { if ((u = cache_update_force(STATE_SYNC(internal), ct))) { debug_ct(u->ct, "overrun resync"); - mcast_send_sync(u, NFCT_Q_UPDATE); + mcast_send_sync(u, NET_T_STATE_UPD); } } @@ -466,7 +466,7 @@ static void event_new_sync(struct nf_conntrack *ct) nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS); retry: if ((u = cache_add(STATE_SYNC(internal), ct))) { - mcast_send_sync(u, NFCT_Q_CREATE); + mcast_send_sync(u, NET_T_STATE_NEW); debug_ct(u->ct, "internal new"); } else { if (errno == EEXIST) { @@ -489,7 +489,7 @@ static void event_update_sync(struct nf_conntrack *ct) return; } debug_ct(u->ct, "internal update"); - mcast_send_sync(u, NFCT_Q_UPDATE); + mcast_send_sync(u, NET_T_STATE_UPD); } static int event_destroy_sync(struct nf_conntrack *ct) @@ -502,7 +502,7 @@ static int event_destroy_sync(struct nf_conntrack *ct) return 0; } - mcast_send_sync(u, NFCT_Q_DESTROY); + mcast_send_sync(u, NET_T_STATE_DEL); __cache_del_timer(STATE_SYNC(internal), u, CONFIG(del_timeout)); debug_ct(ct, "internal destroy"); return 1; diff --git a/src/sync-notrack.c b/src/sync-notrack.c index fdb0c43..8e6601a 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -188,7 +188,7 @@ static void notrack_run(void) struct us_conntrack *u; u = cache_get_conntrack(STATE_SYNC(internal), cn); - tx_list_xmit(&cn->tx_list, u, NFCT_Q_UPDATE); + tx_list_xmit(&cn->tx_list, u, NET_T_STATE_UPD); } } -- cgit v1.2.3 From 74455dae1d095178b09ea3f1b1e8b005076e7a94 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 13 Dec 2008 17:24:27 +0100 Subject: network: do more strict message type checking This patch adds more strict checking in the message type. We add a new message type NET_T_CTL for control messages. Signed-off-by: Pablo Neira Ayuso --- include/network.h | 12 +++++++----- src/network.c | 2 +- src/sync-ftfw.c | 1 + src/sync-notrack.c | 1 + 4 files changed, 10 insertions(+), 6 deletions(-) (limited to 'src/sync-notrack.c') diff --git a/include/network.h b/include/network.h index b6722bd..f9756db 100644 --- a/include/network.h +++ b/include/network.h @@ -22,6 +22,7 @@ enum nethdr_type { NET_T_STATE_UPD, NET_T_STATE_DEL, NET_T_STATE_MAX = NET_T_STATE_DEL, + NET_T_CTL = 10, }; int nethdr_align(int len); @@ -95,11 +96,12 @@ void mcast_buffered_destroy(void); int mcast_buffered_send_netmsg(struct mcast_sock *m, const struct nethdr *net); ssize_t mcast_buffered_pending_netmsg(struct mcast_sock *m); -#define IS_DATA(x) ((x->flags & ~(NET_F_HELLO | NET_F_HELLO_BACK)) == 0) -#define IS_ACK(x) (x->flags & NET_F_ACK) -#define IS_NACK(x) (x->flags & NET_F_NACK) -#define IS_RESYNC(x) (x->flags & NET_F_RESYNC) -#define IS_ALIVE(x) (x->flags & NET_F_ALIVE) +#define IS_DATA(x) (x->type <= NET_T_STATE_MAX && \ + (x->flags & ~(NET_F_HELLO | NET_F_HELLO_BACK)) == 0) +#define IS_ACK(x) (x->type == NET_T_CTL && x->flags & NET_F_ACK) +#define IS_NACK(x) (x->type == NET_T_CTL && x->flags & NET_F_NACK) +#define IS_RESYNC(x) (x->type == NET_T_CTL && x->flags & NET_F_RESYNC) +#define IS_ALIVE(x) (x->type == NET_T_CTL && x->flags & NET_F_ALIVE) #define IS_CTL(x) IS_ACK(x) || IS_NACK(x) || IS_RESYNC(x) || IS_ALIVE(x) #define IS_HELLO(x) (x->flags & NET_F_HELLO) #define IS_HELLO_BACK(x)(x->flags & NET_F_HELLO_BACK) diff --git a/src/network.c b/src/network.c index 34992ec..98df5ea 100644 --- a/src/network.c +++ b/src/network.c @@ -58,7 +58,7 @@ void nethdr_set(struct nethdr *net, int type) void nethdr_set_ack(struct nethdr *net) { - __nethdr_set(net, NETHDR_ACK_SIZ, 0); + __nethdr_set(net, NETHDR_ACK_SIZ, NET_T_CTL); } static size_t tx_buflenmax; diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 749ccac..014cebd 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -97,6 +97,7 @@ static struct cache_extra cache_ftfw_extra = { static void tx_queue_add_ctlmsg(uint32_t flags, uint32_t from, uint32_t to) { struct nethdr_ack ack = { + .type = NET_T_CTL, .flags = flags, .from = from, .to = to, diff --git a/src/sync-notrack.c b/src/sync-notrack.c index 8e6601a..700e272 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -61,6 +61,7 @@ static struct cache_extra cache_notrack_extra = { static void tx_queue_add_ctlmsg(uint32_t flags, uint32_t from, uint32_t to) { struct nethdr_ack ack = { + .type = NET_T_CTL, .flags = flags, .from = from, .to = to, -- cgit v1.2.3 From 50339f96638eed35dac2b673b64cc6f1eb96406c Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 15 Jan 2009 23:19:57 +0100 Subject: src: rework of the hash-cache infrastructure Currently, the caching system is implemented in a two layer architecture: hashtable (inner layer) and cache (upper layer). This patch reworks the hash-cache infrastructure to solve some initial design problems to make it more flexible, the main strong points of this patch are: * Memory handling is done in the cache layer, not in the inner hashtable layer. This removes one of the main dependencies between the hashtable and the cache classes. * Remove excessive encapsulation: the former cache used to hide a lot of details of the inner hashtable implementation. * Fix over-hashing of some operations: lookup-delete-add required three hash calculations. Similarly, the update-or-add operation required two hash calculations. Now, we calculate the hash once and re-use the value how many times as we need. This patch simplifies the caching system. As a result, we save ~130 lines of code. Small code means and less complexity means less chance to have bugs. Signed-off-by: Pablo Neira Ayuso --- include/Makefile.am | 4 +- include/cache.h | 43 +++++--- include/filter.h | 11 ++ include/hash.h | 22 ++-- include/network.h | 1 - include/slist.h | 41 -------- include/sync.h | 4 +- include/us-conntrack.h | 14 --- src/cache.c | 273 +++++++++++++++++++------------------------------ src/cache_iterators.c | 65 ++++++------ src/cache_lifetime.c | 10 +- src/cache_timer.c | 36 +++---- src/cache_wt.c | 33 +++--- src/filter.c | 57 +++++++++-- src/hash.c | 136 +++++++----------------- src/stats-mode.c | 55 +++++----- src/sync-alarm.c | 27 +++-- src/sync-ftfw.c | 40 ++++---- src/sync-mode.c | 116 +++++++++++---------- src/sync-notrack.c | 19 ++-- 20 files changed, 440 insertions(+), 567 deletions(-) delete mode 100644 include/slist.h delete mode 100644 include/us-conntrack.h (limited to 'src/sync-notrack.c') diff --git a/include/Makefile.am b/include/Makefile.am index 13f7e37..c3f8904 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -1,6 +1,6 @@ -noinst_HEADERS = alarm.h jhash.h slist.h cache.h linux_list.h linux_rbtree.h \ - sync.h conntrackd.h local.h us-conntrack.h \ +noinst_HEADERS = alarm.h jhash.h cache.h linux_list.h linux_rbtree.h \ + sync.h conntrackd.h local.h \ debug.h log.h hash.h mcast.h conntrack.h \ network.h filter.h queue.h vector.h cidr.h \ traffic_stats.h netlink.h fds.h event.h bitops.h diff --git a/include/cache.h b/include/cache.h index ebed70a..dcd6bcd 100644 --- a/include/cache.h +++ b/include/cache.h @@ -3,6 +3,8 @@ #include #include +#include "hash.h" +#include "alarm.h" /* cache features */ enum { @@ -22,14 +24,20 @@ enum { #define CACHE_MAX_FEATURE __CACHE_MAX_FEATURE struct cache; -struct us_conntrack; +struct cache_object { + struct hashtable_node hashnode; + struct nf_conntrack *ct; + struct cache *cache; + struct alarm_block alarm; + char data[0]; +}; struct cache_feature { size_t size; - void (*add)(struct us_conntrack *u, void *data); - void (*update)(struct us_conntrack *u, void *data); - void (*destroy)(struct us_conntrack *u, void *data); - int (*dump)(struct us_conntrack *u, void *data, char *buf, int type); + void (*add)(struct cache_object *obj, void *data); + void (*update)(struct cache_object *obj, void *data); + void (*destroy)(struct cache_object *obj, void *data); + int (*dump)(struct cache_object *obj, void *data, char *buf, int type); }; extern struct cache_feature lifetime_feature; @@ -48,6 +56,7 @@ struct cache { unsigned int *feature_offset; struct cache_extra *extra; unsigned int extra_offset; + size_t object_size; /* statistics */ struct { @@ -77,9 +86,9 @@ struct cache { struct cache_extra { unsigned int size; - void (*add)(struct us_conntrack *u, void *data); - void (*update)(struct us_conntrack *u, void *data); - void (*destroy)(struct us_conntrack *u, void *data); + void (*add)(struct cache_object *obj, void *data); + void (*update)(struct cache_object *obj, void *data); + void (*destroy)(struct cache_object *obj, void *data); }; struct nf_conntrack; @@ -87,16 +96,18 @@ struct nf_conntrack; struct cache *cache_create(const char *name, unsigned int features, struct cache_extra *extra); void cache_destroy(struct cache *e); -struct us_conntrack *cache_add(struct cache *c, struct nf_conntrack *ct); -struct us_conntrack *cache_update(struct cache *c, struct nf_conntrack *ct); -struct us_conntrack *cache_update_force(struct cache *c, struct nf_conntrack *ct); -int cache_del(struct cache *c, struct nf_conntrack *ct); -int __cache_del_timer(struct cache *c, struct us_conntrack *u, int timeout); -struct us_conntrack *cache_find(struct cache *c, struct nf_conntrack *ct); -int cache_test(struct cache *c, struct nf_conntrack *ct); +struct cache_object *cache_object_new(struct cache *c, struct nf_conntrack *ct); +void cache_object_free(struct cache_object *obj); + +int cache_add(struct cache *c, struct cache_object *obj, int id); +void cache_update(struct cache *c, struct cache_object *obj, int id, struct nf_conntrack *ct); +struct cache_object *cache_update_force(struct cache *c, struct nf_conntrack *ct); +void cache_del(struct cache *c, struct cache_object *obj); +int cache_del_timer(struct cache *c, struct cache_object *obj, int timeout); +struct cache_object *cache_find(struct cache *c, struct nf_conntrack *ct, int *pos); void cache_stats(const struct cache *c, int fd); void cache_stats_extended(const struct cache *c, int fd); -struct us_conntrack *cache_get_conntrack(struct cache *, void *); +struct cache_object *cache_data_get_object(struct cache *c, void *data); void *cache_get_extra(struct cache *, void *); void cache_iterate(struct cache *c, void *data, int (*iterate)(void *data1, void *data2)); diff --git a/include/filter.h b/include/filter.h index 9c2cf66..72c2aa4 100644 --- a/include/filter.h +++ b/include/filter.h @@ -4,6 +4,7 @@ #include #include #include +#include enum ct_filter_type { CT_FILTER_L4PROTO, @@ -17,6 +18,16 @@ enum ct_filter_logic { CT_FILTER_POSITIVE = 1, }; +struct ct_filter_ipv4_hnode { + struct hashtable_node node; + uint32_t ip; +}; + +struct ct_filter_ipv6_hnode { + struct hashtable_node node; + uint32_t ipv6[4]; +}; + struct ct_filter_netmask_ipv4 { uint32_t ip; uint32_t mask; diff --git a/include/hash.h b/include/hash.h index 2fb0a27..68d618b 100644 --- a/include/hash.h +++ b/include/hash.h @@ -2,7 +2,6 @@ #define _NF_SET_HASH_H_ #include -#include "slist.h" #include "linux_list.h" #include @@ -15,35 +14,30 @@ struct hashtable { uint32_t limit; uint32_t count; uint32_t initval; - uint32_t datasize; uint32_t (*hash)(const void *data, const struct hashtable *table); int (*compare)(const void *data1, const void *data2); - struct slist_head members[0]; + struct list_head members[0]; }; struct hashtable_node { - struct slist_head head; - char data[0]; + struct list_head head; }; -struct hashtable_node *hashtable_alloc_node(int datasize, void *data); -void hashtable_destroy_node(struct hashtable_node *h); - struct hashtable * -hashtable_create(int hashsize, int limit, int datasize, +hashtable_create(int hashsize, int limit, uint32_t (*hash)(const void *data, const struct hashtable *table), int (*compare)(const void *data1, const void *data2)); void hashtable_destroy(struct hashtable *h); - -void *hashtable_add(struct hashtable *table, void *data); -void *hashtable_find(struct hashtable *table, const void *data); -int hashtable_del(struct hashtable *table, void *data); +int hashtable_hash(const struct hashtable *table, const void *data); +struct hashtable_node *hashtable_find(const struct hashtable *table, const void *data, int id); +int hashtable_add(struct hashtable *table, struct hashtable_node *n, int id); +void hashtable_del(struct hashtable *table, struct hashtable_node *node); int hashtable_flush(struct hashtable *table); int hashtable_iterate(struct hashtable *table, void *data, - int (*iterate)(void *data1, void *data2)); + int (*iterate)(void *data, struct hashtable_node *n)); unsigned int hashtable_counter(const struct hashtable *table); #endif diff --git a/include/network.h b/include/network.h index 40bb2b2..619ce3e 100644 --- a/include/network.h +++ b/include/network.h @@ -75,7 +75,6 @@ enum { __hdr; \ }) -struct us_conntrack; struct mcast_sock; enum { diff --git a/include/slist.h b/include/slist.h deleted file mode 100644 index 257b627..0000000 --- a/include/slist.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef _SLIST_H_ -#define _SLIST_H_ - -#include "linux_list.h" - -#define INIT_SLIST_HEAD(ptr) ((ptr).next = NULL) - -struct slist_head { - struct slist_head *next; -}; - -static inline int slist_empty(const struct slist_head *h) -{ - return !h->next; -} - -static inline void slist_del(struct slist_head *t, struct slist_head *prev) -{ - prev->next = t->next; - t->next = LIST_POISON1; -} - -static inline void slist_add(struct slist_head *head, struct slist_head *t) -{ - struct slist_head *tmp = head->next; - head->next = t; - t->next = tmp; -} - -#define slist_entry(ptr, type, member) container_of(ptr,type,member) - -#define slist_for_each(pos, head) \ - for (pos = (head)->next; pos; \ - pos = pos->next) - -#define slist_for_each_safe(pos, prev, next, head) \ - for (pos = (head)->next, prev = (head); \ - pos && ({ next = pos->next; 1; }); \ - ({ prev = (prev->next != next) ? prev->next : prev; }), pos = next) - -#endif diff --git a/include/sync.h b/include/sync.h index fc06c93..60c9fae 100644 --- a/include/sync.h +++ b/include/sync.h @@ -2,7 +2,7 @@ #define _SYNC_HOOKS_H_ struct nethdr; -struct us_conntrack; +struct cache_object; struct sync_mode { int internal_cache_flags; @@ -14,7 +14,7 @@ struct sync_mode { void (*kill)(void); int (*local)(int fd, int type, void *data); int (*recv)(const struct nethdr *net); - void (*send)(struct nethdr *net, struct us_conntrack *u); + void (*send)(struct nethdr *net, struct cache_object *obj); void (*run)(void); }; diff --git a/include/us-conntrack.h b/include/us-conntrack.h deleted file mode 100644 index 9eafa3b..0000000 --- a/include/us-conntrack.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef _US_CONNTRACK_H_ -#define _US_CONNTRACK_H_ - -#include "alarm.h" -#include - -struct us_conntrack { - struct nf_conntrack *ct; - struct cache *cache; - struct alarm_block alarm; - char data[0]; -}; - -#endif diff --git a/src/cache.c b/src/cache.c index 553dddf..621a3f4 100644 --- a/src/cache.c +++ b/src/cache.c @@ -1,5 +1,5 @@ /* - * (C) 2006-2007 by Pablo Neira Ayuso + * (C) 2006-2009 by Pablo Neira Ayuso * * 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,7 +20,6 @@ #include "jhash.h" #include "hash.h" #include "log.h" -#include "us-conntrack.h" #include "conntrackd.h" #include @@ -68,14 +67,14 @@ __hash6(const struct nf_conntrack *ct, const struct hashtable *table) static uint32_t hash(const void *data, const struct hashtable *table) { int ret = 0; - const struct us_conntrack *u = data; + const struct nf_conntrack *ct = data; - switch(nfct_get_attr_u8(u->ct, ATTR_L3PROTO)) { + switch(nfct_get_attr_u8(ct, ATTR_L3PROTO)) { case AF_INET: - ret = __hash4(u->ct, table); + ret = __hash4(ct, table); break; case AF_INET6: - ret = __hash6(u->ct, table); + ret = __hash6(ct, table); break; default: dlog(LOG_ERR, "unknown layer 3 proto in hash"); @@ -87,10 +86,10 @@ static uint32_t hash(const void *data, const struct hashtable *table) static int compare(const void *data1, const void *data2) { - const struct us_conntrack *u1 = data1; - const struct us_conntrack *u2 = data2; + const struct cache_object *obj = data1; + const struct nf_conntrack *ct = data2; - return nfct_cmp(u1->ct, u2->ct, NFCT_CMP_ORIG); + return nfct_cmp(obj->ct, ct, NFCT_CMP_ORIG); } struct cache_feature *cache_feature[CACHE_MAX_FEATURE] = { @@ -103,7 +102,7 @@ struct cache *cache_create(const char *name, unsigned int features, struct cache_extra *extra) { - size_t size = sizeof(struct us_conntrack); + size_t size = sizeof(struct cache_object); int i, j = 0; struct cache *c; struct cache_feature *feature_array[CACHE_MAX_FEATURE] = {}; @@ -152,7 +151,6 @@ struct cache *cache_create(const char *name, c->h = hashtable_create(CONFIG(hashsize), CONFIG(limit), - size, hash, compare); @@ -162,6 +160,7 @@ struct cache *cache_create(const char *name, free(c); return NULL; } + c->object_size = size; return c; } @@ -177,225 +176,165 @@ void cache_destroy(struct cache *c) static void __del_timeout(struct alarm_block *a, void *data); -static struct us_conntrack *__add(struct cache *c, struct nf_conntrack *ct) +struct cache_object *cache_object_new(struct cache *c, struct nf_conntrack *ct) { - unsigned i; - size_t size = c->h->datasize; - char buf[size]; - struct us_conntrack *u = (struct us_conntrack *) buf; - struct nf_conntrack *newct; + struct cache_object *obj; - memset(u, 0, size); + obj = calloc(c->object_size, 1); + if (obj == NULL) { + errno = ENOMEM; + c->stats.add_fail_enomem++; + return NULL; + } + obj->cache = c; + init_alarm(&obj->alarm, obj, __del_timeout); - u->cache = c; - if ((u->ct = newct = nfct_new()) == NULL) { + if ((obj->ct = nfct_new()) == NULL) { + free(obj); errno = ENOMEM; - return 0; + c->stats.add_fail_enomem++; + return NULL; } - memcpy(u->ct, ct, nfct_sizeof(ct)); + memcpy(obj->ct, ct, nfct_sizeof(ct)); - u = hashtable_add(c->h, u); - if (u) { - char *data = u->data; + return obj; +} - init_alarm(&u->alarm, u, __del_timeout); +void cache_object_free(struct cache_object *obj) +{ + nfct_destroy(obj->ct); + free(obj); +} - for (i = 0; i < c->num_features; i++) { - c->features[i]->add(u, data); - data += c->features[i]->size; - } +static int __add(struct cache *c, struct cache_object *obj, int id) +{ + int ret; + unsigned int i; + char *data = obj->data; - if (c->extra && c->extra->add) - c->extra->add(u, ((char *) u) + c->extra_offset); + ret = hashtable_add(c->h, &obj->hashnode, id); + if (ret == -1) + return -1; - c->stats.active++; - return u; + for (i = 0; i < c->num_features; i++) { + c->features[i]->add(obj, data); + data += c->features[i]->size; } - free(newct); - return NULL; + if (c->extra && c->extra->add) + c->extra->add(obj, ((char *) obj) + c->extra_offset); + + c->stats.active++; + return 0; } -struct us_conntrack *cache_add(struct cache *c, struct nf_conntrack *ct) +int cache_add(struct cache *c, struct cache_object *obj, int id) { - struct us_conntrack *u; + int ret; - u = __add(c, ct); - if (u) { - c->stats.add_ok++; - return u; - } - if (errno != EEXIST) { + ret = __add(c, obj, id); + if (ret == -1) { c->stats.add_fail++; if (errno == ENOSPC) c->stats.add_fail_enospc++; - if (errno == ENOMEM) - c->stats.add_fail_enomem++; + return -1; } - - return NULL; + c->stats.add_ok++; + return 0; } -static void -__cache_update(struct cache *c, struct us_conntrack *u, struct nf_conntrack *ct) +void cache_update(struct cache *c, struct cache_object *obj, int id, + struct nf_conntrack *ct) { - unsigned i; - char *data = u->data; + char *data = obj->data; + unsigned int i; - nfct_copy(u->ct, ct, NFCT_CP_META); + nfct_copy(obj->ct, ct, NFCT_CP_META); for (i = 0; i < c->num_features; i++) { - c->features[i]->update(u, data); + c->features[i]->update(obj, data); data += c->features[i]->size; } if (c->extra && c->extra->update) - c->extra->update(u, ((char *) u) + c->extra_offset); -} - -static struct us_conntrack *__update(struct cache *c, struct nf_conntrack *ct) -{ - size_t size = c->h->datasize; - char buf[size]; - struct us_conntrack *u = (struct us_conntrack *) buf; - - u->ct = ct; - - u = (struct us_conntrack *) hashtable_find(c->h, u); - if (u) { - __cache_update(c, u, ct); - return u; - } - return NULL; -} + c->extra->update(obj, ((char *) obj) + c->extra_offset); -struct us_conntrack *cache_update(struct cache *c, struct nf_conntrack *ct) -{ - struct us_conntrack *u; - - u = __update(c, ct); - if (u) { - c->stats.upd_ok++; - return u; - } - c->stats.upd_fail++; - if (errno == ENOENT) - c->stats.upd_fail_enoent++; - - return NULL; + c->stats.upd_ok++; } -static void __del(struct cache *c, struct us_conntrack *u) +static void __del(struct cache *c, struct cache_object *obj) { unsigned i; - char *data = u->data; - struct nf_conntrack *p = u->ct; + char *data = obj->data; for (i = 0; i < c->num_features; i++) { - c->features[i]->destroy(u, data); + c->features[i]->destroy(obj, data); data += c->features[i]->size; } if (c->extra && c->extra->destroy) - c->extra->destroy(u, ((char *) u) + c->extra_offset); + c->extra->destroy(obj, ((char *) obj) + c->extra_offset); - hashtable_del(c->h, u); - free(p); + hashtable_del(c->h, &obj->hashnode); } -static void __cache_del(struct cache *c, struct us_conntrack *u) +void cache_del(struct cache *c, struct cache_object *obj) { /* * Do not increase stats if we are trying to * kill an entry was previously deleted via * __cache_del_timer. */ - if (!alarm_pending(&u->alarm)) { + if (!alarm_pending(&obj->alarm)) { c->stats.del_ok++; c->stats.active--; } - del_alarm(&u->alarm); - __del(c, u); + del_alarm(&obj->alarm); + __del(c, obj); } -struct us_conntrack *cache_update_force(struct cache *c, - struct nf_conntrack *ct) +struct cache_object * +cache_update_force(struct cache *c, struct nf_conntrack *ct) { - struct us_conntrack *u; - - u = cache_find(c, ct); - if (u) { - if (!alarm_pending(&u->alarm)) { - c->stats.upd_ok++; - __cache_update(c, u, ct); - return u; + struct cache_object *obj; + int id; + + obj = cache_find(c, ct, &id); + if (obj) { + if (!alarm_pending(&obj->alarm)) { + cache_update(c, obj, id, ct); + return obj; } else { - __cache_del(c, u); + cache_del(c, obj); + cache_object_free(obj); } } - if ((u = __add(c, ct)) != NULL) { - c->stats.add_ok++; - return u; - } - c->stats.add_fail++; - if (errno == ENOSPC) - c->stats.add_fail_enospc++; - if (errno == ENOMEM) - c->stats.add_fail_enomem++; - - return NULL; -} - -int cache_test(struct cache *c, struct nf_conntrack *ct) -{ - size_t size = c->h->datasize; - char buf[size]; - struct us_conntrack *u = (struct us_conntrack *) buf; - void *ret; - - u->ct = ct; - - ret = hashtable_find(c->h, u); - - return ret != NULL; -} - -int cache_del(struct cache *c, struct nf_conntrack *ct) -{ - size_t size = c->h->datasize; - char buf[size]; - struct us_conntrack *u = (struct us_conntrack *) buf; - - u->ct = ct; + obj = cache_object_new(c, ct); + if (obj == NULL) + return NULL; - u = (struct us_conntrack *) hashtable_find(c->h, u); - if (u) { - __cache_del(c, u); - return 1; - } - c->stats.del_fail++; - if (errno == ENOENT) - c->stats.del_fail_enoent++; + if (cache_add(c, obj, id) == -1) + return NULL; - return 0; + return obj; } static void __del_timeout(struct alarm_block *a, void *data) { - struct us_conntrack *u = (struct us_conntrack *) data; - - __del(u->cache, u); + struct cache_object *obj = (struct cache_object *) data; + __del(obj->cache, obj); + cache_object_free(obj); } -int -__cache_del_timer(struct cache *c, struct us_conntrack *u, int timeout) +int cache_del_timer(struct cache *c, struct cache_object *obj, int timeout) { if (timeout <= 0) { - __cache_del(c, u); + cache_del(c, obj); + cache_object_free(obj); return 1; } - if (!alarm_pending(&u->alarm)) { - add_alarm(&u->alarm, timeout, 0); + if (!alarm_pending(&obj->alarm)) { + add_alarm(&obj->alarm, timeout, 0); /* * increase stats even if this entry was not really * removed yet. We do not want to make people think @@ -409,20 +348,16 @@ __cache_del_timer(struct cache *c, struct us_conntrack *u, int timeout) return 0; } -struct us_conntrack *cache_find(struct cache *c, struct nf_conntrack *ct) +struct cache_object * +cache_find(struct cache *c, struct nf_conntrack *ct, int *id) { - size_t size = c->h->datasize; - char buf[size]; - struct us_conntrack *u = (struct us_conntrack *) buf; - - u->ct = ct; - - return ((struct us_conntrack *) hashtable_find(c->h, u)); + *id = hashtable_hash(c->h, ct); + return ((struct cache_object *) hashtable_find(c->h, ct, *id)); } -struct us_conntrack *cache_get_conntrack(struct cache *c, void *data) +struct cache_object *cache_data_get_object(struct cache *c, void *data) { - return (struct us_conntrack *)((char*)data - c->extra_offset); + return (struct cache_object *)((char*)data - c->extra_offset); } void *cache_get_extra(struct cache *c, void *data) diff --git a/src/cache_iterators.c b/src/cache_iterators.c index a14f428..4773889 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -21,7 +21,6 @@ #include "log.h" #include "conntrackd.h" #include "netlink.h" -#include "us-conntrack.h" #include #include @@ -33,13 +32,13 @@ struct __dump_container { int type; }; -static int do_dump(void *data1, void *data2) +static int do_dump(void *data1, struct hashtable_node *n) { char buf[1024]; int size; struct __dump_container *container = data1; - struct us_conntrack *u = data2; - char *data = u->data; + struct cache_object *obj = (struct cache_object *)n; + char *data = obj->data; unsigned i; /* @@ -52,28 +51,28 @@ static int do_dump(void *data1, void *data2) * specific and it breaks conntrackd modularity. Probably * there's a nicer way to do this but until I come up with it... */ - if (CONFIG(flags) & CTD_SYNC_FTFW && alarm_pending(&u->alarm)) + if (CONFIG(flags) & CTD_SYNC_FTFW && alarm_pending(&obj->alarm)) return 0; /* do not show cached timeout, this may confuse users */ - if (nfct_attr_is_set(u->ct, ATTR_TIMEOUT)) - nfct_attr_unset(u->ct, ATTR_TIMEOUT); + if (nfct_attr_is_set(obj->ct, ATTR_TIMEOUT)) + nfct_attr_unset(obj->ct, ATTR_TIMEOUT); memset(buf, 0, sizeof(buf)); size = nfct_snprintf(buf, sizeof(buf), - u->ct, + obj->ct, NFCT_T_UNKNOWN, container->type, 0); - for (i = 0; i < u->cache->num_features; i++) { - if (u->cache->features[i]->dump) { - size += u->cache->features[i]->dump(u, - data, - buf+size, - container->type); - data += u->cache->features[i]->size; + for (i = 0; i < obj->cache->num_features; i++) { + if (obj->cache->features[i]->dump) { + size += obj->cache->features[i]->dump(obj, + data, + buf+size, + container->type); + data += obj->cache->features[i]->size; } } size += sprintf(buf+size, "\n"); @@ -101,10 +100,10 @@ struct __commit_container { }; static void -__do_commit_step(struct __commit_container *tmp, struct us_conntrack *u) +__do_commit_step(struct __commit_container *tmp, struct cache_object *obj) { int ret, retry = 1; - struct nf_conntrack *ct = u->ct; + struct nf_conntrack *ct = obj->ct; /* * Set a reduced timeout for candidate-to-be-committed @@ -166,25 +165,25 @@ try_again: } } -static int do_commit_related(void *data1, void *data2) +static int do_commit_related(void *data, struct hashtable_node *n) { - struct us_conntrack *u = data2; + struct cache_object *obj = (struct cache_object *)n; - if (ct_is_related(u->ct)) - __do_commit_step(data1, u); + if (ct_is_related(obj->ct)) + __do_commit_step(data, obj); /* keep iterating even if we have found errors */ return 0; } -static int do_commit_master(void *data1, void *data2) +static int do_commit_master(void *data, struct hashtable_node *n) { - struct us_conntrack *u = data2; + struct cache_object *obj = (struct cache_object *)n; - if (ct_is_related(u->ct)) + if (ct_is_related(obj->ct)) return 0; - __do_commit_step(data1, u); + __do_commit_step(data, obj); return 0; } @@ -231,13 +230,13 @@ void cache_commit(struct cache *c) res.tv_sec, res.tv_usec); } -static int do_reset_timers(void *data1, void *data2) +static int do_reset_timers(void *data1, struct hashtable_node *n) { int ret; u_int32_t current_timeout; struct nfct_handle *h = data1; - struct us_conntrack *u = data2; - struct nf_conntrack *ct = u->ct; + struct cache_object *obj = (struct cache_object *)n; + struct nf_conntrack *ct = obj->ct; char __tmp[nfct_maxsize()]; struct nf_conntrack *tmp = (struct nf_conntrack *) (void *)__tmp; @@ -286,13 +285,13 @@ void cache_reset_timers(struct cache *c) nfct_close(h); } -static int do_flush(void *data1, void *data2) +static int do_flush(void *data, struct hashtable_node *n) { - struct cache *c = data1; - struct us_conntrack *u = data2; - - cache_del(c, u->ct); + struct cache *c = data; + struct cache_object *obj = (struct cache_object *)n; + cache_del(c, obj); + cache_object_free(obj); return 0; } diff --git a/src/cache_lifetime.c b/src/cache_lifetime.c index ad3416a..639d8c1 100644 --- a/src/cache_lifetime.c +++ b/src/cache_lifetime.c @@ -17,12 +17,12 @@ */ #include -#include "us-conntrack.h" #include "cache.h" #include #include +#include -static void lifetime_add(struct us_conntrack *u, void *data) +static void lifetime_add(struct cache_object *obj, void *data) { long *lifetime = data; struct timeval tv; @@ -32,15 +32,15 @@ static void lifetime_add(struct us_conntrack *u, void *data) *lifetime = tv.tv_sec; } -static void lifetime_update(struct us_conntrack *u, void *data) +static void lifetime_update(struct cache_object *obj, void *data) { } -static void lifetime_destroy(struct us_conntrack *u, void *data) +static void lifetime_destroy(struct cache_object *obj, void *data) { } -static int lifetime_dump(struct us_conntrack *u, +static int lifetime_dump(struct cache_object *obj, void *data, char *buf, int type) diff --git a/src/cache_timer.c b/src/cache_timer.c index 44482b7..a9e3e3d 100644 --- a/src/cache_timer.c +++ b/src/cache_timer.c @@ -18,7 +18,6 @@ #include "cache.h" #include "conntrackd.h" -#include "us-conntrack.h" #include "alarm.h" #include "debug.h" @@ -26,45 +25,46 @@ static void timeout(struct alarm_block *a, void *data) { - struct us_conntrack *u = data; + struct cache_object *obj = data; - debug_ct(u->ct, "expired timeout"); - cache_del(u->cache, u->ct); + debug_ct(obj->ct, "expired timeout"); + cache_del(obj->cache, obj); + cache_object_free(obj); } -static void timer_add(struct us_conntrack *u, void *data) +static void timer_add(struct cache_object *obj, void *data) { - struct alarm_block *alarm = data; + struct alarm_block *a = data; - init_alarm(alarm, u, timeout); - add_alarm(alarm, CONFIG(cache_timeout), 0); + init_alarm(a, obj, timeout); + add_alarm(a, CONFIG(cache_timeout), 0); } -static void timer_update(struct us_conntrack *u, void *data) +static void timer_update(struct cache_object *obj, void *data) { - struct alarm_block *alarm = data; - add_alarm(alarm, CONFIG(cache_timeout), 0); + struct alarm_block *a = data; + add_alarm(a, CONFIG(cache_timeout), 0); } -static void timer_destroy(struct us_conntrack *u, void *data) +static void timer_destroy(struct cache_object *obj, void *data) { - struct alarm_block *alarm = data; - del_alarm(alarm); + struct alarm_block *a = data; + del_alarm(a); } -static int timer_dump(struct us_conntrack *u, void *data, char *buf, int type) +static int timer_dump(struct cache_object *obj, void *data, char *buf, int type) { struct timeval tv, tmp; - struct alarm_block *alarm = data; + struct alarm_block *a = data; if (type == NFCT_O_XML) return 0; - if (!alarm_pending(alarm)) + if (!alarm_pending(a)) return 0; gettimeofday(&tv, NULL); - timersub(&alarm->tv, &tv, &tmp); + timersub(&a->tv, &tv, &tmp); return sprintf(buf, " [expires in %lds]", tmp.tv_sec); } diff --git a/src/cache_wt.c b/src/cache_wt.c index d0ae8bb..84a816f 100644 --- a/src/cache_wt.c +++ b/src/cache_wt.c @@ -19,67 +19,66 @@ #include "conntrackd.h" #include "cache.h" #include "netlink.h" -#include "us-conntrack.h" #include "log.h" #include #include -static void add_wt(struct us_conntrack *u) +static void add_wt(struct cache_object *obj) { int ret; char __ct[nfct_maxsize()]; struct nf_conntrack *ct = (struct nf_conntrack *)(void*) __ct; - ret = nl_exist_conntrack(STATE(request), u->ct); + ret = nl_exist_conntrack(STATE(request), obj->ct); switch (ret) { case -1: dlog(LOG_ERR, "cache_wt problem: %s", strerror(errno)); - dlog_ct(STATE(log), u->ct, NFCT_O_PLAIN); + dlog_ct(STATE(log), obj->ct, NFCT_O_PLAIN); break; case 0: - memcpy(ct, u->ct, nfct_maxsize()); + memcpy(ct, obj->ct, nfct_maxsize()); if (nl_create_conntrack(STATE(dump), ct) == -1) { dlog(LOG_ERR, "cache_wt create: %s", strerror(errno)); - dlog_ct(STATE(log), u->ct, NFCT_O_PLAIN); + dlog_ct(STATE(log), obj->ct, NFCT_O_PLAIN); } break; case 1: - memcpy(ct, u->ct, nfct_maxsize()); + memcpy(ct, obj->ct, nfct_maxsize()); if (nl_update_conntrack(STATE(dump), ct) == -1) { dlog(LOG_ERR, "cache_wt crt-upd: %s", strerror(errno)); - dlog_ct(STATE(log), u->ct, NFCT_O_PLAIN); + dlog_ct(STATE(log), obj->ct, NFCT_O_PLAIN); } break; } } -static void upd_wt(struct us_conntrack *u) +static void upd_wt(struct cache_object *obj) { char __ct[nfct_maxsize()]; struct nf_conntrack *ct = (struct nf_conntrack *)(void*) __ct; - memcpy(ct, u->ct, nfct_maxsize()); + memcpy(ct, obj->ct, nfct_maxsize()); if (nl_update_conntrack(STATE(dump), ct) == -1) { dlog(LOG_ERR, "cache_wt update:%s", strerror(errno)); - dlog_ct(STATE(log), u->ct, NFCT_O_PLAIN); + dlog_ct(STATE(log), obj->ct, NFCT_O_PLAIN); } } -static void writethrough_add(struct us_conntrack *u, void *data) +static void writethrough_add(struct cache_object *obj, void *data) { - add_wt(u); + add_wt(obj); } -static void writethrough_update(struct us_conntrack *u, void *data) +static void writethrough_update(struct cache_object *obj, void *data) { - upd_wt(u); + upd_wt(obj); } -static void writethrough_destroy(struct us_conntrack *u, void *data) +static void writethrough_destroy(struct cache_object *obj, void *data) { - nl_destroy_conntrack(STATE(dump), u->ct); + nl_destroy_conntrack(STATE(dump), obj->ct); } struct cache_feature writethrough_feature = { diff --git a/src/filter.c b/src/filter.c index c6e24a9..6a09c77 100644 --- a/src/filter.c +++ b/src/filter.c @@ -58,15 +58,17 @@ static uint32_t ct_filter_hash6(const void *data, const struct hashtable *table) static int ct_filter_compare(const void *data1, const void *data2) { - const uint32_t *f1 = data1; + const struct ct_filter_ipv4_hnode *f1 = data1; const uint32_t *f2 = data2; - return *f1 == *f2; + return f1->ip == *f2; } static int ct_filter_compare6(const void *data1, const void *data2) { - return memcmp(data1, data2, sizeof(uint32_t)*4) == 0; + const struct ct_filter_ipv6_hnode *f = data1; + + return memcmp(f->ipv6, data2, sizeof(uint32_t)*4) == 0; } struct ct_filter *ct_filter_create(void) @@ -80,7 +82,6 @@ struct ct_filter *ct_filter_create(void) filter->h = hashtable_create(FILTER_POOL_SIZE, FILTER_POOL_LIMIT, - sizeof(uint32_t), ct_filter_hash, ct_filter_compare); if (!filter->h) { @@ -90,7 +91,6 @@ struct ct_filter *ct_filter_create(void) filter->h6 = hashtable_create(FILTER_POOL_SIZE, FILTER_POOL_LIMIT, - sizeof(uint32_t)*4, ct_filter_hash6, ct_filter_compare6); if (!filter->h6) { @@ -155,16 +155,33 @@ void ct_filter_set_logic(struct ct_filter *filter, int ct_filter_add_ip(struct ct_filter *filter, void *data, uint8_t family) { + int id; filter = __filter_alloc(filter); switch(family) { case AF_INET: - if (!hashtable_add(filter->h, data)) + id = hashtable_hash(filter->h, data); + if (!hashtable_find(filter->h, data, id)) { + struct ct_filter_ipv4_hnode *n; + n = malloc(sizeof(struct ct_filter_ipv4_hnode)); + if (n == NULL) + return 0; + memcpy(&n->ip, data, sizeof(uint32_t)); + hashtable_add(filter->h, &n->node, id); return 0; + } break; case AF_INET6: - if (!hashtable_add(filter->h6, data)) + id = hashtable_hash(filter->h6, data); + if (!hashtable_find(filter->h6, data, id)) { + struct ct_filter_ipv6_hnode *n; + n = malloc(sizeof(struct ct_filter_ipv6_hnode)); + if (n == NULL) + return 0; + memcpy(n->ipv6, data, sizeof(uint32_t)*4); + hashtable_add(filter->h6, &n->node, id); return 0; + } break; } return 1; @@ -220,16 +237,34 @@ void ct_filter_add_state(struct ct_filter *f, int protonum, int val) static inline int __ct_filter_test_ipv4(struct ct_filter *f, struct nf_conntrack *ct) { + int id_src, id_dst; + uint32_t src, dst; + /* we only use the real source and destination address */ - return (hashtable_find(f->h, nfct_get_attr(ct, ATTR_ORIG_IPV4_SRC)) || - hashtable_find(f->h, nfct_get_attr(ct, ATTR_REPL_IPV4_SRC))); + src = nfct_get_attr_u32(ct, ATTR_ORIG_IPV4_SRC); + dst = nfct_get_attr_u32(ct, ATTR_REPL_IPV4_SRC); + + id_src = hashtable_hash(f->h, &src); + id_dst = hashtable_hash(f->h, &dst); + + return hashtable_find(f->h, &src, id_src) || + hashtable_find(f->h, &dst, id_dst); } static inline int __ct_filter_test_ipv6(struct ct_filter *f, struct nf_conntrack *ct) { - return (hashtable_find(f->h6, nfct_get_attr(ct, ATTR_ORIG_IPV6_SRC)) || - hashtable_find(f->h6, nfct_get_attr(ct, ATTR_REPL_IPV6_SRC))); + int id_src, id_dst; + const uint32_t *src, *dst; + + src = nfct_get_attr(ct, ATTR_ORIG_IPV6_SRC); + dst = nfct_get_attr(ct, ATTR_REPL_IPV6_SRC); + + id_src = hashtable_hash(f->h6, src); + id_dst = hashtable_hash(f->h6, dst); + + return hashtable_find(f->h6, src, id_src) || + hashtable_find(f->h6, dst, id_dst); } static int diff --git a/src/hash.c b/src/hash.c index 1edb977..9c9ea5b 100644 --- a/src/hash.c +++ b/src/hash.c @@ -1,5 +1,5 @@ /* - * (C) 2006-2007 by Pablo Neira Ayuso + * (C) 2006-2009 by Pablo Neira Ayuso * * 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 @@ -19,32 +19,13 @@ */ #include "hash.h" -#include "slist.h" #include #include #include -struct hashtable_node *hashtable_alloc_node(int datasize, void *data) -{ - struct hashtable_node *n; - int size = sizeof(struct hashtable_node) + datasize; - - n = calloc(size, 1); - if (n == NULL) - return NULL; - memcpy(n->data, data, datasize); - - return n; -} - -void hashtable_destroy_node(struct hashtable_node *h) -{ - free(h); -} - struct hashtable * -hashtable_create(int hashsize, int limit, int datasize, +hashtable_create(int hashsize, int limit, uint32_t (*hash)(const void *data, const struct hashtable *table), int (*compare)(const void *data1, const void *data2)) @@ -52,7 +33,7 @@ hashtable_create(int hashsize, int limit, int datasize, int i; struct hashtable *h; int size = sizeof(struct hashtable) - + hashsize * sizeof(struct slist_head); + + hashsize * sizeof(struct list_head); h = (struct hashtable *) calloc(size, 1); if (h == NULL) { @@ -61,11 +42,10 @@ hashtable_create(int hashsize, int limit, int datasize, } for (i=0; imembers[i]); + INIT_LIST_HEAD(&h->members[i]); h->hashsize = hashsize; h->limit = limit; - h->datasize = datasize; h->hash = hash; h->compare = compare; @@ -74,112 +54,74 @@ hashtable_create(int hashsize, int limit, int datasize, void hashtable_destroy(struct hashtable *h) { - hashtable_flush(h); free(h); } -void *hashtable_add(struct hashtable *table, void *data) +int hashtable_hash(const struct hashtable *table, const void *data) { - struct slist_head *e; - struct hashtable_node *n; - uint32_t id; - - /* hash table is full */ - if (table->count >= table->limit) { - errno = ENOSPC; - return NULL; - } - - id = table->hash(data, table); - - slist_for_each(e, &table->members[id]) { - n = slist_entry(e, struct hashtable_node, head); - if (table->compare(n->data, data)) { - errno = EEXIST; - return NULL; - } - } - - n = hashtable_alloc_node(table->datasize, data); - if (n == NULL) { - errno = ENOMEM; - return NULL; - } - - slist_add(&table->members[id], &n->head); - table->count++; - - return n->data; + return table->hash(data, table); } -void *hashtable_find(struct hashtable *table, const void *data) +struct hashtable_node * +hashtable_find(const struct hashtable *table, const void *data, int id) { - struct slist_head *e; - uint32_t id; + struct list_head *e; struct hashtable_node *n; - id = table->hash(data, table); - - slist_for_each(e, &table->members[id]) { - n = slist_entry(e, struct hashtable_node, head); - if (table->compare(n->data, data)) - return n->data; + list_for_each(e, &table->members[id]) { + n = list_entry(e, struct hashtable_node, head); + if (table->compare(n, data)) { + return n; + } } - errno = ENOENT; return NULL; } -int hashtable_del(struct hashtable *table, void *data) +int hashtable_add(struct hashtable *table, struct hashtable_node *n, int id) { - struct slist_head *e, *next, *prev; - uint32_t id; - struct hashtable_node *n; - - id = table->hash(data, table); - - slist_for_each_safe(e, prev, next, &table->members[id]) { - n = slist_entry(e, struct hashtable_node, head); - if (table->compare(n->data, data)) { - slist_del(e, prev); - hashtable_destroy_node(n); - table->count--; - return 0; - } + /* hash table is full */ + if (table->count >= table->limit) { + errno = ENOSPC; + return -1; } - errno = ENOENT; - return -1; + list_add(&n->head, &table->members[id]); + table->count++; + return 0; +} + +void hashtable_del(struct hashtable *table, struct hashtable_node *n) +{ + list_del(&n->head); + table->count--; } int hashtable_flush(struct hashtable *table) { uint32_t i; - struct slist_head *e, *next, *prev; + struct list_head *e, *tmp; struct hashtable_node *n; - for (i=0; i < table->hashsize; i++) - slist_for_each_safe(e, prev, next, &table->members[i]) { - n = slist_entry(e, struct hashtable_node, head); - slist_del(e, prev); - hashtable_destroy_node(n); + for (i=0; i < table->hashsize; i++) { + list_for_each_safe(e, tmp, &table->members[i]) { + n = list_entry(e, struct hashtable_node, head); + free(n); } - - table->count = 0; - + } return 0; } int hashtable_iterate(struct hashtable *table, void *data, - int (*iterate)(void *data1, void *data2)) + int (*iterate)(void *data1, struct hashtable_node *n)) { uint32_t i; - struct slist_head *e, *next, *prev; + struct list_head *e, *tmp; struct hashtable_node *n; for (i=0; i < table->hashsize; i++) { - slist_for_each_safe(e, prev, next, &table->members[i]) { - n = slist_entry(e, struct hashtable_node, head); - if (iterate(data, n->data) == -1) + list_for_each_safe(e, tmp, &table->members[i]) { + n = list_entry(e, struct hashtable_node, head); + if (iterate(data, n) == -1) return -1; } } diff --git a/src/stats-mode.c b/src/stats-mode.c index d340b0d..679a50c 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -22,7 +22,6 @@ #include "cache.h" #include "log.h" #include "conntrackd.h" -#include "us-conntrack.h" #include #include @@ -118,9 +117,8 @@ static int overrun_stats(enum nf_conntrack_msg_type type, nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS); nfct_attr_unset(ct, ATTR_USE); - if (!cache_test(STATE_STATS(cache), ct)) - if (!cache_update_force(STATE_STATS(cache), ct)) - debug_ct(ct, "overrun stats resync"); + if (!cache_update_force(STATE_STATS(cache), ct)) + debug_ct(ct, "overrun stats resync"); return NFCT_CB_CONTINUE; } @@ -128,12 +126,13 @@ static int overrun_stats(enum nf_conntrack_msg_type type, static int purge_step(void *data1, void *data2) { int ret; - struct us_conntrack *u = data2; + struct cache_object *obj = data2; - ret = nfct_query(STATE(dump), NFCT_Q_GET, u->ct); + ret = nfct_query(STATE(dump), NFCT_Q_GET, obj->ct); if (ret == -1 && errno == ENOENT) { - debug_ct(u->ct, "overrun purge stats"); - cache_del(STATE_STATS(cache), u->ct); + debug_ct(obj->ct, "overrun purge stats"); + cache_del(STATE_STATS(cache), obj); + cache_object_free(obj); } return 0; @@ -148,42 +147,46 @@ static int purge_stats(void) static void event_new_stats(struct nf_conntrack *ct) { + int id; + struct cache_object *obj; + nfct_attr_unset(ct, ATTR_TIMEOUT); - if (cache_add(STATE_STATS(cache), ct)) { - debug_ct(ct, "cache new"); - } else { - if (errno != EEXIST) { - dlog(LOG_ERR, - "can't add to cache cache: %s\n", strerror(errno)); - debug_ct(ct, "can't add"); + obj = cache_find(STATE_STATS(cache), ct, &id); + if (obj == NULL) { + obj = cache_object_new(STATE_STATS(cache), ct); + if (obj == NULL) + return; + + if (cache_add(STATE_STATS(cache), obj, id) == -1) { + cache_object_free(obj); + return; } } + return; } static void event_update_stats(struct nf_conntrack *ct) { nfct_attr_unset(ct, ATTR_TIMEOUT); - - if (!cache_update_force(STATE_STATS(cache), ct)) { - debug_ct(ct, "can't update"); - return; - } - debug_ct(ct, "update"); + cache_update_force(STATE_STATS(cache), ct); } static int event_destroy_stats(struct nf_conntrack *ct) { + int id; + struct cache_object *obj; + nfct_attr_unset(ct, ATTR_TIMEOUT); - if (cache_del(STATE_STATS(cache), ct)) { - debug_ct(ct, "cache destroy"); + obj = cache_find(STATE_STATS(cache), ct, &id); + if (obj) { + cache_del(STATE_STATS(cache), obj); dlog_ct(STATE(stats_log), ct, NFCT_O_PLAIN); + cache_object_free(obj); return 1; - } else { - debug_ct(ct, "can't destroy!"); - return 0; } + return 0; } struct ct_mode stats_mode = { diff --git a/src/sync-alarm.c b/src/sync-alarm.c index d871b75..34937fe 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -19,7 +19,6 @@ #include "conntrackd.h" #include "sync.h" #include "network.h" -#include "us-conntrack.h" #include "alarm.h" #include "cache.h" #include "debug.h" @@ -30,40 +29,40 @@ static void refresher(struct alarm_block *a, void *data) { struct nethdr *net; - struct us_conntrack *u = data; + struct cache_object *obj = data; - debug_ct(u->ct, "persistence update"); + debug_ct(obj->ct, "persistence update"); add_alarm(a, random() % CONFIG(refresh) + 1, ((random() % 5 + 1) * 200000) - 1); - net = BUILD_NETMSG(u->ct, NET_T_STATE_UPD); + net = BUILD_NETMSG(obj->ct, NET_T_STATE_UPD); mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); } -static void cache_alarm_add(struct us_conntrack *u, void *data) +static void cache_alarm_add(struct cache_object *obj, void *data) { - struct alarm_block *alarm = data; + struct alarm_block *a = data; - init_alarm(alarm, u, refresher); - add_alarm(alarm, + init_alarm(a, obj, refresher); + add_alarm(a, random() % CONFIG(refresh) + 1, ((random() % 5 + 1) * 200000) - 1); } -static void cache_alarm_update(struct us_conntrack *u, void *data) +static void cache_alarm_update(struct cache_object *obj, void *data) { - struct alarm_block *alarm = data; - add_alarm(alarm, + struct alarm_block *a = data; + add_alarm(a, random() % CONFIG(refresh) + 1, ((random() % 5 + 1) * 200000) - 1); } -static void cache_alarm_destroy(struct us_conntrack *u, void *data) +static void cache_alarm_destroy(struct cache_object *obj, void *data) { - struct alarm_block *alarm = data; - del_alarm(alarm); + struct alarm_block *a = data; + del_alarm(a); } static struct cache_extra cache_alarm_extra = { diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 44e8f2f..bddc18c 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -18,7 +18,6 @@ #include "conntrackd.h" #include "sync.h" -#include "us-conntrack.h" #include "queue.h" #include "debug.h" #include "network.h" @@ -64,7 +63,7 @@ struct cache_ftfw { uint32_t seq; }; -static void cache_ftfw_add(struct us_conntrack *u, void *data) +static void cache_ftfw_add(struct cache_object *obj, void *data) { struct cache_ftfw *cn = data; /* These nodes are not inserted in the list */ @@ -72,7 +71,7 @@ static void cache_ftfw_add(struct us_conntrack *u, void *data) INIT_LIST_HEAD(&cn->tx_list); } -static void cache_ftfw_del(struct us_conntrack *u, void *data) +static void cache_ftfw_del(struct cache_object *obj, void *data) { struct cache_ftfw *cn = data; @@ -190,8 +189,8 @@ static void ftfw_kill(void) static int do_cache_to_tx(void *data1, void *data2) { - struct us_conntrack *u = data2; - struct cache_ftfw *cn = cache_get_extra(STATE_SYNC(internal), u); + struct cache_object *obj = data2; + struct cache_ftfw *cn = cache_get_extra(STATE_SYNC(internal), obj); /* repeated request for resync? */ if (!list_empty(&cn->tx_list)) @@ -226,9 +225,6 @@ static void debug_rs_dump(int fd) size = sprintf(buf, "resent list (len=%u):\n", rs_list_len); send(fd, buf, size, 0); list_for_each_entry_safe(cn, tmp, &rs_list, rs_list) { - struct us_conntrack *u; - - u = cache_get_conntrack(STATE_SYNC(internal), cn); size = sprintf(buf, "seq:%u\n", cn->seq); send(fd, buf, size, 0); } @@ -305,9 +301,9 @@ static void rs_list_to_tx(struct cache *c, unsigned int from, unsigned int to) struct cache_ftfw *cn, *tmp; list_for_each_entry_safe(cn, tmp, &rs_list, rs_list) { - struct us_conntrack *u; + struct cache_object *obj;; - u = cache_get_conntrack(STATE_SYNC(internal), cn); + obj = cache_data_get_object(STATE_SYNC(internal), cn); if (before(cn->seq, from)) continue; else if (after(cn->seq, to)) @@ -330,9 +326,9 @@ static void rs_list_empty(struct cache *c, unsigned int from, unsigned int to) struct cache_ftfw *cn, *tmp; list_for_each_entry_safe(cn, tmp, &rs_list, rs_list) { - struct us_conntrack *u; + struct cache_object *obj; - u = cache_get_conntrack(STATE_SYNC(internal), cn); + obj = cache_data_get_object(STATE_SYNC(internal), cn); if (before(cn->seq, from)) continue; else if (after(cn->seq, to)) @@ -473,7 +469,7 @@ out: return ret; } -static void ftfw_send(struct nethdr *net, struct us_conntrack *u) +static void ftfw_send(struct nethdr *net, struct cache_object *obj) { struct cache_ftfw *cn; @@ -482,7 +478,7 @@ static void ftfw_send(struct nethdr *net, struct us_conntrack *u) case NET_T_STATE_UPD: case NET_T_STATE_DEL: cn = (struct cache_ftfw *) - cache_get_extra(STATE_SYNC(internal), u); + cache_get_extra(STATE_SYNC(internal), obj); if (!list_empty(&cn->rs_list)) { list_del_init(&cn->rs_list); @@ -538,10 +534,10 @@ static int tx_queue_xmit(void *data1, const void *data2) return 0; } -static int tx_list_xmit(struct list_head *i, struct us_conntrack *u, int type) +static int tx_list_xmit(struct list_head *i, struct cache_object *obj, int type) { int ret; - struct nethdr *net = BUILD_NETMSG(u->ct, type); + struct nethdr *net = BUILD_NETMSG(obj->ct, type); dp("tx_list sq: %u fl:%u len:%u\n", ntohl(net->seq), net->flags, ntohs(net->len)); @@ -550,7 +546,7 @@ static int tx_list_xmit(struct list_head *i, struct us_conntrack *u, int type) tx_list_len--; ret = mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); - ftfw_send(net, u); + ftfw_send(net, obj); return ret; } @@ -564,13 +560,13 @@ static void ftfw_run(void) /* send conntracks in the tx_list */ list_for_each_entry_safe(cn, tmp, &tx_list, tx_list) { - struct us_conntrack *u; + struct cache_object *obj; - u = cache_get_conntrack(STATE_SYNC(internal), cn); - if (alarm_pending(&u->alarm)) - tx_list_xmit(&cn->tx_list, u, NET_T_STATE_DEL); + obj = cache_data_get_object(STATE_SYNC(internal), cn); + if (alarm_pending(&obj->alarm)) + tx_list_xmit(&cn->tx_list, obj, NET_T_STATE_DEL); else - tx_list_xmit(&cn->tx_list, u, NET_T_STATE_UPD); + tx_list_xmit(&cn->tx_list, obj, NET_T_STATE_UPD); } /* reset alive alarm */ diff --git a/src/sync-mode.c b/src/sync-mode.c index ad2e2ff..368984f 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -22,7 +22,6 @@ #include "log.h" #include "cache.h" #include "conntrackd.h" -#include "us-conntrack.h" #include "network.h" #include "fds.h" #include "event.h" @@ -38,7 +37,8 @@ static void do_mcast_handler_step(struct nethdr *net, size_t remain) { char __ct[nfct_maxsize()]; struct nf_conntrack *ct = (struct nf_conntrack *)(void*) __ct; - struct us_conntrack *u; + struct cache_object *obj; + int id; if (net->version != CONNTRACKD_PROTOCOL_VERSION) { STATE_SYNC(error).msg_rcv_malformed++; @@ -75,33 +75,32 @@ static void do_mcast_handler_step(struct nethdr *net, size_t remain) switch(net->type) { case NET_T_STATE_NEW: -retry: - if ((u = cache_add(STATE_SYNC(external), ct))) { - debug_ct(u->ct, "external new"); - } else { - /* - * One certain connection A arrives to the cache but - * another existing connection B in the cache has - * the same configuration, therefore B clashes with A. - */ - if (errno == EEXIST) { - cache_del(STATE_SYNC(external), ct); - goto retry; + obj = cache_find(STATE_SYNC(external), ct, &id); + if (obj == NULL) { +retry: + obj = cache_object_new(STATE_SYNC(external), ct); + if (obj == NULL) + return; + + if (cache_add(STATE_SYNC(external), obj, id) == -1) { + cache_object_free(obj); + return; } - debug_ct(ct, "can't add"); + } else { + cache_del(STATE_SYNC(external), obj); + cache_object_free(obj); + goto retry; } break; case NET_T_STATE_UPD: - if ((u = cache_update_force(STATE_SYNC(external), ct))) { - debug_ct(u->ct, "external update"); - } else - debug_ct(ct, "can't update"); + cache_update_force(STATE_SYNC(external), ct); break; case NET_T_STATE_DEL: - if (cache_del(STATE_SYNC(external), ct)) - debug_ct(ct, "external destroy"); - else - debug_ct(ct, "can't destroy"); + obj = cache_find(STATE_SYNC(external), ct, &id); + if (obj) { + cache_del(STATE_SYNC(external), obj); + cache_object_free(obj); + } break; default: STATE_SYNC(error).msg_rcv_malformed++; @@ -441,14 +440,14 @@ static void dump_sync(struct nf_conntrack *ct) debug_ct(ct, "resync"); } -static void mcast_send_sync(struct us_conntrack *u, int query) +static void mcast_send_sync(struct cache_object *obj, int query) { struct nethdr *net; - net = BUILD_NETMSG(u->ct, query); + net = BUILD_NETMSG(obj->ct, query); if (STATE_SYNC(sync)->send) - STATE_SYNC(sync)->send(net, u); + STATE_SYNC(sync)->send(net, obj); mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); } @@ -457,13 +456,13 @@ static int purge_step(void *data1, void *data2) { int ret; struct nfct_handle *h = STATE(dump); - struct us_conntrack *u = data2; + struct cache_object *obj = data2; - ret = nfct_query(h, NFCT_Q_GET, u->ct); + ret = nfct_query(h, NFCT_Q_GET, obj->ct); if (ret == -1 && errno == ENOENT) { - debug_ct(u->ct, "overrun purge resync"); - mcast_send_sync(u, NET_T_STATE_DEL); - __cache_del_timer(STATE_SYNC(internal), u, CONFIG(del_timeout)); + debug_ct(obj->ct, "overrun purge resync"); + mcast_send_sync(obj, NET_T_STATE_DEL); + cache_del_timer(STATE_SYNC(internal), obj, CONFIG(del_timeout)); } return 0; @@ -480,7 +479,7 @@ static int overrun_sync(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *data) { - struct us_conntrack *u; + struct cache_object *obj; if (ct_filter_conntrack(ct, 1)) return NFCT_CB_CONTINUE; @@ -492,11 +491,9 @@ static int overrun_sync(enum nf_conntrack_msg_type type, nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS); nfct_attr_unset(ct, ATTR_USE); - if (!cache_test(STATE_SYNC(internal), ct)) { - if ((u = cache_update_force(STATE_SYNC(internal), ct))) { - debug_ct(u->ct, "overrun resync"); - mcast_send_sync(u, NET_T_STATE_UPD); - } + if ((obj = cache_update_force(STATE_SYNC(internal), ct))) { + debug_ct(obj->ct, "overrun resync"); + mcast_send_sync(obj, NET_T_STATE_UPD); } return NFCT_CB_CONTINUE; @@ -504,50 +501,59 @@ static int overrun_sync(enum nf_conntrack_msg_type type, static void event_new_sync(struct nf_conntrack *ct) { - struct us_conntrack *u; + struct cache_object *obj; + int id; /* required by linux kernel <= 2.6.20 */ nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES); nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS); nfct_attr_unset(ct, ATTR_REPL_COUNTER_BYTES); nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS); + + obj = cache_find(STATE_SYNC(internal), ct, &id); + if (obj == NULL) { retry: - if ((u = cache_add(STATE_SYNC(internal), ct))) { - mcast_send_sync(u, NET_T_STATE_NEW); - debug_ct(u->ct, "internal new"); - } else { - if (errno == EEXIST) { - cache_del(STATE_SYNC(internal), ct); - goto retry; + obj = cache_object_new(STATE_SYNC(internal), ct); + if (obj == NULL) + return; + if (cache_add(STATE_SYNC(internal), obj, id) == -1) { + cache_object_free(obj); + return; } + mcast_send_sync(obj, NET_T_STATE_NEW); + debug_ct(obj->ct, "internal new"); + } else { + cache_del(STATE_SYNC(internal), obj); + cache_object_free(obj); debug_ct(ct, "can't add"); + goto retry; } } static void event_update_sync(struct nf_conntrack *ct) { - struct us_conntrack *u; + struct cache_object *obj; - if ((u = cache_update_force(STATE_SYNC(internal), ct)) == NULL) { + if ((obj = cache_update_force(STATE_SYNC(internal), ct)) == NULL) { debug_ct(ct, "can't update"); return; } - debug_ct(u->ct, "internal update"); - mcast_send_sync(u, NET_T_STATE_UPD); + debug_ct(obj->ct, "internal update"); + mcast_send_sync(obj, NET_T_STATE_UPD); } static int event_destroy_sync(struct nf_conntrack *ct) { - struct us_conntrack *u; + struct cache_object *obj; + int id; - u = cache_find(STATE_SYNC(internal), ct); - if (u == NULL) { + obj = cache_find(STATE_SYNC(internal), ct, &id); + if (obj == NULL) { debug_ct(ct, "can't destroy"); return 0; } - - mcast_send_sync(u, NET_T_STATE_DEL); - __cache_del_timer(STATE_SYNC(internal), u, CONFIG(del_timeout)); + mcast_send_sync(obj, NET_T_STATE_DEL); + cache_del_timer(STATE_SYNC(internal), obj, CONFIG(del_timeout)); debug_ct(ct, "internal destroy"); return 1; } diff --git a/src/sync-notrack.c b/src/sync-notrack.c index 700e272..2d3783e 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -18,7 +18,6 @@ #include "conntrackd.h" #include "sync.h" -#include "us-conntrack.h" #include "queue.h" #include "debug.h" #include "network.h" @@ -36,13 +35,13 @@ struct cache_notrack { struct list_head tx_list; }; -static void cache_notrack_add(struct us_conntrack *u, void *data) +static void cache_notrack_add(struct cache_object *obj, void *data) { struct cache_notrack *cn = data; INIT_LIST_HEAD(&cn->tx_list); } -static void cache_notrack_del(struct us_conntrack *u, void *data) +static void cache_notrack_del(struct cache_object *obj, void *data) { struct cache_notrack *cn = data; @@ -89,8 +88,8 @@ static void notrack_kill(void) static int do_cache_to_tx(void *data1, void *data2) { - struct us_conntrack *u = data2; - struct cache_notrack *cn = cache_get_extra(STATE_SYNC(internal), u); + struct cache_object *obj = data2; + struct cache_notrack *cn = cache_get_extra(STATE_SYNC(internal), obj); if (!list_empty(&cn->tx_list)) return 0; @@ -164,10 +163,10 @@ static int tx_queue_xmit(void *data1, const void *data2) return 0; } -static int tx_list_xmit(struct list_head *i, struct us_conntrack *u, int type) +static int tx_list_xmit(struct list_head *i, struct cache_object *obj, int type) { int ret; - struct nethdr *net = BUILD_NETMSG(u->ct, type); + struct nethdr *net = BUILD_NETMSG(obj->ct, type); list_del_init(i); tx_list_len--; @@ -186,10 +185,10 @@ static void notrack_run(void) /* send conntracks in the tx_list */ list_for_each_entry_safe(cn, tmp, &tx_list, tx_list) { - struct us_conntrack *u; + struct cache_object *obj; - u = cache_get_conntrack(STATE_SYNC(internal), cn); - tx_list_xmit(&cn->tx_list, u, NET_T_STATE_UPD); + obj = cache_data_get_object(STATE_SYNC(internal), cn); + tx_list_xmit(&cn->tx_list, obj, NET_T_STATE_UPD); } } -- cgit v1.2.3 From e2af183ea7e5ea35a1582f40a01a7c49e83b31be Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 15 Jan 2009 23:19:58 +0100 Subject: sync: unify tx_list and tx_queue into one single tx_queue This patch unifies the tx_list and the tx_queue to have only one transmission queue. Since the tx_list hold state objects and tx_queue control messages, I have introduced a queue node type that can be used to differenciate the kind of information that the node stores: object or control message. This patch also reworks the existing queue class to include a file descriptor that can be used to know if there are new data added to the queue (see QUEUE_F_EVFD flag). In this change, I have also modified the current evfd to make the file descriptor to make read operations non-blocking. Moreover, it keeps a counter that is used to know how many messages are inserted in the queue. Signed-off-by: Pablo Neira Ayuso --- include/conntrackd.h | 1 - include/queue.h | 51 +++++-- include/sync.h | 6 +- src/event.c | 20 +-- src/queue.c | 124 +++++++++-------- src/sync-ftfw.c | 367 ++++++++++++++++++++++++--------------------------- src/sync-mode.c | 20 +-- src/sync-notrack.c | 114 ++++++++-------- 8 files changed, 360 insertions(+), 343 deletions(-) (limited to 'src/sync-notrack.c') diff --git a/include/conntrackd.h b/include/conntrackd.h index 67397b8..8cb520d 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -150,7 +150,6 @@ struct ct_sync_state { struct mcast_sock *mcast_server; /* multicast socket: incoming */ struct mcast_sock *mcast_client; /* multicast socket: outgoing */ - struct evfd *evfd; /* event fd */ struct sync_mode *sync; /* sync mode */ diff --git a/include/queue.h b/include/queue.h index 5a9cf39..ef56323 100644 --- a/include/queue.h +++ b/include/queue.h @@ -1,28 +1,53 @@ #ifndef _QUEUE_H_ #define _QUEUE_H_ +#include #include "linux_list.h" -struct queue { - size_t max_size; - size_t cur_size; - unsigned int num_elems; - struct list_head head; +struct queue_node { + struct list_head head; + uint32_t type; + struct queue *owner; + size_t size; }; -struct queue_node { - struct list_head head; - size_t size; - char data[0]; +enum { + Q_ELEM_OBJ = 0, + Q_ELEM_CTL = 1 +}; + +void queue_node_init(struct queue_node *n, int type); +void *queue_node_data(struct queue_node *n); + +struct queue_object { + struct queue_node qnode; + char data[0]; }; -struct queue *queue_create(size_t max_size); +struct queue_object *queue_object_new(int type, size_t size); +void queue_object_free(struct queue_object *obj); + +struct evfd; + +struct queue { + unsigned int max_elems; + unsigned int num_elems; + uint32_t flags; + struct list_head head; + struct evfd *evfd; +}; + +#define QUEUE_F_EVFD (1U << 0) + +struct queue *queue_create(int max_objects, unsigned int flags); void queue_destroy(struct queue *b); unsigned int queue_len(const struct queue *b); -int queue_add(struct queue *b, const void *data, size_t size); -void queue_del(struct queue *b, void *data); +int queue_add(struct queue *b, struct queue_node *n); +int queue_del(struct queue_node *n); +int queue_in(struct queue *b, struct queue_node *n); void queue_iterate(struct queue *b, const void *data, - int (*iterate)(void *data1, const void *data2)); + int (*iterate)(struct queue_node *n, const void *data2)); +int queue_get_eventfd(struct queue *b); #endif diff --git a/include/sync.h b/include/sync.h index 60c9fae..9a9540c 100644 --- a/include/sync.h +++ b/include/sync.h @@ -1,8 +1,11 @@ #ifndef _SYNC_HOOKS_H_ #define _SYNC_HOOKS_H_ +#include + struct nethdr; struct cache_object; +struct fds; struct sync_mode { int internal_cache_flags; @@ -15,7 +18,8 @@ struct sync_mode { int (*local)(int fd, int type, void *data); int (*recv)(const struct nethdr *net); void (*send)(struct nethdr *net, struct cache_object *obj); - void (*run)(void); + void (*run)(fd_set *readfds); + int (*register_fds)(struct fds *fds); }; extern struct sync_mode sync_alarm; diff --git a/src/event.c b/src/event.c index ed78835..d1dfe72 100644 --- a/src/event.c +++ b/src/event.c @@ -17,6 +17,8 @@ */ #include #include +#include +#include #include "event.h" @@ -37,6 +39,7 @@ struct evfd *create_evfd(void) free(e); return NULL; } + fcntl(e->fds[0], F_SETFL, O_NONBLOCK); return e; } @@ -55,19 +58,20 @@ int get_read_evfd(struct evfd *evfd) int write_evfd(struct evfd *evfd) { - int data = 0; + int data = 0, ret = 0; - if (evfd->read) - return 0; + if (evfd->read == 0) + ret = write(evfd->fds[1], &data, sizeof(data)); + evfd->read++; - evfd->read = 1; - return write(evfd->fds[1], &data, sizeof(data)); + return ret; } int read_evfd(struct evfd *evfd) { - int data; + int data, ret = 0; - evfd->read = 0; - return read(evfd->fds[0], &data, sizeof(data)); + if (--evfd->read == 0) + ret = read(evfd->fds[0], &data, sizeof(data)); + return ret; } diff --git a/src/queue.c b/src/queue.c index cdd70ae..cffcc93 100644 --- a/src/queue.c +++ b/src/queue.c @@ -1,5 +1,5 @@ /* - * (C) 2006-2008 by Pablo Neira Ayuso + * (C) 2006-2009 by Pablo Neira Ayuso * * 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 @@ -17,110 +17,122 @@ */ #include "queue.h" +#include "event.h" #include #include #include -struct queue *queue_create(size_t max_size) +struct queue *queue_create(int max_objects, unsigned int flags) { struct queue *b; - b = malloc(sizeof(struct queue)); + b = calloc(sizeof(struct queue), 1); if (b == NULL) return NULL; - memset(b, 0, sizeof(struct queue)); - b->max_size = max_size; + b->max_elems = max_objects; INIT_LIST_HEAD(&b->head); + b->flags = flags; + + if (flags & QUEUE_F_EVFD) { + b->evfd = create_evfd(); + if (b->evfd == NULL) { + free(b); + return NULL; + } + } return b; } void queue_destroy(struct queue *b) { - struct list_head *i, *tmp; - struct queue_node *node; - - /* XXX: set cur_size and num_elems */ - list_for_each_safe(i, tmp, &b->head) { - node = (struct queue_node *) i; - list_del(i); - free(node); - } + if (b->flags & QUEUE_F_EVFD) + destroy_evfd(b->evfd); free(b); } -static struct queue_node *queue_node_create(const void *data, size_t size) +void queue_node_init(struct queue_node *n, int type) { - struct queue_node *n; + INIT_LIST_HEAD(&n->head); + n->type = type; +} - n = malloc(sizeof(struct queue_node) + size); - if (n == NULL) +void *queue_node_data(struct queue_node *n) +{ + return ((char *)n) + sizeof(struct queue_node); +} + +struct queue_object *queue_object_new(int type, size_t size) +{ + struct queue_object *obj; + + obj = calloc(sizeof(struct queue_object) + size, 1); + if (obj == NULL) return NULL; - n->size = size; - memcpy(n->data, data, size); + obj->qnode.size = size; + queue_node_init(&obj->qnode, type); - return n; + return obj; } -int queue_add(struct queue *b, const void *data, size_t size) +void queue_object_free(struct queue_object *obj) { - int ret = 0; - struct queue_node *n; - - /* does it fit this queue? */ - if (size > b->max_size) { - errno = ENOSPC; - ret = -1; - goto err; - } + free(obj); +} -retry: - /* queue is full: kill the oldest entry */ - if (b->cur_size + size > b->max_size) { - n = (struct queue_node *) b->head.prev; - list_del(b->head.prev); - b->cur_size -= n->size; - free(n); - goto retry; - } +int queue_add(struct queue *b, struct queue_node *n) +{ + if (!list_empty(&n->head)) + return 0; - n = queue_node_create(data, size); - if (n == NULL) { - ret = -1; - goto err; + if (b->num_elems >= b->max_elems) { + errno = ENOSPC; + return -1; } - + n->owner = b; list_add_tail(&n->head, &b->head); - b->cur_size += size; b->num_elems++; + if (b->evfd) + write_evfd(b->evfd); + return 1; +} -err: - return ret; +int queue_del(struct queue_node *n) +{ + if (list_empty(&n->head)) + return 0; + + list_del_init(&n->head); + n->owner->num_elems--; + if (n->owner->evfd) + read_evfd(n->owner->evfd); + n->owner = NULL; + return 1; } -void queue_del(struct queue *b, void *data) +int queue_in(struct queue *b, struct queue_node *n) { - struct queue_node *n = container_of(data, struct queue_node, data); + return b == n->owner; +} - list_del(&n->head); - b->cur_size -= n->size; - b->num_elems--; - free(n); +int queue_get_eventfd(struct queue *b) +{ + return get_read_evfd(b->evfd); } void queue_iterate(struct queue *b, const void *data, - int (*iterate)(void *data1, const void *data2)) + int (*iterate)(struct queue_node *n, const void *data2)) { struct list_head *i, *tmp; struct queue_node *n; list_for_each_safe(i, tmp, &b->head) { n = (struct queue_node *) i; - if (iterate(n->data, data)) + if (iterate(n, data)) break; } } diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index bddc18c..bb53849 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -24,7 +24,7 @@ #include "alarm.h" #include "log.h" #include "cache.h" -#include "event.h" +#include "fds.h" #include @@ -34,12 +34,8 @@ #define dp(...) #endif -static LIST_HEAD(rs_list); -static LIST_HEAD(tx_list); -static unsigned int rs_list_len; -static unsigned int tx_list_len; -static struct queue *rs_queue; -static struct queue *tx_queue; +struct queue *tx_queue; +struct queue *rs_queue; static uint32_t exp_seq; static uint32_t window; static uint32_t ack_from; @@ -58,8 +54,7 @@ static int say_hello_back; #define ALIVE_INT 1 struct cache_ftfw { - struct list_head rs_list; - struct list_head tx_list; + struct queue_node qnode; uint32_t seq; }; @@ -67,24 +62,13 @@ static void cache_ftfw_add(struct cache_object *obj, void *data) { struct cache_ftfw *cn = data; /* These nodes are not inserted in the list */ - INIT_LIST_HEAD(&cn->rs_list); - INIT_LIST_HEAD(&cn->tx_list); + queue_node_init(&cn->qnode, Q_ELEM_OBJ); } static void cache_ftfw_del(struct cache_object *obj, void *data) { struct cache_ftfw *cn = data; - - /* this node is already out of the list */ - if (!list_empty(&cn->rs_list)) { - /* no need for list_del_init since the entry is destroyed */ - list_del(&cn->rs_list); - rs_list_len--; - } - if (!list_empty(&cn->tx_list)) { - list_del(&cn->tx_list); - tx_list_len--; - } + queue_del(&cn->qnode); } static struct cache_extra cache_ftfw_extra = { @@ -95,54 +79,64 @@ static struct cache_extra cache_ftfw_extra = { static void tx_queue_add_ctlmsg(uint32_t flags, uint32_t from, uint32_t to) { - struct nethdr_ack ack = { - .type = NET_T_CTL, - .flags = flags, - .from = from, - .to = to, - }; + struct queue_object *qobj; + struct nethdr_ack *ack; + + qobj = queue_object_new(Q_ELEM_CTL, sizeof(struct nethdr_ack)); + if (qobj == NULL) + return; + + ack = (struct nethdr_ack *)qobj->data; + ack->type = NET_T_CTL; + ack->flags = flags; + ack->from = from; + ack->to = to; switch(hello_state) { case HELLO_INIT: hello_state = HELLO_SAY; /* fall through */ case HELLO_SAY: - ack.flags |= NET_F_HELLO; + ack->flags |= NET_F_HELLO; break; } if (say_hello_back) { - ack.flags |= NET_F_HELLO_BACK; + ack->flags |= NET_F_HELLO_BACK; say_hello_back = 0; } - queue_add(tx_queue, &ack, NETHDR_ACK_SIZ); - write_evfd(STATE_SYNC(evfd)); + queue_add(tx_queue, &qobj->qnode); } static void tx_queue_add_ctlmsg2(uint32_t flags) { - struct nethdr ctl = { - .type = NET_T_CTL, - .flags = flags, - }; + struct queue_object *qobj; + struct nethdr *ctl; + + qobj = queue_object_new(Q_ELEM_CTL, sizeof(struct nethdr_ack)); + if (qobj == NULL) + return; + + ctl = (struct nethdr *)qobj->data; + ctl->type = NET_T_CTL; + ctl->flags = flags; switch(hello_state) { case HELLO_INIT: hello_state = HELLO_SAY; /* fall through */ case HELLO_SAY: - ctl.flags |= NET_F_HELLO; + ctl->flags |= NET_F_HELLO; break; } if (say_hello_back) { - ctl.flags |= NET_F_HELLO_BACK; + ctl->flags |= NET_F_HELLO_BACK; say_hello_back = 0; } - queue_add(tx_queue, &ctl, NETHDR_SIZ); - write_evfd(STATE_SYNC(evfd)); + queue_add(tx_queue, &qobj->qnode); } /* this function is called from the alarm framework */ @@ -156,17 +150,18 @@ static void do_alive_alarm(struct alarm_block *a, void *data) ack_from_set = 0; } else tx_queue_add_ctlmsg2(NET_F_ALIVE); + + add_alarm(&alive_alarm, ALIVE_INT, 0); } static int ftfw_init(void) { - tx_queue = queue_create(CONFIG(resend_queue_size)); + tx_queue = queue_create(INT_MAX, QUEUE_F_EVFD); if (tx_queue == NULL) { dlog(LOG_ERR, "cannot create tx queue"); return -1; } - - rs_queue = queue_create(CONFIG(resend_queue_size)); + rs_queue = queue_create(INT_MAX, 0); if (rs_queue == NULL) { dlog(LOG_ERR, "cannot create rs queue"); return -1; @@ -192,45 +187,47 @@ static int do_cache_to_tx(void *data1, void *data2) struct cache_object *obj = data2; struct cache_ftfw *cn = cache_get_extra(STATE_SYNC(internal), obj); - /* repeated request for resync? */ - if (!list_empty(&cn->tx_list)) - return 0; + if (queue_in(rs_queue, &cn->qnode)) + queue_del(&cn->qnode); - /* add to tx list */ - list_add_tail(&cn->tx_list, &tx_list); - tx_list_len++; - write_evfd(STATE_SYNC(evfd)); + queue_add(tx_queue, &cn->qnode); return 0; } -static int debug_rs_queue_dump_step(void *data1, const void *data2) +static int rs_queue_dump(struct queue_node *n, const void *data2) { - struct nethdr_ack *net = data1; const int *fd = data2; char buf[512]; int size; - size = sprintf(buf, "seq:%u flags:%u\n", net->seq, net->flags); + switch(n->type) { + case Q_ELEM_CTL: { + struct nethdr *net = queue_node_data(n); + size = sprintf(buf, "control -> seq:%u flags:%u\n", + net->seq, net->flags); + break; + } + case Q_ELEM_OBJ: { + struct cache_ftfw *cn = (struct cache_ftfw *) n; + size = sprintf(buf, "object -> seq:%u\n", cn->seq); + break; + } + default: + return 0; + } send(*fd, buf, size, 0); return 0; } static void debug_rs_dump(int fd) { - struct cache_ftfw *cn, *tmp; char buf[512]; int size; - size = sprintf(buf, "resent list (len=%u):\n", rs_list_len); - send(fd, buf, size, 0); - list_for_each_entry_safe(cn, tmp, &rs_list, rs_list) { - size = sprintf(buf, "seq:%u\n", cn->seq); - send(fd, buf, size, 0); - } - size = sprintf(buf, "\nresent queue (len=%u):\n", queue_len(rs_queue)); + size = sprintf(buf, "resent queue (len=%u):\n", queue_len(rs_queue)); send(fd, buf, size, 0); - queue_iterate(rs_queue, &fd, debug_rs_queue_dump_step); + queue_iterate(rs_queue, &fd, rs_queue_dump); } static int ftfw_local(int fd, int type, void *data) @@ -257,87 +254,84 @@ static int ftfw_local(int fd, int type, void *data) return ret; } -static int rs_queue_to_tx(void *data1, const void *data2) +static int rs_queue_to_tx(struct queue_node *n, const void *data) { - struct nethdr_ack *net = data1; - const struct nethdr_ack *nack = data2; - - if (before(net->seq, nack->from)) - return 0; /* continue */ - else if (after(net->seq, nack->to)) - return 1; /* break */ - - dp("rs_queue_to_tx sq: %u fl:%u len:%u\n", - net->seq, net->flags, net->len); - queue_add(tx_queue, net, net->len); - write_evfd(STATE_SYNC(evfd)); - queue_del(rs_queue, net); - return 0; -} + const struct nethdr_ack *nack = data; -static int rs_queue_empty(void *data1, const void *data2) -{ - struct nethdr *net = data1; - const struct nethdr_ack *h = data2; + switch(n->type) { + case Q_ELEM_CTL: { + struct nethdr_ack *net = queue_node_data(n); - if (h == NULL) { - dp("inconditional remove from queue (seq=%u)\n", net->seq); - queue_del(rs_queue, data1); - return 0; + if (before(net->seq, nack->from)) + return 0; /* continue */ + else if (after(net->seq, nack->to)) + return 1; /* break */ + + dp("rs_queue_to_tx sq: %u fl:%u len:%u\n", + net->seq, net->flags, net->len); + + queue_del(n); + queue_add(tx_queue, n); + break; } + case Q_ELEM_OBJ: { + struct cache_ftfw *cn; - if (before(net->seq, h->from)) - return 0; /* continue */ - else if (after(net->seq, h->to)) - return 1; /* break */ + cn = (struct cache_ftfw *) n; + if (before(cn->seq, nack->from)) + return 0; + else if (after(cn->seq, nack->to)) + return 1; - dp("remove from queue (seq=%u)\n", net->seq); - queue_del(rs_queue, data1); + dp("resending nack'ed (oldseq=%u)\n", cn->seq); + + queue_del(n); + queue_add(tx_queue, n); + break; + } + } return 0; } -static void rs_list_to_tx(struct cache *c, unsigned int from, unsigned int to) +static int rs_queue_empty(struct queue_node *n, const void *data) { - struct cache_ftfw *cn, *tmp; + const struct nethdr_ack *h = data; - list_for_each_entry_safe(cn, tmp, &rs_list, rs_list) { - struct cache_object *obj;; - - obj = cache_data_get_object(STATE_SYNC(internal), cn); - if (before(cn->seq, from)) - continue; - else if (after(cn->seq, to)) - break; + if (h == NULL) { + dp("inconditional remove from queue (seq=%u)\n", net->seq); + queue_del(n); + return 0; + } - dp("resending nack'ed (oldseq=%u)\n", cn->seq); - list_del_init(&cn->rs_list); - rs_list_len--; - /* we received a request for resync before this nack? */ - if (list_empty(&cn->tx_list)) { - list_add_tail(&cn->tx_list, &tx_list); - tx_list_len++; - } - write_evfd(STATE_SYNC(evfd)); - } -} + switch(n->type) { + case Q_ELEM_CTL: { + struct nethdr_ack *net = queue_node_data(n); -static void rs_list_empty(struct cache *c, unsigned int from, unsigned int to) -{ - struct cache_ftfw *cn, *tmp; + if (before(net->seq, h->from)) + return 0; /* continue */ + else if (after(net->seq, h->to)) + return 1; /* break */ - list_for_each_entry_safe(cn, tmp, &rs_list, rs_list) { - struct cache_object *obj; + dp("remove from queue (seq=%u)\n", net->seq); + queue_del(n); + queue_object_free((struct queue_object *)n); + break; + } + case Q_ELEM_OBJ: { + struct cache_ftfw *cn; - obj = cache_data_get_object(STATE_SYNC(internal), cn); - if (before(cn->seq, from)) - continue; - else if (after(cn->seq, to)) - break; + cn = (struct cache_ftfw *) n; + if (before(cn->seq, h->from)) + return 0; + else if (after(cn->seq, h->to)) + return 1; dp("queue: deleting from queue (seq=%u)\n", cn->seq); - list_del_init(&cn->rs_list); - rs_list_len--; + queue_del(n); + break; } + } + return 0; } static int digest_msg(const struct nethdr *net) @@ -351,7 +345,6 @@ static int digest_msg(const struct nethdr *net) if (before(h->to, h->from)) return MSG_BAD; - rs_list_empty(STATE_SYNC(internal), h->from, h->to); queue_iterate(rs_queue, h, rs_queue_empty); return MSG_CTL; @@ -361,7 +354,6 @@ static int digest_msg(const struct nethdr *net) if (before(nack->to, nack->from)) return MSG_BAD; - rs_list_to_tx(STATE_SYNC(internal), nack->from, nack->to); queue_iterate(rs_queue, nack, rs_queue_to_tx); return MSG_CTL; @@ -409,7 +401,6 @@ static int ftfw_recv(const struct nethdr *net) * know anything about that data, we are unreliable until * the helloing finishes */ queue_iterate(rs_queue, NULL, rs_queue_empty); - rs_list_empty(STATE_SYNC(internal), 0, ~0U); goto bypass; } @@ -480,10 +471,8 @@ static void ftfw_send(struct nethdr *net, struct cache_object *obj) cn = (struct cache_ftfw *) cache_get_extra(STATE_SYNC(internal), obj); - if (!list_empty(&cn->rs_list)) { - list_del_init(&cn->rs_list); - rs_list_len--; - } + if (queue_in(rs_queue, &cn->qnode)) + queue_del(&cn->qnode); switch(hello_state) { case HELLO_INIT: @@ -500,82 +489,77 @@ static void ftfw_send(struct nethdr *net, struct cache_object *obj) } cn->seq = ntohl(net->seq); - list_add_tail(&cn->rs_list, &rs_list); - rs_list_len++; + queue_add(rs_queue, &cn->qnode); break; } } -static int tx_queue_xmit(void *data1, const void *data2) +static int tx_queue_xmit(struct queue_node *n, const void *data) { - struct nethdr *net = data1; - - if (IS_ACK(net) || IS_NACK(net) || IS_RESYNC(net)) { - nethdr_set_ack(net); - } else if (IS_ALIVE(net)) { - nethdr_set_ctl(net); - } else { - STATE_SYNC(error).msg_snd_malformed++; - return 0; - } - HDR_HOST2NETWORK(net); - - dp("tx_queue sq: %u fl:%u len:%u\n", - ntohl(net->seq), net->flags, ntohs(net->len)); - - mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); - HDR_NETWORK2HOST(net); + switch(n->type) { + case Q_ELEM_CTL: { + struct nethdr *net = queue_node_data(n); + + if (IS_ACK(net) || IS_NACK(net) || IS_RESYNC(net)) { + nethdr_set_ack(net); + } else if (IS_ALIVE(net)) { + nethdr_set_ctl(net); + } else { + STATE_SYNC(error).msg_snd_malformed++; + return 0; + } + HDR_HOST2NETWORK(net); - if (IS_ACK(net) || IS_NACK(net) || IS_RESYNC(net)) - queue_add(rs_queue, net, net->len); + dp("tx_queue sq: %u fl:%u len:%u\n", + ntohl(net->seq), net->flags, ntohs(net->len)); - queue_del(tx_queue, net); + mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); + HDR_NETWORK2HOST(net); - return 0; -} - -static int tx_list_xmit(struct list_head *i, struct cache_object *obj, int type) -{ - int ret; - struct nethdr *net = BUILD_NETMSG(obj->ct, type); + queue_del(n); + if (IS_ACK(net) || IS_NACK(net) || IS_RESYNC(net)) + queue_add(rs_queue, n); + else + queue_object_free((struct queue_object *)n); + break; + } + case Q_ELEM_OBJ: { + struct cache_ftfw *cn; + struct cache_object *obj; + int type; + struct nethdr *net; - dp("tx_list sq: %u fl:%u len:%u\n", - ntohl(net->seq), net->flags, ntohs(net->len)); + cn = (struct cache_ftfw *)n; + obj = cache_data_get_object(STATE_SYNC(internal), cn); + type = object_status_to_network_type(obj->status); + net = BUILD_NETMSG(obj->ct, type); - list_del_init(i); - tx_list_len--; + dp("tx_list sq: %u fl:%u len:%u\n", + ntohl(net->seq), net->flags, ntohs(net->len)); - ret = mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); - ftfw_send(net, obj); + queue_del(n); + mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); + ftfw_send(net, obj); + break; + } + } - return ret; + return 0; } -static void ftfw_run(void) +static void ftfw_run(fd_set *readfds) { - struct cache_ftfw *cn, *tmp; - - /* send messages in the tx_queue */ - queue_iterate(tx_queue, NULL, tx_queue_xmit); - - /* send conntracks in the tx_list */ - list_for_each_entry_safe(cn, tmp, &tx_list, tx_list) { - struct cache_object *obj; - - obj = cache_data_get_object(STATE_SYNC(internal), cn); - if (alarm_pending(&obj->alarm)) - tx_list_xmit(&cn->tx_list, obj, NET_T_STATE_DEL); - else - tx_list_xmit(&cn->tx_list, obj, NET_T_STATE_UPD); + if (FD_ISSET(queue_get_eventfd(tx_queue), readfds)) { + queue_iterate(tx_queue, NULL, tx_queue_xmit); + add_alarm(&alive_alarm, 1, 0); + dp("tx_queue_len:%u rs_queue_len:%u\n", + queue_len(tx_queue), queue_len(rs_queue)); } +} - /* reset alive alarm */ - add_alarm(&alive_alarm, 1, 0); - - dp("tx_list_len:%u tx_queue_len:%u " - "rs_list_len: %u rs_queue_len:%u\n", - tx_list_len, queue_len(tx_queue), - rs_list_len, queue_len(rs_queue)); +static int ftfw_register_fds(struct fds *fds) +{ + return register_fd(queue_get_eventfd(tx_queue), fds); } struct sync_mode sync_ftfw = { @@ -588,4 +572,5 @@ struct sync_mode sync_ftfw = { .recv = ftfw_recv, .send = ftfw_send, .run = ftfw_run, + .register_fds = ftfw_register_fds, }; diff --git a/src/sync-mode.c b/src/sync-mode.c index 368984f..711f71b 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -242,12 +242,6 @@ static int init_sync(void) return -1; } - STATE_SYNC(evfd) = create_evfd(); - if (STATE_SYNC(evfd) == NULL) { - dlog(LOG_ERR, "cannot open evfd"); - return -1; - } - /* initialization of multicast sequence generation */ STATE_SYNC(last_seq_sent) = time(NULL); @@ -259,7 +253,10 @@ static int register_fds_sync(struct fds *fds) if (register_fd(STATE_SYNC(mcast_server->fd), fds) == -1) return -1; - return register_fd(get_read_evfd(STATE_SYNC(evfd)), fds); + if (STATE_SYNC(sync)->register_fds) + return STATE_SYNC(sync)->register_fds(fds); + + return 0; } static void run_sync(fd_set *readfds) @@ -268,11 +265,8 @@ static void run_sync(fd_set *readfds) if (FD_ISSET(STATE_SYNC(mcast_server->fd), readfds)) mcast_handler(); - if (FD_ISSET(get_read_evfd(STATE_SYNC(evfd)), readfds) && - STATE_SYNC(sync)->run) { - read_evfd(STATE_SYNC(evfd)); - STATE_SYNC(sync)->run(); - } + if (STATE_SYNC(sync)->run) + STATE_SYNC(sync)->run(readfds); /* flush pending messages */ mcast_buffered_pending_netmsg(STATE_SYNC(mcast_client)); @@ -286,8 +280,6 @@ static void kill_sync(void) mcast_server_destroy(STATE_SYNC(mcast_server)); mcast_client_destroy(STATE_SYNC(mcast_client)); - destroy_evfd(STATE_SYNC(evfd)); - mcast_buffered_destroy(); if (STATE_SYNC(sync)->kill) diff --git a/src/sync-notrack.c b/src/sync-notrack.c index 2d3783e..40cc199 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -23,32 +23,26 @@ #include "network.h" #include "log.h" #include "cache.h" -#include "event.h" +#include "fds.h" #include -static LIST_HEAD(tx_list); -static unsigned int tx_list_len; static struct queue *tx_queue; struct cache_notrack { - struct list_head tx_list; + struct queue_node qnode; }; static void cache_notrack_add(struct cache_object *obj, void *data) { struct cache_notrack *cn = data; - INIT_LIST_HEAD(&cn->tx_list); + queue_node_init(&cn->qnode, Q_ELEM_OBJ); } static void cache_notrack_del(struct cache_object *obj, void *data) { struct cache_notrack *cn = data; - - if (!list_empty(&cn->tx_list)) { - list_del(&cn->tx_list); - tx_list_len--; - } + queue_del(&cn->qnode); } static struct cache_extra cache_notrack_extra = { @@ -59,20 +53,25 @@ static struct cache_extra cache_notrack_extra = { static void tx_queue_add_ctlmsg(uint32_t flags, uint32_t from, uint32_t to) { - struct nethdr_ack ack = { - .type = NET_T_CTL, - .flags = flags, - .from = from, - .to = to, - }; - - queue_add(tx_queue, &ack, NETHDR_ACK_SIZ); - write_evfd(STATE_SYNC(evfd)); + struct queue_object *qobj; + struct nethdr_ack *ack; + + qobj = queue_object_new(Q_ELEM_CTL, sizeof(struct nethdr_ack)); + if (qobj == NULL) + return; + + ack = (struct nethdr_ack *)qobj->data; + ack->type = NET_T_CTL; + ack->flags = flags; + ack->from = from; + ack->to = to; + + queue_add(tx_queue, &qobj->qnode); } static int notrack_init(void) { - tx_queue = queue_create(~0U); + tx_queue = queue_create(INT_MAX, QUEUE_F_EVFD); if (tx_queue == NULL) { dlog(LOG_ERR, "cannot create tx queue"); return -1; @@ -90,16 +89,7 @@ static int do_cache_to_tx(void *data1, void *data2) { struct cache_object *obj = data2; struct cache_notrack *cn = cache_get_extra(STATE_SYNC(internal), obj); - - if (!list_empty(&cn->tx_list)) - return 0; - - /* add to tx list */ - list_add_tail(&cn->tx_list, &tx_list); - tx_list_len++; - - write_evfd(STATE_SYNC(evfd)); - + queue_add(tx_queue, &cn->qnode); return 0; } @@ -152,44 +142,49 @@ static int notrack_recv(const struct nethdr *net) return ret; } -static int tx_queue_xmit(void *data1, const void *data2) +static int tx_queue_xmit(struct queue_node *n, const void *data2) { - struct nethdr *net = data1; - nethdr_set_ack(net); - HDR_HOST2NETWORK(net); - mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); - queue_del(tx_queue, net); + switch (n->type) { + case Q_ELEM_CTL: { + struct nethdr *net = queue_node_data(n); + if (IS_RESYNC(net)) + nethdr_set_ack(net); + else + nethdr_set_ctl(net); + HDR_HOST2NETWORK(net); + mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); + queue_del(n); + queue_object_free((struct queue_object *)n); + break; + } + case Q_ELEM_OBJ: { + struct cache_ftfw *cn; + struct cache_object *obj; + int type; + struct nethdr *net; + + cn = (struct cache_ftfw *)n; + obj = cache_data_get_object(STATE_SYNC(internal), cn); + type = object_status_to_network_type(obj->status);; + net = BUILD_NETMSG(obj->ct, type); + mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); + queue_del(n); + break; + } + } return 0; } -static int tx_list_xmit(struct list_head *i, struct cache_object *obj, int type) +static void notrack_run(fd_set *readfds) { - int ret; - struct nethdr *net = BUILD_NETMSG(obj->ct, type); - - list_del_init(i); - tx_list_len--; - - ret = mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); - - return ret; + if (FD_ISSET(queue_get_eventfd(tx_queue), readfds)) + queue_iterate(tx_queue, NULL, tx_queue_xmit); } -static void notrack_run(void) +static int notrack_register_fds(struct fds *fds) { - struct cache_notrack *cn, *tmp; - - /* send messages in the tx_queue */ - queue_iterate(tx_queue, NULL, tx_queue_xmit); - - /* send conntracks in the tx_list */ - list_for_each_entry_safe(cn, tmp, &tx_list, tx_list) { - struct cache_object *obj; - - obj = cache_data_get_object(STATE_SYNC(internal), cn); - tx_list_xmit(&cn->tx_list, obj, NET_T_STATE_UPD); - } + return register_fd(queue_get_eventfd(tx_queue), fds); } struct sync_mode sync_notrack = { @@ -201,4 +196,5 @@ struct sync_mode sync_notrack = { .local = notrack_local, .recv = notrack_recv, .run = notrack_run, + .register_fds = notrack_register_fds, }; -- cgit v1.2.3 From 786f37040cdcb64b24eb0b437307ed5e208f717f Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 17 Jan 2009 17:54:57 +0100 Subject: sync: add generic tx_queue for all synchronization modes This patch adds a generic tx queue for all synchronization modes. Signed-off-by: Pablo Neira Ayuso --- include/conntrackd.h | 1 + include/sync.h | 3 +-- src/sync-ftfw.c | 37 +++++++++++-------------------------- src/sync-mode.c | 16 ++++++++++++---- src/sync-notrack.c | 37 +++++-------------------------------- 5 files changed, 30 insertions(+), 64 deletions(-) (limited to 'src/sync-notrack.c') diff --git a/include/conntrackd.h b/include/conntrackd.h index 8cb520d..3637e2c 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -150,6 +150,7 @@ struct ct_sync_state { struct mcast_sock *mcast_server; /* multicast socket: incoming */ struct mcast_sock *mcast_client; /* multicast socket: outgoing */ + struct queue *tx_queue; struct sync_mode *sync; /* sync mode */ diff --git a/include/sync.h b/include/sync.h index 9a9540c..bced1cc 100644 --- a/include/sync.h +++ b/include/sync.h @@ -18,8 +18,7 @@ struct sync_mode { int (*local)(int fd, int type, void *data); int (*recv)(const struct nethdr *net); void (*send)(struct nethdr *net, struct cache_object *obj); - void (*run)(fd_set *readfds); - int (*register_fds)(struct fds *fds); + void (*xmit)(void); }; extern struct sync_mode sync_alarm; diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 565a4bc..d544a7b 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -34,7 +34,6 @@ #define dp(...) #endif -struct queue *tx_queue; struct queue *rs_queue; static uint32_t exp_seq; static uint32_t window; @@ -108,7 +107,7 @@ static void tx_queue_add_ctlmsg(uint32_t flags, uint32_t from, uint32_t to) ack->from = from; ack->to = to; - queue_add(tx_queue, &qobj->qnode); + queue_add(STATE_SYNC(tx_queue), &qobj->qnode); } static void tx_queue_add_ctlmsg2(uint32_t flags) @@ -124,7 +123,7 @@ static void tx_queue_add_ctlmsg2(uint32_t flags) ctl->type = NET_T_CTL; ctl->flags = flags; - queue_add(tx_queue, &qobj->qnode); + queue_add(STATE_SYNC(tx_queue), &qobj->qnode); } /* this function is called from the alarm framework */ @@ -144,11 +143,6 @@ static void do_alive_alarm(struct alarm_block *a, void *data) static int ftfw_init(void) { - tx_queue = queue_create(INT_MAX, QUEUE_F_EVFD); - if (tx_queue == NULL) { - dlog(LOG_ERR, "cannot create tx queue"); - return -1; - } rs_queue = queue_create(INT_MAX, 0); if (rs_queue == NULL) { dlog(LOG_ERR, "cannot create rs queue"); @@ -167,7 +161,6 @@ static int ftfw_init(void) static void ftfw_kill(void) { queue_destroy(rs_queue); - queue_destroy(tx_queue); } static int do_cache_to_tx(void *data1, void *data2) @@ -178,7 +171,7 @@ static int do_cache_to_tx(void *data1, void *data2) if (queue_in(rs_queue, &cn->qnode)) queue_del(&cn->qnode); - queue_add(tx_queue, &cn->qnode); + queue_add(STATE_SYNC(tx_queue), &cn->qnode); return 0; } @@ -259,7 +252,7 @@ static int rs_queue_to_tx(struct queue_node *n, const void *data) net->seq, net->flags, net->len); queue_del(n); - queue_add(tx_queue, n); + queue_add(STATE_SYNC(tx_queue), n); break; } case Q_ELEM_OBJ: { @@ -274,7 +267,7 @@ static int rs_queue_to_tx(struct queue_node *n, const void *data) dp("resending nack'ed (oldseq=%u)\n", cn->seq); queue_del(n); - queue_add(tx_queue, n); + queue_add(STATE_SYNC(tx_queue), n); break; } } @@ -526,19 +519,12 @@ static int tx_queue_xmit(struct queue_node *n, const void *data) return 0; } -static void ftfw_run(fd_set *readfds) +static void ftfw_xmit(void) { - if (FD_ISSET(queue_get_eventfd(tx_queue), readfds)) { - queue_iterate(tx_queue, NULL, tx_queue_xmit); - add_alarm(&alive_alarm, 1, 0); - dp("tx_queue_len:%u rs_queue_len:%u\n", - queue_len(tx_queue), queue_len(rs_queue)); - } -} - -static int ftfw_register_fds(struct fds *fds) -{ - return register_fd(queue_get_eventfd(tx_queue), fds); + queue_iterate(STATE_SYNC(tx_queue), NULL, tx_queue_xmit); + add_alarm(&alive_alarm, ALIVE_INT, 0); + dp("tx_queue_len:%u rs_queue_len:%u\n", + queue_len(tx_queue), queue_len(rs_queue)); } struct sync_mode sync_ftfw = { @@ -550,6 +536,5 @@ struct sync_mode sync_ftfw = { .local = ftfw_local, .recv = ftfw_recv, .send = ftfw_send, - .run = ftfw_run, - .register_fds = ftfw_register_fds, + .xmit = ftfw_xmit, }; diff --git a/src/sync-mode.c b/src/sync-mode.c index 711f71b..5ae9062 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -26,6 +26,7 @@ #include "fds.h" #include "event.h" #include "debug.h" +#include "queue.h" #include #include @@ -242,6 +243,12 @@ static int init_sync(void) return -1; } + STATE_SYNC(tx_queue) = queue_create(INT_MAX, QUEUE_F_EVFD); + if (STATE_SYNC(tx_queue) == NULL) { + dlog(LOG_ERR, "cannot create tx queue"); + return -1; + } + /* initialization of multicast sequence generation */ STATE_SYNC(last_seq_sent) = time(NULL); @@ -253,8 +260,8 @@ static int register_fds_sync(struct fds *fds) if (register_fd(STATE_SYNC(mcast_server->fd), fds) == -1) return -1; - if (STATE_SYNC(sync)->register_fds) - return STATE_SYNC(sync)->register_fds(fds); + if (register_fd(queue_get_eventfd(STATE_SYNC(tx_queue)), fds) == -1) + return -1; return 0; } @@ -265,8 +272,8 @@ static void run_sync(fd_set *readfds) if (FD_ISSET(STATE_SYNC(mcast_server->fd), readfds)) mcast_handler(); - if (STATE_SYNC(sync)->run) - STATE_SYNC(sync)->run(readfds); + if (FD_ISSET(queue_get_eventfd(STATE_SYNC(tx_queue)), readfds)) + STATE_SYNC(sync)->xmit(); /* flush pending messages */ mcast_buffered_pending_netmsg(STATE_SYNC(mcast_client)); @@ -281,6 +288,7 @@ static void kill_sync(void) mcast_client_destroy(STATE_SYNC(mcast_client)); mcast_buffered_destroy(); + queue_destroy(STATE_SYNC(tx_queue)); if (STATE_SYNC(sync)->kill) STATE_SYNC(sync)->kill(); diff --git a/src/sync-notrack.c b/src/sync-notrack.c index 40cc199..4ded298 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -27,8 +27,6 @@ #include -static struct queue *tx_queue; - struct cache_notrack { struct queue_node qnode; }; @@ -66,30 +64,14 @@ static void tx_queue_add_ctlmsg(uint32_t flags, uint32_t from, uint32_t to) ack->from = from; ack->to = to; - queue_add(tx_queue, &qobj->qnode); -} - -static int notrack_init(void) -{ - tx_queue = queue_create(INT_MAX, QUEUE_F_EVFD); - if (tx_queue == NULL) { - dlog(LOG_ERR, "cannot create tx queue"); - return -1; - } - - return 0; -} - -static void notrack_kill(void) -{ - queue_destroy(tx_queue); + queue_add(STATE_SYNC(tx_queue), &qobj->qnode); } static int do_cache_to_tx(void *data1, void *data2) { struct cache_object *obj = data2; struct cache_notrack *cn = cache_get_extra(STATE_SYNC(internal), obj); - queue_add(tx_queue, &cn->qnode); + queue_add(STATE_SYNC(tx_queue), &cn->qnode); return 0; } @@ -176,25 +158,16 @@ static int tx_queue_xmit(struct queue_node *n, const void *data2) return 0; } -static void notrack_run(fd_set *readfds) -{ - if (FD_ISSET(queue_get_eventfd(tx_queue), readfds)) - queue_iterate(tx_queue, NULL, tx_queue_xmit); -} - -static int notrack_register_fds(struct fds *fds) +static void notrack_xmit(void) { - return register_fd(queue_get_eventfd(tx_queue), fds); + queue_iterate(STATE_SYNC(tx_queue), NULL, tx_queue_xmit); } struct sync_mode sync_notrack = { .internal_cache_flags = LIFETIME, .external_cache_flags = LIFETIME, .internal_cache_extra = &cache_notrack_extra, - .init = notrack_init, - .kill = notrack_kill, .local = notrack_local, .recv = notrack_recv, - .run = notrack_run, - .register_fds = notrack_register_fds, + .xmit = notrack_xmit, }; -- cgit v1.2.3 From b1d00262f999a597fa24af3298195db9cf52b790 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 17 Jan 2009 18:03:50 +0100 Subject: sync: enqueue state updates to tx_queue With this patch, all the states updates are enqueued in the tx_queue. Thus, there's a single output path. This patch adds a simple refcounting mechanism to note when an object is sitting in the txqueue. This patch also removes the alarm that is required by the ftfw approach. Signed-off-by: Pablo Neira Ayuso --- include/cache.h | 7 ++--- include/sync.h | 2 +- src/cache.c | 59 ++++++++++++++++++------------------------ src/sync-alarm.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++-------- src/sync-ftfw.c | 70 +++++++++++++++++++++++++------------------------- src/sync-mode.c | 23 ++++++++--------- src/sync-notrack.c | 12 ++++++++- 7 files changed, 152 insertions(+), 96 deletions(-) (limited to 'src/sync-notrack.c') diff --git a/include/cache.h b/include/cache.h index fd8e05f..03b6822 100644 --- a/include/cache.h +++ b/include/cache.h @@ -4,7 +4,6 @@ #include #include #include "hash.h" -#include "alarm.h" /* cache features */ enum { @@ -36,7 +35,7 @@ struct cache_object { struct nf_conntrack *ct; struct cache *cache; int status; - struct alarm_block alarm; + int refcnt; char data[0]; }; @@ -106,12 +105,14 @@ void cache_destroy(struct cache *e); struct cache_object *cache_object_new(struct cache *c, struct nf_conntrack *ct); void cache_object_free(struct cache_object *obj); +void cache_object_get(struct cache_object *obj); +int cache_object_put(struct cache_object *obj); +void cache_object_set_status(struct cache_object *obj, int status); int cache_add(struct cache *c, struct cache_object *obj, int id); void cache_update(struct cache *c, struct cache_object *obj, int id, struct nf_conntrack *ct); struct cache_object *cache_update_force(struct cache *c, struct nf_conntrack *ct); void cache_del(struct cache *c, struct cache_object *obj); -int cache_del_timer(struct cache *c, struct cache_object *obj, int timeout); struct cache_object *cache_find(struct cache *c, struct nf_conntrack *ct, int *pos); void cache_stats(const struct cache *c, int fd); void cache_stats_extended(const struct cache *c, int fd); diff --git a/include/sync.h b/include/sync.h index bced1cc..51f8f5b 100644 --- a/include/sync.h +++ b/include/sync.h @@ -17,7 +17,7 @@ struct sync_mode { void (*kill)(void); int (*local)(int fd, int type, void *data); int (*recv)(const struct nethdr *net); - void (*send)(struct nethdr *net, struct cache_object *obj); + void (*enqueue)(struct cache_object *obj, int type); void (*xmit)(void); }; diff --git a/src/cache.c b/src/cache.c index c46498b..1e08a33 100644 --- a/src/cache.c +++ b/src/cache.c @@ -174,8 +174,6 @@ void cache_destroy(struct cache *c) free(c); } -static void __del_timeout(struct alarm_block *a, void *data); - struct cache_object *cache_object_new(struct cache *c, struct nf_conntrack *ct) { struct cache_object *obj; @@ -187,7 +185,6 @@ struct cache_object *cache_object_new(struct cache *c, struct nf_conntrack *ct) return NULL; } obj->cache = c; - init_alarm(&obj->alarm, obj, __del_timeout); if ((obj->ct = nfct_new()) == NULL) { free(obj); @@ -207,6 +204,30 @@ void cache_object_free(struct cache_object *obj) free(obj); } +int cache_object_put(struct cache_object *obj) +{ + if (--obj->refcnt == 0) { + cache_del(obj->cache, obj); + cache_object_free(obj); + return 1; + } + return 0; +} + +void cache_object_get(struct cache_object *obj) +{ + obj->refcnt++; +} + +void cache_object_set_status(struct cache_object *obj, int status) +{ + if (status == C_OBJ_DEAD) { + obj->cache->stats.del_ok++; + obj->cache->stats.active--; + } + obj->status = status; +} + static int __add(struct cache *c, struct cache_object *obj, int id) { int ret; @@ -227,6 +248,7 @@ static int __add(struct cache *c, struct cache_object *obj, int id) c->stats.active++; obj->status = C_OBJ_NEW; + obj->refcnt++; return 0; } @@ -292,7 +314,6 @@ void cache_del(struct cache *c, struct cache_object *obj) c->stats.del_ok++; c->stats.active--; } - del_alarm(&obj->alarm); __del(c, obj); } @@ -322,36 +343,6 @@ cache_update_force(struct cache *c, struct nf_conntrack *ct) return obj; } -static void __del_timeout(struct alarm_block *a, void *data) -{ - struct cache_object *obj = (struct cache_object *) data; - __del(obj->cache, obj); - cache_object_free(obj); -} - -int cache_del_timer(struct cache *c, struct cache_object *obj, int timeout) -{ - if (timeout <= 0) { - cache_del(c, obj); - cache_object_free(obj); - return 1; - } - if (obj->status != C_OBJ_DEAD) { - obj->status = C_OBJ_DEAD; - add_alarm(&obj->alarm, timeout, 0); - /* - * increase stats even if this entry was not really - * removed yet. We do not want to make people think - * that the replication protocol does not work - * properly. - */ - c->stats.del_ok++; - c->stats.active--; - return 1; - } - return 0; -} - struct cache_object * cache_find(struct cache *c, struct nf_conntrack *ct, int *id) { diff --git a/src/sync-alarm.c b/src/sync-alarm.c index 34937fe..a2f17ac 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -21,14 +21,21 @@ #include "network.h" #include "alarm.h" #include "cache.h" +#include "queue.h" #include "debug.h" #include #include +struct cache_alarm { + struct queue_node qnode; + struct alarm_block alarm; +}; + +static void alarm_enqueue(struct cache_object *obj, int query); + static void refresher(struct alarm_block *a, void *data) { - struct nethdr *net; struct cache_object *obj = data; debug_ct(obj->ct, "persistence update"); @@ -37,36 +44,37 @@ static void refresher(struct alarm_block *a, void *data) random() % CONFIG(refresh) + 1, ((random() % 5 + 1) * 200000) - 1); - net = BUILD_NETMSG(obj->ct, NET_T_STATE_UPD); - mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); + alarm_enqueue(obj, NET_T_STATE_UPD); } static void cache_alarm_add(struct cache_object *obj, void *data) { - struct alarm_block *a = data; + struct cache_alarm *ca = data; - init_alarm(a, obj, refresher); - add_alarm(a, + queue_node_init(&ca->qnode, Q_ELEM_OBJ); + init_alarm(&ca->alarm, obj, refresher); + add_alarm(&ca->alarm, random() % CONFIG(refresh) + 1, ((random() % 5 + 1) * 200000) - 1); } static void cache_alarm_update(struct cache_object *obj, void *data) { - struct alarm_block *a = data; - add_alarm(a, + struct cache_alarm *ca = data; + add_alarm(&ca->alarm, random() % CONFIG(refresh) + 1, ((random() % 5 + 1) * 200000) - 1); } static void cache_alarm_destroy(struct cache_object *obj, void *data) { - struct alarm_block *a = data; - del_alarm(a); + struct cache_alarm *ca = data; + queue_del(&ca->qnode); + del_alarm(&ca->alarm); } static struct cache_extra cache_alarm_extra = { - .size = sizeof(struct alarm_block), + .size = sizeof(struct cache_alarm), .add = cache_alarm_add, .update = cache_alarm_update, .destroy = cache_alarm_destroy @@ -102,9 +110,54 @@ static int alarm_recv(const struct nethdr *net) return 0; } +static void alarm_enqueue(struct cache_object *obj, int query) +{ + struct cache_alarm *ca = cache_get_extra(STATE_SYNC(internal), obj); + if (queue_add(STATE_SYNC(tx_queue), &ca->qnode)) + cache_object_get(obj); +} + +static int tx_queue_xmit(struct queue_node *n, const void *data) +{ + struct nethdr *net; + + queue_del(n); + + switch(n->type) { + case Q_ELEM_CTL: + net = queue_node_data(n); + nethdr_set_ctl(net); + HDR_HOST2NETWORK(net); + mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); + queue_object_free((struct queue_object *)n); + break; + case Q_ELEM_OBJ: { + struct cache_alarm *ca; + struct cache_object *obj; + int type; + + ca = (struct cache_alarm *)n; + obj = cache_data_get_object(STATE_SYNC(internal), ca); + type = object_status_to_network_type(obj->status); + net = BUILD_NETMSG(obj->ct, type); + mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); + cache_object_put(obj); + break; + } + } + return 0; +} + +static void alarm_xmit(void) +{ + queue_iterate(STATE_SYNC(tx_queue), NULL, tx_queue_xmit); +} + struct sync_mode sync_alarm = { .internal_cache_flags = LIFETIME, .external_cache_flags = TIMER | LIFETIME, .internal_cache_extra = &cache_alarm_extra, .recv = alarm_recv, + .enqueue = alarm_enqueue, + .xmit = alarm_xmit, }; diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index d544a7b..a287ecd 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -168,11 +168,13 @@ static int do_cache_to_tx(void *data1, void *data2) struct cache_object *obj = data2; struct cache_ftfw *cn = cache_get_extra(STATE_SYNC(internal), obj); - if (queue_in(rs_queue, &cn->qnode)) + if (queue_in(rs_queue, &cn->qnode)) { queue_del(&cn->qnode); - - queue_add(STATE_SYNC(tx_queue), &cn->qnode); - + queue_add(STATE_SYNC(tx_queue), &cn->qnode); + } else { + if (queue_add(STATE_SYNC(tx_queue), &cn->qnode)) + cache_object_get(obj); + } return 0; } @@ -278,16 +280,15 @@ static int rs_queue_empty(struct queue_node *n, const void *data) { const struct nethdr_ack *h = data; - if (h == NULL) { - dp("inconditional remove from queue (seq=%u)\n", net->seq); - queue_del(n); - return 0; - } - switch(n->type) { case Q_ELEM_CTL: { struct nethdr_ack *net = queue_node_data(n); + if (h == NULL) { + queue_del(n); + queue_object_free((struct queue_object *)n); + return 0; + } if (before(net->seq, h->from)) return 0; /* continue */ else if (after(net->seq, h->to)) @@ -300,8 +301,15 @@ static int rs_queue_empty(struct queue_node *n, const void *data) } case Q_ELEM_OBJ: { struct cache_ftfw *cn; + struct cache_object *obj; cn = (struct cache_ftfw *) n; + if (h == NULL) { + queue_del(n); + obj = cache_data_get_object(STATE_SYNC(internal), cn); + cache_object_put(obj); + return 0; + } if (before(cn->seq, h->from)) return 0; else if (after(cn->seq, h->to)) @@ -309,6 +317,8 @@ static int rs_queue_empty(struct queue_node *n, const void *data) dp("queue: deleting from queue (seq=%u)\n", cn->seq); queue_del(n); + obj = cache_data_get_object(STATE_SYNC(internal), cn); + cache_object_put(obj); break; } } @@ -441,28 +451,6 @@ out: return ret; } -static void ftfw_send(struct nethdr *net, struct cache_object *obj) -{ - struct cache_ftfw *cn; - - switch(net->type) { - case NET_T_STATE_NEW: - case NET_T_STATE_UPD: - case NET_T_STATE_DEL: - cn = (struct cache_ftfw *) - cache_get_extra(STATE_SYNC(internal), obj); - - if (queue_in(rs_queue, &cn->qnode)) - queue_del(&cn->qnode); - - nethdr_set_hello(net); - - cn->seq = ntohl(net->seq); - queue_add(rs_queue, &cn->qnode); - break; - } -} - static int tx_queue_xmit(struct queue_node *n, const void *data) { queue_del(n); @@ -511,7 +499,9 @@ static int tx_queue_xmit(struct queue_node *n, const void *data) ntohl(net->seq), net->flags, ntohs(net->len)); mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); - ftfw_send(net, obj); + cn->seq = ntohl(net->seq); + queue_add(rs_queue, &cn->qnode); + /* we release the object once we get the acknowlegment */ break; } } @@ -527,6 +517,18 @@ static void ftfw_xmit(void) queue_len(tx_queue), queue_len(rs_queue)); } +static void ftfw_enqueue(struct cache_object *obj, int type) +{ + struct cache_ftfw *cn = cache_get_extra(STATE_SYNC(internal), obj); + if (queue_in(rs_queue, &cn->qnode)) { + queue_del(&cn->qnode); + queue_add(STATE_SYNC(tx_queue), &cn->qnode); + } else { + if (queue_add(STATE_SYNC(tx_queue), &cn->qnode)) + cache_object_get(obj); + } +} + struct sync_mode sync_ftfw = { .internal_cache_flags = LIFETIME, .external_cache_flags = LIFETIME, @@ -535,6 +537,6 @@ struct sync_mode sync_ftfw = { .kill = ftfw_kill, .local = ftfw_local, .recv = ftfw_recv, - .send = ftfw_send, + .enqueue = ftfw_enqueue, .xmit = ftfw_xmit, }; diff --git a/src/sync-mode.c b/src/sync-mode.c index 5ae9062..00e2f7b 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -442,14 +442,7 @@ static void dump_sync(struct nf_conntrack *ct) static void mcast_send_sync(struct cache_object *obj, int query) { - struct nethdr *net; - - net = BUILD_NETMSG(obj->ct, query); - - if (STATE_SYNC(sync)->send) - STATE_SYNC(sync)->send(net, obj); - - mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); + STATE_SYNC(sync)->enqueue(obj, query); } static int purge_step(void *data1, void *data2) @@ -461,8 +454,11 @@ static int purge_step(void *data1, void *data2) ret = nfct_query(h, NFCT_Q_GET, obj->ct); if (ret == -1 && errno == ENOENT) { debug_ct(obj->ct, "overrun purge resync"); - mcast_send_sync(obj, NET_T_STATE_DEL); - cache_del_timer(STATE_SYNC(internal), obj, CONFIG(del_timeout)); + if (obj->status != C_OBJ_DEAD) { + cache_object_set_status(obj, C_OBJ_DEAD); + mcast_send_sync(obj, NET_T_STATE_DEL); + cache_object_put(obj); + } } return 0; @@ -552,8 +548,11 @@ static int event_destroy_sync(struct nf_conntrack *ct) debug_ct(ct, "can't destroy"); return 0; } - mcast_send_sync(obj, NET_T_STATE_DEL); - cache_del_timer(STATE_SYNC(internal), obj, CONFIG(del_timeout)); + if (obj->status != C_OBJ_DEAD) { + cache_object_set_status(obj, C_OBJ_DEAD); + mcast_send_sync(obj, NET_T_STATE_DEL); + cache_object_put(obj); + } debug_ct(ct, "internal destroy"); return 1; } diff --git a/src/sync-notrack.c b/src/sync-notrack.c index 4ded298..3b547ee 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -71,7 +71,8 @@ static int do_cache_to_tx(void *data1, void *data2) { struct cache_object *obj = data2; struct cache_notrack *cn = cache_get_extra(STATE_SYNC(internal), obj); - queue_add(STATE_SYNC(tx_queue), &cn->qnode); + if (queue_add(STATE_SYNC(tx_queue), &cn->qnode)) + cache_object_get(obj); return 0; } @@ -152,6 +153,7 @@ static int tx_queue_xmit(struct queue_node *n, const void *data2) mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); queue_del(n); + cache_object_put(obj); break; } } @@ -163,11 +165,19 @@ static void notrack_xmit(void) queue_iterate(STATE_SYNC(tx_queue), NULL, tx_queue_xmit); } +static void notrack_enqueue(struct cache_object *obj, int query) +{ + struct cache_notrack *cn = cache_get_extra(STATE_SYNC(internal), obj); + if (queue_add(STATE_SYNC(tx_queue), &cn->qnode)) + cache_object_get(obj); +} + struct sync_mode sync_notrack = { .internal_cache_flags = LIFETIME, .external_cache_flags = LIFETIME, .internal_cache_extra = &cache_notrack_extra, .local = notrack_local, .recv = notrack_recv, + .enqueue = notrack_enqueue, .xmit = notrack_xmit, }; -- cgit v1.2.3 From 1c9faf8c218bc7ff4617557383e4116f1adb11e5 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 25 Jan 2009 17:53:02 +0100 Subject: cache: move lifetime feature to main cache code The lifetime feature is used by all working modes, it is useful to know how long it has been an entry living in the cache. This patch moves the lifetime feature to the main caching code. Signed-off-by: Pablo Neira Ayuso --- include/cache.h | 6 ++--- src/Makefile.am | 2 +- src/cache.c | 3 ++- src/cache_iterators.c | 6 +++++ src/cache_lifetime.c | 65 --------------------------------------------------- src/stats-mode.c | 4 +--- src/sync-alarm.c | 4 ++-- src/sync-ftfw.c | 4 ++-- src/sync-notrack.c | 4 ++-- 9 files changed, 18 insertions(+), 80 deletions(-) delete mode 100644 src/cache_lifetime.c (limited to 'src/sync-notrack.c') diff --git a/include/cache.h b/include/cache.h index 5e96dd3..1fd3881 100644 --- a/include/cache.h +++ b/include/cache.h @@ -12,10 +12,7 @@ enum { TIMER_FEATURE = 0, TIMER = (1 << TIMER_FEATURE), - LIFETIME_FEATURE = 2, - LIFETIME = (1 << LIFETIME_FEATURE), - - WRITE_THROUGH_FEATURE = 3, + WRITE_THROUGH_FEATURE = 1, WRITE_THROUGH = (1 << WRITE_THROUGH_FEATURE), __CACHE_MAX_FEATURE @@ -36,6 +33,7 @@ struct cache_object { struct cache *cache; int status; int refcnt; + long lifetime; char data[0]; }; diff --git a/src/Makefile.am b/src/Makefile.am index 64ed2b5..8ba09e1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -14,7 +14,7 @@ conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c rbtree.c \ local.c log.c mcast.c netlink.c vector.c \ filter.c fds.c event.c \ cache.c cache_iterators.c \ - cache_lifetime.c cache_timer.c cache_wt.c \ + cache_timer.c cache_wt.c \ sync-mode.c sync-alarm.c sync-ftfw.c sync-notrack.c \ traffic_stats.c stats-mode.c \ network.c cidr.c \ diff --git a/src/cache.c b/src/cache.c index a5f37dd..71825e1 100644 --- a/src/cache.c +++ b/src/cache.c @@ -26,6 +26,7 @@ #include #include #include +#include static uint32_t __hash4(const struct nf_conntrack *ct, const struct hashtable *table) @@ -94,7 +95,6 @@ static int compare(const void *data1, const void *data2) struct cache_feature *cache_feature[CACHE_MAX_FEATURE] = { [TIMER_FEATURE] = &timer_feature, - [LIFETIME_FEATURE] = &lifetime_feature, [WRITE_THROUGH_FEATURE] = &writethrough_feature, }; @@ -249,6 +249,7 @@ static int __add(struct cache *c, struct cache_object *obj, int id) c->extra->add(obj, ((char *) obj) + c->extra_offset); c->stats.active++; + obj->lifetime = time(NULL); obj->status = C_OBJ_NEW; obj->refcnt++; return 0; diff --git a/src/cache_iterators.c b/src/cache_iterators.c index 4bf518a..3a1ec72 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -26,6 +26,7 @@ #include #include #include +#include struct __dump_container { int fd; @@ -75,6 +76,11 @@ static int do_dump(void *data1, struct hashtable_node *n) data += obj->cache->features[i]->size; } } + if (container->type != NFCT_O_XML) { + long tm = time(NULL); + size += sprintf(buf+size, " [active since %lds]", + tm - obj->lifetime); + } size += sprintf(buf+size, "\n"); if (send(container->fd, buf, size, 0) == -1) { if (errno != EPIPE) diff --git a/src/cache_lifetime.c b/src/cache_lifetime.c deleted file mode 100644 index 639d8c1..0000000 --- a/src/cache_lifetime.c +++ /dev/null @@ -1,65 +0,0 @@ -/* - * (C) 2006 by Pablo Neira Ayuso - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include "cache.h" -#include -#include -#include - -static void lifetime_add(struct cache_object *obj, void *data) -{ - long *lifetime = data; - struct timeval tv; - - gettimeofday(&tv, NULL); - - *lifetime = tv.tv_sec; -} - -static void lifetime_update(struct cache_object *obj, void *data) -{ -} - -static void lifetime_destroy(struct cache_object *obj, void *data) -{ -} - -static int lifetime_dump(struct cache_object *obj, - void *data, - char *buf, - int type) -{ - long *lifetime = data; - struct timeval tv; - - if (type == NFCT_O_XML) - return 0; - - gettimeofday(&tv, NULL); - - return sprintf(buf, " [active since %lds]", tv.tv_sec - *lifetime); -} - -struct cache_feature lifetime_feature = { - .size = sizeof(long), - .add = lifetime_add, - .update = lifetime_update, - .destroy = lifetime_destroy, - .dump = lifetime_dump -}; diff --git a/src/stats-mode.c b/src/stats-mode.c index b742c0c..226a6b8 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -37,9 +37,7 @@ static int init_stats(void) } memset(state.stats, 0, sizeof(struct ct_stats_state)); - STATE_STATS(cache) = cache_create("stats", - LIFETIME, - NULL); + STATE_STATS(cache) = cache_create("stats", NO_FEATURES, NULL); if (!STATE_STATS(cache)) { dlog(LOG_ERR, "can't allocate memory for the " "external cache"); diff --git a/src/sync-alarm.c b/src/sync-alarm.c index a2f17ac..1815447 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -154,8 +154,8 @@ static void alarm_xmit(void) } struct sync_mode sync_alarm = { - .internal_cache_flags = LIFETIME, - .external_cache_flags = TIMER | LIFETIME, + .internal_cache_flags = NO_FEATURES, + .external_cache_flags = TIMER, .internal_cache_extra = &cache_alarm_extra, .recv = alarm_recv, .enqueue = alarm_enqueue, diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index fd6c350..91ce25d 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -561,8 +561,8 @@ static void ftfw_enqueue(struct cache_object *obj, int type) } struct sync_mode sync_ftfw = { - .internal_cache_flags = LIFETIME, - .external_cache_flags = LIFETIME, + .internal_cache_flags = NO_FEATURES, + .external_cache_flags = NO_FEATURES, .internal_cache_extra = &cache_ftfw_extra, .init = ftfw_init, .kill = ftfw_kill, diff --git a/src/sync-notrack.c b/src/sync-notrack.c index 3b547ee..7bd4351 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -173,8 +173,8 @@ static void notrack_enqueue(struct cache_object *obj, int query) } struct sync_mode sync_notrack = { - .internal_cache_flags = LIFETIME, - .external_cache_flags = LIFETIME, + .internal_cache_flags = NO_FEATURES, + .external_cache_flags = NO_FEATURES, .internal_cache_extra = &cache_notrack_extra, .local = notrack_local, .recv = notrack_recv, -- cgit v1.2.3 From e83250c0381bbff232011b67c87a5b9f3a0de09a Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 20 Feb 2009 20:42:22 +0100 Subject: src: remove obsolete debug() and debug_ct() calls This patch removes debug() and debug_ct(), I haven't use the debugging information that these functions provide in years. Signed-off-by: Pablo Neira Ayuso --- src/cache_timer.c | 2 -- src/mcast.c | 17 ----------------- src/netlink.c | 1 - src/network.c | 1 - src/stats-mode.c | 8 ++------ src/sync-alarm.c | 3 --- src/sync-ftfw.c | 1 - src/sync-mode.c | 26 ++++++-------------------- src/sync-notrack.c | 1 - 9 files changed, 8 insertions(+), 52 deletions(-) (limited to 'src/sync-notrack.c') diff --git a/src/cache_timer.c b/src/cache_timer.c index a9e3e3d..5881236 100644 --- a/src/cache_timer.c +++ b/src/cache_timer.c @@ -19,7 +19,6 @@ #include "cache.h" #include "conntrackd.h" #include "alarm.h" -#include "debug.h" #include @@ -27,7 +26,6 @@ static void timeout(struct alarm_block *a, void *data) { struct cache_object *obj = data; - debug_ct(obj->ct, "expired timeout"); cache_del(obj->cache, obj); cache_object_free(obj); } diff --git a/src/mcast.c b/src/mcast.c index 70205d8..bc530d3 100644 --- a/src/mcast.c +++ b/src/mcast.c @@ -19,7 +19,6 @@ */ #include "mcast.h" -#include "debug.h" #include #include @@ -73,7 +72,6 @@ struct mcast_sock *mcast_server_create(struct mcast_conf *conf) } if ((m->fd = socket(conf->ipproto, SOCK_DGRAM, 0)) == -1) { - debug("mcast_sock_server_create:socket"); free(m); return NULL; } @@ -84,7 +82,6 @@ struct mcast_sock *mcast_server_create(struct mcast_conf *conf) strncpy(ifr.ifr_name, conf->iface, sizeof(ifr.ifr_name)); if (ioctl(m->fd, SIOCGIFMTU, &ifr) == -1) { - debug("ioctl"); close(m->fd); free(m); return NULL; @@ -94,7 +91,6 @@ struct mcast_sock *mcast_server_create(struct mcast_conf *conf) if (setsockopt(m->fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) { - debug("mcast_sock_server_create:setsockopt1"); close(m->fd); free(m); return NULL; @@ -109,7 +105,6 @@ struct mcast_sock *mcast_server_create(struct mcast_conf *conf) sizeof(int)) == -1) { /* not supported in linux kernel < 2.6.14 */ if (errno != ENOPROTOOPT) { - debug("mcast_sock_server_create:setsockopt2"); close(m->fd); free(m); return NULL; @@ -119,7 +114,6 @@ struct mcast_sock *mcast_server_create(struct mcast_conf *conf) getsockopt(m->fd, SOL_SOCKET, SO_RCVBUF, &conf->rcvbuf, &socklen); if (bind(m->fd, (struct sockaddr *) &m->addr, m->sockaddr_len) == -1) { - debug("mcast_sock_server_create:bind"); close(m->fd); free(m); return NULL; @@ -129,7 +123,6 @@ struct mcast_sock *mcast_server_create(struct mcast_conf *conf) case AF_INET: if (setsockopt(m->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq.ipv4, sizeof(mreq.ipv4)) < 0) { - debug("mcast_sock_server_create:setsockopt2"); close(m->fd); free(m); return NULL; @@ -138,7 +131,6 @@ struct mcast_sock *mcast_server_create(struct mcast_conf *conf) case AF_INET6: if (setsockopt(m->fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq.ipv6, sizeof(mreq.ipv6)) < 0) { - debug("mcast_sock_server_create:setsockopt2"); close(m->fd); free(m); return NULL; @@ -207,7 +199,6 @@ __mcast_client_create_ipv4(struct mcast_sock *m, struct mcast_conf *conf) if (setsockopt(m->fd, IPPROTO_IP, IP_MULTICAST_LOOP, &no, sizeof(int)) < 0) { - debug("mcast_sock_client_create:setsockopt2"); close(m->fd); return -1; } @@ -215,7 +206,6 @@ __mcast_client_create_ipv4(struct mcast_sock *m, struct mcast_conf *conf) if (setsockopt(m->fd, IPPROTO_IP, IP_MULTICAST_IF, &conf->ifa.interface_addr, sizeof(struct in_addr)) == -1) { - debug("mcast_sock_client_create:setsockopt3"); close(m->fd); return -1; } @@ -237,7 +227,6 @@ __mcast_client_create_ipv6(struct mcast_sock *m, struct mcast_conf *conf) if (setsockopt(m->fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &no, sizeof(int)) < 0) { - debug("mcast_sock_client_create:setsockopt2"); close(m->fd); return -1; } @@ -245,7 +234,6 @@ __mcast_client_create_ipv6(struct mcast_sock *m, struct mcast_conf *conf) if (setsockopt(m->fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &conf->ifa.interface_index6, sizeof(unsigned int)) == -1) { - debug("mcast_sock_client_create:setsockopt3"); close(m->fd); return -1; } @@ -267,14 +255,12 @@ struct mcast_sock *mcast_client_create(struct mcast_conf *conf) m->interface_idx = conf->interface_idx; if ((m->fd = socket(conf->ipproto, SOCK_DGRAM, 0)) == -1) { - debug("mcast_sock_client_create:socket"); free(m); return NULL; } if (setsockopt(m->fd, SOL_SOCKET, SO_NO_CHECK, &conf->checksum, sizeof(int)) == -1) { - debug("mcast_sock_client_create:setsockopt1"); close(m->fd); free(m); return NULL; @@ -289,7 +275,6 @@ struct mcast_sock *mcast_client_create(struct mcast_conf *conf) sizeof(int)) == -1) { /* not supported in linux kernel < 2.6.14 */ if (errno != ENOPROTOOPT) { - debug("mcast_sock_server_create:setsockopt2"); close(m->fd); free(m); return NULL; @@ -376,7 +361,6 @@ ssize_t mcast_send(struct mcast_sock *m, void *data, int size) (struct sockaddr *) &m->addr, m->sockaddr_len); if (ret == -1) { - debug("mcast_sock_send"); m->stats.error++; return ret; } @@ -399,7 +383,6 @@ ssize_t mcast_recv(struct mcast_sock *m, void *data, int size) (struct sockaddr *)&m->addr, &sin_size); if (ret == -1) { - debug("mcast_sock_recv"); m->stats.error++; return ret; } diff --git a/src/netlink.c b/src/netlink.c index 78cc466..ef729c1 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -20,7 +20,6 @@ #include "conntrackd.h" #include "filter.h" #include "log.h" -#include "debug.h" #include #include diff --git a/src/network.c b/src/network.c index f71aef0..690b28e 100644 --- a/src/network.c +++ b/src/network.c @@ -19,7 +19,6 @@ #include "conntrackd.h" #include "network.h" #include "log.h" -#include "debug.h" #include #include diff --git a/src/stats-mode.c b/src/stats-mode.c index 94fc45b..af1c136 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -18,7 +18,6 @@ #include "netlink.h" #include "traffic_stats.h" -#include "debug.h" #include "cache.h" #include "log.h" #include "conntrackd.h" @@ -97,8 +96,7 @@ static void dump_stats(struct nf_conntrack *ct) nfct_attr_unset(ct, ATTR_TIMEOUT); nfct_attr_unset(ct, ATTR_USE); - if (cache_update_force(STATE_STATS(cache), ct)) - debug_ct(ct, "resync entry"); + cache_update_force(STATE_STATS(cache), ct); } static int resync_stats(enum nf_conntrack_msg_type type, @@ -116,8 +114,7 @@ static int resync_stats(enum nf_conntrack_msg_type type, nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS); nfct_attr_unset(ct, ATTR_USE); - if (!cache_update_force(STATE_STATS(cache), ct)) - debug_ct(ct, "stats resync"); + cache_update_force(STATE_STATS(cache), ct); return NFCT_CB_CONTINUE; } @@ -129,7 +126,6 @@ static int purge_step(void *data1, void *data2) STATE(get_retval) = 0; nl_get_conntrack(STATE(get), obj->ct); /* modifies STATE(get_retval) */ if (!STATE(get_retval)) { - debug_ct(obj->ct, "purge stats"); cache_del(STATE_STATS(cache), obj); dlog_ct(STATE(stats_log), obj->ct, NFCT_O_PLAIN); cache_object_free(obj); diff --git a/src/sync-alarm.c b/src/sync-alarm.c index 1815447..a59ae11 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -22,7 +22,6 @@ #include "alarm.h" #include "cache.h" #include "queue.h" -#include "debug.h" #include #include @@ -38,8 +37,6 @@ static void refresher(struct alarm_block *a, void *data) { struct cache_object *obj = data; - debug_ct(obj->ct, "persistence update"); - add_alarm(a, random() % CONFIG(refresh) + 1, ((random() % 5 + 1) * 200000) - 1); diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 91ce25d..d608e5b 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -19,7 +19,6 @@ #include "conntrackd.h" #include "sync.h" #include "queue.h" -#include "debug.h" #include "network.h" #include "alarm.h" #include "log.h" diff --git a/src/sync-mode.c b/src/sync-mode.c index 02a5a46..d1a941b 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -25,7 +25,6 @@ #include "network.h" #include "fds.h" #include "event.h" -#include "debug.h" #include "queue.h" #include @@ -166,10 +165,6 @@ static void mcast_handler(struct mcast_sock *m, int if_idx) } } - debug("recv sq: %u fl:%u len:%u (rem:%d)\n", - ntohl(net->seq), net->flags, - ntohs(net->len), remain); - HDR_NETWORK2HOST(net); do_mcast_handler_step(if_idx, net, remain); @@ -531,8 +526,7 @@ static void dump_sync(struct nf_conntrack *ct) nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS); nfct_attr_unset(ct, ATTR_USE); - if (cache_update_force(STATE_SYNC(internal), ct)) - debug_ct(ct, "dump"); + cache_update_force(STATE_SYNC(internal), ct); } static int purge_step(void *data1, void *data2) @@ -542,7 +536,6 @@ static int purge_step(void *data1, void *data2) STATE(get_retval) = 0; nl_get_conntrack(STATE(get), obj->ct); /* modifies STATE(get_reval) */ if (!STATE(get_retval)) { - debug_ct(obj->ct, "purge resync"); if (obj->status != C_OBJ_DEAD) { cache_object_set_status(obj, C_OBJ_DEAD); mcast_send_sync(obj, NET_T_STATE_DEL); @@ -582,11 +575,9 @@ static int resync_sync(enum nf_conntrack_msg_type type, switch (obj->status) { case C_OBJ_NEW: - debug_ct(ct, "resync"); mcast_send_sync(obj, NET_T_STATE_NEW); break; case C_OBJ_ALIVE: - debug_ct(ct, "resync"); mcast_send_sync(obj, NET_T_STATE_UPD); break; } @@ -615,11 +606,9 @@ retry: return; } mcast_send_sync(obj, NET_T_STATE_NEW); - debug_ct(obj->ct, "internal new"); } else { cache_del(STATE_SYNC(internal), obj); cache_object_free(obj); - debug_ct(ct, "can't add"); goto retry; } } @@ -628,11 +617,10 @@ static void event_update_sync(struct nf_conntrack *ct) { struct cache_object *obj; - if ((obj = cache_update_force(STATE_SYNC(internal), ct)) == NULL) { - debug_ct(ct, "can't update"); + obj = cache_update_force(STATE_SYNC(internal), ct); + if (obj == NULL) return; - } - debug_ct(obj->ct, "internal update"); + mcast_send_sync(obj, NET_T_STATE_UPD); } @@ -642,16 +630,14 @@ static int event_destroy_sync(struct nf_conntrack *ct) int id; obj = cache_find(STATE_SYNC(internal), ct, &id); - if (obj == NULL) { - debug_ct(ct, "can't destroy"); + if (obj == NULL) return 0; - } + if (obj->status != C_OBJ_DEAD) { cache_object_set_status(obj, C_OBJ_DEAD); mcast_send_sync(obj, NET_T_STATE_DEL); cache_object_put(obj); } - debug_ct(ct, "internal destroy"); return 1; } diff --git a/src/sync-notrack.c b/src/sync-notrack.c index 7bd4351..57c3368 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -19,7 +19,6 @@ #include "conntrackd.h" #include "sync.h" #include "queue.h" -#include "debug.h" #include "network.h" #include "log.h" #include "cache.h" -- cgit v1.2.3 From 656d5ad7c69a5a7d356c6251743890f1eec0bb71 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 12 Mar 2009 21:09:27 +0100 Subject: sync-mode: add abstract layer to make daemon independent of multicast This patch reworks conntrackd to make it independent of the protocol used to propagate state-changes. This patch adds the channel layer abstraction, this layer allows you to add support for different protocols like unicast UDP or TIPC. Signed-off-by: Pablo Neira Ayuso --- include/Makefile.am | 2 +- include/channel.h | 95 +++++++++++++++++++++++++++ include/conntrackd.h | 10 +-- include/mcast.h | 26 ++------ include/network.h | 5 -- src/Makefile.am | 1 + src/channel.c | 180 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/channel_mcast.c | 123 +++++++++++++++++++++++++++++++++++ src/mcast.c | 169 +---------------------------------------------- src/multichannel.c | 110 +++++++++++++++++++++++++++++++ src/network.c | 61 ----------------- src/read_config_yy.y | 69 +++++++++++--------- src/sync-alarm.c | 4 +- src/sync-ftfw.c | 4 +- src/sync-mode.c | 82 +++++++++-------------- src/sync-notrack.c | 4 +- 16 files changed, 596 insertions(+), 349 deletions(-) create mode 100644 include/channel.h create mode 100644 src/channel.c create mode 100644 src/channel_mcast.c create mode 100644 src/multichannel.c (limited to 'src/sync-notrack.c') diff --git a/include/Makefile.am b/include/Makefile.am index c3f8904..0265620 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -3,5 +3,5 @@ noinst_HEADERS = alarm.h jhash.h cache.h linux_list.h linux_rbtree.h \ sync.h conntrackd.h local.h \ debug.h log.h hash.h mcast.h conntrack.h \ network.h filter.h queue.h vector.h cidr.h \ - traffic_stats.h netlink.h fds.h event.h bitops.h + traffic_stats.h netlink.h fds.h event.h bitops.h channel.h diff --git a/include/channel.h b/include/channel.h new file mode 100644 index 0000000..ac1a93c --- /dev/null +++ b/include/channel.h @@ -0,0 +1,95 @@ +#ifndef _CHANNEL_H_ +#define _CHANNEL_H_ + +#include "mcast.h" + +struct channel; +struct nethdr; + +enum { + CHANNEL_MCAST, + CHANNEL_MAX, +}; + +struct mcast_channel { + struct mcast_sock *client; + struct mcast_sock *server; +}; + +#define CHANNEL_F_DEFAULT (1 << 0) +#define CHANNEL_F_BUFFERED (1 << 1) +#define CHANNEL_F_MAX (1 << 2) + +union channel_type_conf { + struct mcast_conf mcast; +}; + +struct channel_conf { + int channel_type; + char channel_ifname[IFNAMSIZ]; + unsigned int channel_flags; + union channel_type_conf u; +}; + +struct nlif_handle; + +struct channel_ops { + void * (*open)(void *conf); + void (*close)(void *channel); + int (*send)(void *channel, const void *data, int len); + int (*recv)(void *channel, char *buf, int len); + int (*get_fd)(void *channel); + void (*stats)(struct channel *c, int fd); + void (*stats_extended)(struct channel *c, int active, + struct nlif_handle *h, int fd); +}; + +struct channel_buffer; + +struct channel { + int channel_type; + int channel_ifindex; + int channel_ifmtu; + unsigned int channel_flags; + struct channel_buffer *buffer; + struct channel_ops *ops; + void *data; +}; + +void channel_init(void); +struct channel *channel_open(struct channel_conf *conf); +void channel_close(struct channel *c); + +int channel_send(struct channel *c, const struct nethdr *net); +int channel_send_flush(struct channel *c); +int channel_recv(struct channel *c, char *buf, int size); + +int channel_get_fd(struct channel *c); +void channel_stats(struct channel *c, int fd); +void channel_stats_extended(struct channel *c, int active, + struct nlif_handle *h, int fd); + +#define MULTICHANNEL_MAX 4 + +struct multichannel { + int channel_num; + struct channel *channel[MULTICHANNEL_MAX]; + struct channel *current; +}; + +struct multichannel *multichannel_open(struct channel_conf *conf, int len); +void multichannel_close(struct multichannel *m); + +int multichannel_send(struct multichannel *c, const struct nethdr *net); +int multichannel_send_flush(struct multichannel *c); +int multichannel_recv(struct multichannel *c, char *buf, int size); + +void multichannel_stats(struct multichannel *m, int fd); +void multichannel_stats_extended(struct multichannel *m, + struct nlif_handle *h, int fd); + +int multichannel_get_ifindex(struct multichannel *m, int i); +int multichannel_get_current_ifindex(struct multichannel *m); +void multichannel_set_current_channel(struct multichannel *m, int i); + +#endif /* _CHANNEL_H_ */ diff --git a/include/conntrackd.h b/include/conntrackd.h index 536abc9..cfb1ac5 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -5,6 +5,7 @@ #include "local.h" #include "alarm.h" #include "filter.h" +#include "channel.h" #include #include @@ -71,9 +72,9 @@ struct ct_conf { int syslog_facility; char lockfile[FILENAME_MAXLEN]; int hashsize; /* hashtable size */ - int mcast_links; - int mcast_default_link; - struct mcast_conf mcast[MCAST_LINKS_MAX]; + int channel_num; + int channel_default; + struct channel_conf channel[MULTICHANNEL_MAX]; struct local_conf local; /* unix socket facilities */ int nice; int limit; @@ -163,8 +164,7 @@ struct ct_sync_state { struct cache *internal; /* internal events cache (netlink) */ struct cache *external; /* external events cache (mcast) */ - struct mcast_sock_multi *mcast_server; /* multicast incoming */ - struct mcast_sock_multi *mcast_client; /* multicast outgoing */ + struct multichannel *channel; struct nlif_handle *interface; struct queue *tx_queue; diff --git a/include/mcast.h b/include/mcast.h index 623f390..68d18e8 100644 --- a/include/mcast.h +++ b/include/mcast.h @@ -42,38 +42,22 @@ struct mcast_sock { struct mcast_stats stats; }; -#define MCAST_LINKS_MAX 4 - -struct mcast_sock_multi { - int num_links; - int max_mtu; - struct mcast_sock *current_link; - struct mcast_sock *multi[MCAST_LINKS_MAX]; -}; - struct mcast_sock *mcast_server_create(struct mcast_conf *conf); void mcast_server_destroy(struct mcast_sock *m); -struct mcast_sock_multi *mcast_server_create_multi(struct mcast_conf *conf, int conf_len); -void mcast_server_destroy_multi(struct mcast_sock_multi *m); struct mcast_sock *mcast_client_create(struct mcast_conf *conf); void mcast_client_destroy(struct mcast_sock *m); -struct mcast_sock_multi *mcast_client_create_multi(struct mcast_conf *conf, int conf_len); -void mcast_client_destroy_multi(struct mcast_sock_multi*m); ssize_t mcast_send(struct mcast_sock *m, void *data, int size); ssize_t mcast_recv(struct mcast_sock *m, void *data, int size); int mcast_get_fd(struct mcast_sock *m); -int mcast_get_ifidx(struct mcast_sock_multi *m, int i); -int mcast_get_current_ifidx(struct mcast_sock_multi *m); - -struct mcast_sock *mcast_get_current_link(struct mcast_sock_multi *m); -void mcast_set_current_link(struct mcast_sock_multi *m, int i); -void mcast_dump_stats(int fd, const struct mcast_sock_multi *s, const struct mcast_sock_multi *r); +int mcast_snprintf_stats(char *buf, size_t buflen, char *ifname, + struct mcast_stats *s, struct mcast_stats *r); -struct nlif_handle; +int mcast_snprintf_stats2(char *buf, size_t buflen, const char *ifname, + const char *status, int active, + struct mcast_stats *s, struct mcast_stats *r); -void mcast_dump_stats_extended(int fd, const struct mcast_sock_multi *s, const struct mcast_sock_multi *r, const struct nlif_handle *h); #endif diff --git a/include/network.h b/include/network.h index 29a6113..7019d7d 100644 --- a/include/network.h +++ b/include/network.h @@ -106,11 +106,6 @@ int mcast_track_is_seq_set(void); struct mcast_conf; -int mcast_buffered_init(int mtu); -void mcast_buffered_destroy(void); -int mcast_buffered_send_netmsg(struct mcast_sock_multi *m, const struct nethdr *net); -ssize_t mcast_buffered_pending_netmsg(struct mcast_sock_multi *m); - #define IS_DATA(x) (x->type <= NET_T_STATE_MAX && \ (x->flags & ~(NET_F_HELLO | NET_F_HELLO_BACK)) == 0) #define IS_ACK(x) (x->type == NET_T_CTL && x->flags & NET_F_ACK) diff --git a/src/Makefile.am b/src/Makefile.am index 8ba09e1..54cfda4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -19,6 +19,7 @@ conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c rbtree.c \ traffic_stats.c stats-mode.c \ network.c cidr.c \ build.c parse.c \ + channel.c multichannel.c channel_mcast.c \ read_config_yy.y read_config_lex.l # yacc and lex generate dirty code diff --git a/src/channel.c b/src/channel.c new file mode 100644 index 0000000..733fd03 --- /dev/null +++ b/src/channel.c @@ -0,0 +1,180 @@ +/* + * (C) 2009 by Pablo Neira Ayuso + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include + +#include "channel.h" +#include "network.h" + +static struct channel_ops *ops[CHANNEL_MAX]; +extern struct channel_ops channel_mcast; + +void channel_init(void) +{ + ops[CHANNEL_MCAST] = &channel_mcast; +} + +#define HEADERSIZ 28 /* IP header (20 bytes) + UDP header 8 (bytes) */ + +struct channel_buffer { + char *data; + int size; + int len; +}; + +static struct channel_buffer * +channel_buffer_open(int mtu) +{ + struct channel_buffer *b; + + b = calloc(sizeof(struct channel_buffer), 1); + if (b == NULL) + return NULL; + + b->size = mtu - HEADERSIZ; + + b->data = malloc(b->size); + if (b->data == NULL) { + free(b); + return NULL; + } + return b; +} + +static void +channel_buffer_close(struct channel_buffer *b) +{ + free(b->data); + free(b); +} + +struct channel * +channel_open(struct channel_conf *conf) +{ + struct channel *c; + struct ifreq ifr; + int fd; + + if (conf->channel_type >= CHANNEL_MAX) + return NULL; + if (!conf->channel_ifname[0]) + return NULL; + if (conf->channel_flags >= CHANNEL_F_MAX) + return NULL; + + c = calloc(sizeof(struct channel), 1); + if (c == NULL) + return NULL; + + c->channel_type = conf->channel_type; + + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd == -1) { + free(c); + return NULL; + } + strncpy(ifr.ifr_name, conf->channel_ifname, sizeof(ifr.ifr_name)); + + if (ioctl(fd, SIOCGIFMTU, &ifr) == -1) { + free(c); + return NULL; + } + close(fd); + c->channel_ifmtu = ifr.ifr_mtu; + + c->channel_ifindex = if_nametoindex(conf->channel_ifname); + if (c->channel_ifindex == 0) { + free(c); + return NULL; + } + c->ops = ops[conf->channel_type]; + + if (conf->channel_flags & CHANNEL_F_BUFFERED) { + c->buffer = channel_buffer_open(c->channel_ifmtu); + if (c->buffer == NULL) { + free(c); + return NULL; + } + } + c->channel_flags = conf->channel_flags; + + c->data = c->ops->open(&conf->u); + if (c->data == NULL) { + channel_buffer_close(c->buffer); + free(c); + return NULL; + } + return c; +} + +void +channel_close(struct channel *c) +{ + c->ops->close(c->data); + if (c->channel_flags & CHANNEL_F_BUFFERED) + channel_buffer_close(c->buffer); + free(c); +} + +int channel_send(struct channel *c, const struct nethdr *net) +{ + int ret = 0, len = ntohs(net->len); + + if (!(c->channel_flags & CHANNEL_F_BUFFERED)) { + c->ops->send(c->data, net, len); + return 1; + } +retry: + if (c->buffer->len + len < c->buffer->size) { + memcpy(c->buffer->data + c->buffer->len, net, len); + c->buffer->len += len; + } else { + c->ops->send(c->data, c->buffer->data, c->buffer->len); + ret = 1; + c->buffer->len = 0; + goto retry; + } + return ret; +} + +int channel_send_flush(struct channel *c) +{ + if (!(c->channel_flags & CHANNEL_F_BUFFERED) || c->buffer->len == 0) + return 0; + + c->ops->send(c->data, c->buffer->data, c->buffer->len); + c->buffer->len = 0; + return 1; +} + +int channel_recv(struct channel *c, char *buf, int size) +{ + return c->ops->recv(c->data, buf, size); +} + +int channel_get_fd(struct channel *c) +{ + return c->ops->get_fd(c->data); +} + +void channel_stats(struct channel *c, int fd) +{ + return c->ops->stats(c, fd); +} + +void channel_stats_extended(struct channel *c, int active, + struct nlif_handle *h, int fd) +{ + return c->ops->stats_extended(c, active, h, fd); +} diff --git a/src/channel_mcast.c b/src/channel_mcast.c new file mode 100644 index 0000000..898b194 --- /dev/null +++ b/src/channel_mcast.c @@ -0,0 +1,123 @@ +/* + * (C) 2009 by Pablo Neira Ayuso + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include + +#include "channel.h" +#include "mcast.h" + +static void +*channel_mcast_open(void *conf) +{ + struct mcast_channel *m; + struct mcast_conf *c = conf; + + m = calloc(sizeof(struct mcast_channel), 1); + if (m == NULL) + return NULL; + + m->client = mcast_client_create(c); + if (m->client == NULL) { + free(m); + return NULL; + } + + m->server = mcast_server_create(c); + if (m->server == NULL) { + mcast_client_destroy(m->client); + free(m); + return NULL; + } + return m; +} + +static int +channel_mcast_send(void *channel, const void *data, int len) +{ + struct mcast_channel *m = channel; + return mcast_send(m->client, data, len); +} + +static int +channel_mcast_recv(void *channel, char *buf, int size) +{ + struct mcast_channel *m = channel; + return mcast_recv(m->server, buf, size); +} + +static void +channel_mcast_close(void *channel) +{ + struct mcast_channel *m = channel; + mcast_client_destroy(m->client); + mcast_server_destroy(m->server); + free(m); +} + +static int +channel_mcast_get_fd(void *channel) +{ + struct mcast_channel *m = channel; + return mcast_get_fd(m->server); +} + +static void +channel_mcast_stats(struct channel *c, int fd) +{ + struct mcast_channel *m = c->data; + char ifname[IFNAMSIZ], buf[512]; + int size; + + if_indextoname(c->channel_ifindex, ifname); + size = mcast_snprintf_stats(buf, sizeof(buf), ifname, + &m->client->stats, &m->server->stats); + send(fd, buf, size, 0); +} + +static void +channel_mcast_stats_extended(struct channel *c, int active, + struct nlif_handle *h, int fd) +{ + struct mcast_channel *m = c->data; + char ifname[IFNAMSIZ], buf[512]; + const char *status; + unsigned int flags; + int size; + + if_indextoname(c->channel_ifindex, ifname); + nlif_get_ifflags(h, c->channel_ifindex, &flags); + /* + * IFF_UP shows administrative status + * IFF_RUNNING shows carrier status + */ + if (flags & IFF_UP) { + if (!(flags & IFF_RUNNING)) + status = "NO-CARRIER"; + else + status = "RUNNING"; + } else { + status = "DOWN"; + } + size = mcast_snprintf_stats2(buf, sizeof(buf), + ifname, status, active, + &m->client->stats, + &m->server->stats); + send(fd, buf, size, 0); +} + +struct channel_ops channel_mcast = { + .open = channel_mcast_open, + .close = channel_mcast_close, + .send = channel_mcast_send, + .recv = channel_mcast_recv, + .get_fd = channel_mcast_get_fd, + .stats = channel_mcast_stats, + .stats_extended = channel_mcast_stats_extended, +}; diff --git a/src/mcast.c b/src/mcast.c index 8f11762..8eedd07 100644 --- a/src/mcast.c +++ b/src/mcast.c @@ -143,52 +143,12 @@ struct mcast_sock *mcast_server_create(struct mcast_conf *conf) return m; } -struct mcast_sock_multi * -mcast_server_create_multi(struct mcast_conf *conf, int conf_len) -{ - struct mcast_sock_multi *m; - int i, j; - - if (conf_len <= 0 || conf_len > MCAST_LINKS_MAX) - return NULL; - - m = calloc(sizeof(struct mcast_sock_multi), 1); - if (m == NULL) - return NULL; - - m->max_mtu = INT_MAX; - for (i=0; imulti[i] = mcast_server_create(&conf[i]); - if (m->multi[i] == NULL) { - for (j=0; jmulti[j]); - } - free(m); - return NULL; - } - if (m->max_mtu > conf[i].mtu) - m->max_mtu = conf[i].mtu; - } - m->num_links = conf_len; - - return m; -} - void mcast_server_destroy(struct mcast_sock *m) { close(m->fd); free(m); } -void mcast_server_destroy_multi(struct mcast_sock_multi *m) -{ - int i; - - for (i=0; inum_links; i++) - mcast_server_destroy(m->multi[i]); - free(m); -} - static int __mcast_client_create_ipv4(struct mcast_sock *m, struct mcast_conf *conf) { @@ -306,52 +266,12 @@ struct mcast_sock *mcast_client_create(struct mcast_conf *conf) return m; } -struct mcast_sock_multi * -mcast_client_create_multi(struct mcast_conf *conf, int conf_len) -{ - struct mcast_sock_multi *m; - int i, j; - - if (conf_len <= 0 || conf_len > MCAST_LINKS_MAX) - return NULL; - - m = calloc(sizeof(struct mcast_sock_multi), 1); - if (m == NULL) - return NULL; - - m->max_mtu = INT_MAX; - for (i=0; imulti[i] = mcast_client_create(&conf[i]); - if (m->multi[i] == NULL) { - for (j=0; jmulti[j]); - } - free(m); - return NULL; - } - if (m->max_mtu > conf[i].mtu) - m->max_mtu = conf[i].mtu; - } - m->num_links = conf_len; - - return m; -} - void mcast_client_destroy(struct mcast_sock *m) { close(m->fd); free(m); } -void mcast_client_destroy_multi(struct mcast_sock_multi *m) -{ - int i; - - for (i=0; inum_links; i++) - mcast_client_destroy(m->multi[i]); - free(m); -} - ssize_t mcast_send(struct mcast_sock *m, void *data, int size) { ssize_t ret; @@ -395,32 +315,12 @@ ssize_t mcast_recv(struct mcast_sock *m, void *data, int size) return ret; } -void mcast_set_current_link(struct mcast_sock_multi *m, int i) -{ - m->current_link = m->multi[i]; -} - -struct mcast_sock *mcast_get_current_link(struct mcast_sock_multi *m) -{ - return m->current_link; -} - int mcast_get_fd(struct mcast_sock *m) { return m->fd; } -int mcast_get_current_ifidx(struct mcast_sock_multi *m) -{ - return m->current_link->interface_idx; -} - -int mcast_get_ifidx(struct mcast_sock_multi *m, int i) -{ - return m->multi[i]->interface_idx; -} - -static int +int mcast_snprintf_stats(char *buf, size_t buflen, char *ifname, struct mcast_stats *s, struct mcast_stats *r) { @@ -443,7 +343,7 @@ mcast_snprintf_stats(char *buf, size_t buflen, char *ifname, return size; } -static int +int mcast_snprintf_stats2(char *buf, size_t buflen, const char *ifname, const char *status, int active, struct mcast_stats *s, struct mcast_stats *r) @@ -467,68 +367,3 @@ mcast_snprintf_stats2(char *buf, size_t buflen, const char *ifname, (unsigned long long)r->error); return size; } - -void -mcast_dump_stats(int fd, - const struct mcast_sock_multi *s, - const struct mcast_sock_multi *r) -{ - int i; - struct mcast_stats snd = { 0, 0, 0}; - struct mcast_stats rcv = { 0, 0, 0}; - char ifname[IFNAMSIZ], buf[512]; - int size; - - /* it is the same for the receiver, no need to do it twice */ - if_indextoname(s->current_link->interface_idx, ifname); - - for (i=0; inum_links && inum_links; i++) { - snd.bytes += s->multi[i]->stats.bytes; - snd.messages += s->multi[i]->stats.messages; - snd.error += s->multi[i]->stats.error; - rcv.bytes += r->multi[i]->stats.bytes; - rcv.messages += r->multi[i]->stats.messages; - rcv.error += r->multi[i]->stats.error; - } - size = mcast_snprintf_stats(buf, sizeof(buf), ifname, &snd, &rcv); - send(fd, buf, size, 0); -} - -void -mcast_dump_stats_extended(int fd, - const struct mcast_sock_multi *s, - const struct mcast_sock_multi *r, - const struct nlif_handle *h) -{ - int i; - char buf[4096]; - int size = 0; - - for (i=0; inum_links && inum_links; i++) { - int idx = s->multi[i]->interface_idx, active; - unsigned int flags; - char ifname[IFNAMSIZ]; - const char *status; - - if_indextoname(idx, ifname); - nlif_get_ifflags(h, idx, &flags); - active = (s->multi[i] == s->current_link); - /* - * IFF_UP shows administrative status - * IFF_RUNNING shows carrier status - */ - if (flags & IFF_UP) { - if (!(flags & IFF_RUNNING)) - status = "NO-CARRIER"; - else - status = "RUNNING"; - } else { - status = "DOWN"; - } - size += mcast_snprintf_stats2(buf+size, sizeof(buf), - ifname, status, active, - &s->multi[i]->stats, - &r->multi[i]->stats); - } - send(fd, buf, size, 0); -} diff --git a/src/multichannel.c b/src/multichannel.c new file mode 100644 index 0000000..ab0f04c --- /dev/null +++ b/src/multichannel.c @@ -0,0 +1,110 @@ +/* + * (C) 2009 by Pablo Neira Ayuso + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include + +#include "channel.h" +#include "network.h" + +struct multichannel * +multichannel_open(struct channel_conf *conf, int len) +{ + struct multichannel *m; + int i, set_default_channel = 0; + + if (len <= 0 || len > MULTICHANNEL_MAX) + return NULL; + + m = calloc(sizeof(struct multichannel), 1); + if (m == NULL) + return NULL; + + m->channel_num = len; + for (i = 0; i < len; i++) { + m->channel[i] = channel_open(&conf[i]); + if (m->channel[i] == NULL) { + int j; + + for (j=0; jchannel[j]); + } + free(m); + return NULL; + } + if (conf[i].channel_flags & CHANNEL_F_DEFAULT) { + m->current = m->channel[i]; + set_default_channel = 1; + } + } + if (!set_default_channel) + m->current = m->channel[0]; + + return m; +} + +int multichannel_send(struct multichannel *c, const struct nethdr *net) +{ + return channel_send(c->current, net); +} + +int multichannel_send_flush(struct multichannel *c) +{ + return channel_send_flush(c->current); +} + +int multichannel_recv(struct multichannel *c, char *buf, int size) +{ + return channel_recv(c->current, buf, size); +} + +void multichannel_close(struct multichannel *m) +{ + int i; + + for (i = 0; i < m->channel_num; i++) { + channel_close(m->channel[i]); + } + free(m); +} + +void multichannel_stats(struct multichannel *m, int fd) +{ + channel_stats(m->current, fd); +} + +void +multichannel_stats_extended(struct multichannel *m, + struct nlif_handle *h, int fd) +{ + int i, active; + + for (i = 0; i < m->channel_num; i++) { + if (m->current == m->channel[i]) { + active = 1; + } else { + active = 0; + } + channel_stats_extended(m->channel[i], active, h, fd); + } +} + +int multichannel_get_ifindex(struct multichannel *m, int i) +{ + return m->channel[i]->channel_ifindex; +} + +int multichannel_get_current_ifindex(struct multichannel *m) +{ + return m->current->channel_ifindex; +} + +void multichannel_set_current_channel(struct multichannel *m, int i) +{ + m->current = m->channel[i]; +} diff --git a/src/network.c b/src/network.c index 690b28e..bdfa10c 100644 --- a/src/network.c +++ b/src/network.c @@ -65,67 +65,6 @@ void nethdr_set_ctl(struct nethdr *net) __nethdr_set(net, NETHDR_SIZ); } -static size_t tx_buflenmax; -static size_t tx_buflen = 0; -static char *tx_buf; - -#define HEADERSIZ 28 /* IP header (20 bytes) + UDP header 8 (bytes) */ - -int mcast_buffered_init(int if_mtu) -{ - int mtu = if_mtu - HEADERSIZ; - - /* default to Ethernet MTU 1500 bytes */ - if (if_mtu == 0) - mtu = 1500 - HEADERSIZ; - - tx_buf = malloc(mtu); - if (tx_buf == NULL) - return -1; - - tx_buflenmax = mtu; - - return 0; -} - -void mcast_buffered_destroy(void) -{ - free(tx_buf); -} - -/* return 0 if it is not sent, otherwise return 1 */ -int -mcast_buffered_send_netmsg(struct mcast_sock_multi *m, const struct nethdr *net) -{ - int ret = 0, len = ntohs(net->len); - -retry: - if (tx_buflen + len < tx_buflenmax) { - memcpy(tx_buf + tx_buflen, net, len); - tx_buflen += len; - } else { - mcast_send(mcast_get_current_link(m), tx_buf, tx_buflen); - ret = 1; - tx_buflen = 0; - goto retry; - } - - return ret; -} - -ssize_t mcast_buffered_pending_netmsg(struct mcast_sock_multi *m) -{ - ssize_t ret; - - if (tx_buflen == 0) - return 0; - - ret = mcast_send(mcast_get_current_link(m), tx_buf, tx_buflen); - tx_buflen = 0; - - return ret; -} - static int local_seq_set = 0; /* this function only tracks, it does not update the last sequence received */ diff --git a/src/read_config_yy.y b/src/read_config_yy.y index b9a37f7..b3a2640 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -181,18 +181,18 @@ checksum: T_CHECKSUM T_ON * XXX: The use of Checksum outside of the Multicast clause is broken * if we have more than one dedicated links. */ - conf.mcast[0].checksum = 0; + conf.channel[0].u.mcast.checksum = 0; }; checksum: T_CHECKSUM T_OFF { fprintf(stderr, "WARNING: The use of `Checksum' outside the " "`Multicast' clause is ambiguous.\n"); - /* + /* * XXX: The use of Checksum outside of the Multicast clause is broken * if we have more than one dedicated links. */ - conf.mcast[0].checksum = 1; + conf.channel[0].u.mcast.checksum = 1; }; ignore_traffic : T_IGNORE_TRAFFIC '{' ignore_traffic_options '}' @@ -256,13 +256,18 @@ ignore_traffic_option : T_IPV6_ADDR T_IP multicast_line : T_MULTICAST '{' multicast_options '}' { - conf.mcast_links++; + conf.channel[conf.channel_num].channel_type = CHANNEL_MCAST; + conf.channel[conf.channel_num].channel_flags = CHANNEL_F_BUFFERED; + conf.channel_num++; }; multicast_line : T_MULTICAST T_DEFAULT '{' multicast_options '}' { - conf.mcast_default_link = conf.mcast_links; - conf.mcast_links++; + conf.channel[conf.channel_num].channel_type = CHANNEL_MCAST; + conf.channel[conf.channel_num].channel_flags = CHANNEL_F_DEFAULT | + CHANNEL_F_BUFFERED; + conf.channel_default = conf.channel_num; + conf.channel_num++; }; multicast_options : @@ -272,19 +277,19 @@ multicast_option : T_IPV4_ADDR T_IP { __max_mcast_dedicated_links_reached(); - if (!inet_aton($2, &conf.mcast[conf.mcast_links].in)) { + if (!inet_aton($2, &conf.channel[conf.channel_num].u.mcast.in)) { fprintf(stderr, "%s is not a valid IPv4 address\n", $2); break; } - if (conf.mcast[conf.mcast_links].ipproto == AF_INET6) { + if (conf.channel[conf.channel_num].u.mcast.ipproto == AF_INET6) { fprintf(stderr, "Your multicast address is IPv4 but " "is binded to an IPv6 interface? Surely " "this is not what you want\n"); break; } - conf.mcast[conf.mcast_links].ipproto = AF_INET; + conf.channel[conf.channel_num].u.mcast.ipproto = AF_INET; }; multicast_option : T_IPV6_ADDR T_IP @@ -292,7 +297,8 @@ multicast_option : T_IPV6_ADDR T_IP __max_mcast_dedicated_links_reached(); #ifdef HAVE_INET_PTON_IPV6 - if (inet_pton(AF_INET6, $2, &conf.mcast[conf.mcast_links].in) <= 0) { + if (inet_pton(AF_INET6, $2, + &conf.channel[conf.channel_num].u.mcast.in) <= 0) { fprintf(stderr, "%s is not a valid IPv6 address\n", $2); break; } @@ -301,17 +307,17 @@ multicast_option : T_IPV6_ADDR T_IP break; #endif - if (conf.mcast[conf.mcast_links].ipproto == AF_INET) { + if (conf.channel[conf.channel_num].u.mcast.ipproto == AF_INET) { fprintf(stderr, "Your multicast address is IPv6 but " "is binded to an IPv4 interface? Surely " "this is not what you want\n"); break; } - conf.mcast[conf.mcast_links].ipproto = AF_INET6; + conf.channel[conf.channel_num].u.mcast.ipproto = AF_INET6; - if (conf.mcast[conf.mcast_links].iface[0] && - !conf.mcast[conf.mcast_links].ifa.interface_index6) { + if (conf.channel[conf.channel_num].u.mcast.iface[0] && + !conf.channel[conf.channel_num].u.mcast.ifa.interface_index6) { unsigned int idx; idx = if_nametoindex($2); @@ -320,8 +326,8 @@ multicast_option : T_IPV6_ADDR T_IP break; } - conf.mcast[conf.mcast_links].ifa.interface_index6 = idx; - conf.mcast[conf.mcast_links].ipproto = AF_INET6; + conf.channel[conf.channel_num].u.mcast.ifa.interface_index6 = idx; + conf.channel[conf.channel_num].u.mcast.ipproto = AF_INET6; } }; @@ -329,19 +335,19 @@ multicast_option : T_IPV4_IFACE T_IP { __max_mcast_dedicated_links_reached(); - if (!inet_aton($2, &conf.mcast[conf.mcast_links].ifa)) { + if (!inet_aton($2, &conf.channel[conf.channel_num].u.mcast.ifa)) { fprintf(stderr, "%s is not a valid IPv4 address\n", $2); break; } - if (conf.mcast[conf.mcast_links].ipproto == AF_INET6) { + if (conf.channel[conf.channel_num].u.mcast.ipproto == AF_INET6) { fprintf(stderr, "Your multicast interface is IPv4 but " "is binded to an IPv6 interface? Surely " "this is not what you want\n"); break; } - conf.mcast[conf.mcast_links].ipproto = AF_INET; + conf.channel[conf.channel_num].u.mcast.ipproto = AF_INET; }; multicast_option : T_IPV6_IFACE T_IP @@ -355,18 +361,19 @@ multicast_option : T_IFACE T_STRING __max_mcast_dedicated_links_reached(); - strncpy(conf.mcast[conf.mcast_links].iface, $2, IFNAMSIZ); + strncpy(conf.channel[conf.channel_num].channel_ifname, $2, IFNAMSIZ); + strncpy(conf.channel[conf.channel_num].u.mcast.iface, $2, IFNAMSIZ); idx = if_nametoindex($2); if (!idx) { fprintf(stderr, "%s is an invalid interface.\n", $2); break; } - conf.mcast[conf.mcast_links].interface_idx = idx; + conf.channel[conf.channel_num].u.mcast.interface_idx = idx; - if (conf.mcast[conf.mcast_links].ipproto == AF_INET6) { - conf.mcast[conf.mcast_links].ifa.interface_index6 = idx; - conf.mcast[conf.mcast_links].ipproto = AF_INET6; + if (conf.channel[conf.channel_num].u.mcast.ipproto == AF_INET6) { + conf.channel[conf.channel_num].u.mcast.ifa.interface_index6 = idx; + conf.channel[conf.channel_num].u.mcast.ipproto = AF_INET6; } }; @@ -379,31 +386,31 @@ multicast_option : T_BACKLOG T_NUMBER multicast_option : T_GROUP T_NUMBER { __max_mcast_dedicated_links_reached(); - conf.mcast[conf.mcast_links].port = $2; + conf.channel[conf.channel_num].u.mcast.port = $2; }; multicast_option: T_MCAST_SNDBUFF T_NUMBER { __max_mcast_dedicated_links_reached(); - conf.mcast[conf.mcast_links].sndbuf = $2; + conf.channel[conf.channel_num].u.mcast.sndbuf = $2; }; multicast_option: T_MCAST_RCVBUFF T_NUMBER { __max_mcast_dedicated_links_reached(); - conf.mcast[conf.mcast_links].rcvbuf = $2; + conf.channel[conf.channel_num].u.mcast.rcvbuf = $2; }; multicast_option: T_CHECKSUM T_ON { __max_mcast_dedicated_links_reached(); - conf.mcast[conf.mcast_links].checksum = 0; + conf.channel[conf.channel_num].u.mcast.checksum = 0; }; multicast_option: T_CHECKSUM T_OFF { __max_mcast_dedicated_links_reached(); - conf.mcast[conf.mcast_links].checksum = 1; + conf.channel[conf.channel_num].u.mcast.checksum = 1; }; hashsize : T_HASHSIZE T_NUMBER @@ -1128,10 +1135,10 @@ static void __kernel_filter_add_state(int value) static void __max_mcast_dedicated_links_reached(void) { - if (conf.mcast_links >= MCAST_LINKS_MAX) { + if (conf.channel_num >= MULTICHANNEL_MAX) { fprintf(stderr, "ERROR: too many dedicated links in " "the configuration file (Maximum: %d).\n", - MCAST_LINKS_MAX); + MULTICHANNEL_MAX); exit(EXIT_FAILURE); } } diff --git a/src/sync-alarm.c b/src/sync-alarm.c index a59ae11..caa6bb2 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -125,7 +125,7 @@ static int tx_queue_xmit(struct queue_node *n, const void *data) net = queue_node_data(n); nethdr_set_ctl(net); HDR_HOST2NETWORK(net); - mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); + multichannel_send(STATE_SYNC(channel), net); queue_object_free((struct queue_object *)n); break; case Q_ELEM_OBJ: { @@ -137,7 +137,7 @@ static int tx_queue_xmit(struct queue_node *n, const void *data) obj = cache_data_get_object(STATE_SYNC(internal), ca); type = object_status_to_network_type(obj->status); net = BUILD_NETMSG(obj->ct, type); - mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); + multichannel_send(STATE_SYNC(channel), net); cache_object_put(obj); break; } diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index d608e5b..cacbb13 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -494,7 +494,7 @@ static int tx_queue_xmit(struct queue_node *n, const void *data) dp("tx_queue sq: %u fl:%u len:%u\n", ntohl(net->seq), net->flags, ntohs(net->len)); - mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); + multichannel_send(STATE_SYNC(channel), net); HDR_NETWORK2HOST(net); if (IS_ACK(net) || IS_NACK(net) || IS_RESYNC(net)) { @@ -523,7 +523,7 @@ static int tx_queue_xmit(struct queue_node *n, const void *data) dp("tx_list sq: %u fl:%u len:%u\n", ntohl(net->seq), net->flags, ntohs(net->len)); - mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); + multichannel_send(STATE_SYNC(channel), net); cn->seq = ntohl(net->seq); if (queue_add(rs_queue, &cn->qnode) < 0) { if (errno == ENOSPC) { diff --git a/src/sync-mode.c b/src/sync-mode.c index b452cba..22609df 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -38,12 +38,12 @@ static void mcast_change_current_link(int if_idx) { - if (if_idx != mcast_get_current_ifidx(STATE_SYNC(mcast_client))) - mcast_set_current_link(STATE_SYNC(mcast_client), if_idx); + if (if_idx != multichannel_get_current_ifindex(STATE_SYNC(channel))) + multichannel_set_current_channel(STATE_SYNC(channel), if_idx); } static void -do_mcast_handler_step(int if_idx, struct nethdr *net, size_t remain) +do_channel_handler_step(int if_idx, struct nethdr *net, size_t remain) { char __ct[nfct_maxsize()]; struct nf_conntrack *ct = (struct nf_conntrack *)(void*) __ct; @@ -122,14 +122,14 @@ retry: } } -/* handler for multicast messages received */ -static void mcast_handler(struct mcast_sock *m, int if_idx) +/* handler for messages received */ +static void channel_handler(struct channel *m, int if_idx) { ssize_t numbytes; ssize_t remain; char __net[65536], *ptr = __net; /* XXX: maximum MTU for IPv4 */ - numbytes = mcast_recv(m, __net, sizeof(__net)); + numbytes = channel_recv(m, __net, sizeof(__net)); if (numbytes <= 0) return; @@ -168,7 +168,7 @@ static void mcast_handler(struct mcast_sock *m, int if_idx) HDR_NETWORK2HOST(net); - do_mcast_handler_step(if_idx, net, remain); + do_channel_handler_step(if_idx, net, remain); ptr += net->len; remain -= net->len; } @@ -181,13 +181,13 @@ static void interface_candidate(void) unsigned int flags; char buf[IFNAMSIZ]; - for (i=0; inum_links; i++) { - idx = mcast_get_ifidx(STATE_SYNC(mcast_client), i); - if (idx == mcast_get_current_ifidx(STATE_SYNC(mcast_client))) + for (i=0; ichannel_num; i++) { + idx = multichannel_get_ifindex(STATE_SYNC(channel), i); + if (idx == multichannel_get_current_ifindex(STATE_SYNC(channel))) continue; nlif_get_ifflags(STATE_SYNC(interface), idx, &flags); if (flags & (IFF_RUNNING | IFF_UP)) { - mcast_set_current_link(STATE_SYNC(mcast_client), i); + multichannel_set_current_channel(STATE_SYNC(channel), i); dlog(LOG_NOTICE, "device `%s' becomes multicast " "dedicated link", if_indextoname(idx, buf)); @@ -199,7 +199,7 @@ static void interface_candidate(void) static void interface_handler(void) { - int idx = mcast_get_current_ifidx(STATE_SYNC(mcast_client)); + int idx = multichannel_get_current_ifindex(STATE_SYNC(channel)); unsigned int flags; nlif_catch(STATE_SYNC(interface)); @@ -267,38 +267,21 @@ static int init_sync(void) return -1; } - /* multicast server to receive events from the wire */ - STATE_SYNC(mcast_server) = - mcast_server_create_multi(CONFIG(mcast), CONFIG(mcast_links)); - if (STATE_SYNC(mcast_server) == NULL) { - dlog(LOG_ERR, "can't open multicast server!"); + channel_init(); + + /* channel to send events on the wire */ + STATE_SYNC(channel) = + multichannel_open(CONFIG(channel), CONFIG(channel_num)); + if (STATE_SYNC(channel) == NULL) { + dlog(LOG_ERR, "can't open channel socket"); return -1; } - for (i=0; inum_links; i++) { - int fd = mcast_get_fd(STATE_SYNC(mcast_server)->multi[i]); + for (i=0; ichannel_num; i++) { + int fd = channel_get_fd(STATE_SYNC(channel)->channel[i]); if (register_fd(fd, STATE(fds)) == -1) return -1; } - /* multicast client to send events on the wire */ - STATE_SYNC(mcast_client) = - mcast_client_create_multi(CONFIG(mcast), CONFIG(mcast_links)); - if (STATE_SYNC(mcast_client) == NULL) { - dlog(LOG_ERR, "can't open client multicast socket"); - mcast_server_destroy_multi(STATE_SYNC(mcast_server)); - return -1; - } - /* we only use one link to send events, but all to receive them */ - mcast_set_current_link(STATE_SYNC(mcast_client), - CONFIG(mcast_default_link)); - - if (mcast_buffered_init(STATE_SYNC(mcast_client)->max_mtu) == -1) { - dlog(LOG_ERR, "can't init tx buffer!"); - mcast_server_destroy_multi(STATE_SYNC(mcast_server)); - mcast_client_destroy_multi(STATE_SYNC(mcast_client)); - return -1; - } - STATE_SYNC(interface) = nl_init_interface_handler(); if (!STATE_SYNC(interface)) { dlog(LOG_ERR, "can't open interface watcher"); @@ -328,10 +311,10 @@ static void run_sync(fd_set *readfds) { int i; - for (i=0; inum_links; i++) { - int fd = mcast_get_fd(STATE_SYNC(mcast_server)->multi[i]); + for (i=0; ichannel_num; i++) { + int fd = channel_get_fd(STATE_SYNC(channel)->channel[i]); if (FD_ISSET(fd, readfds)) - mcast_handler(STATE_SYNC(mcast_server)->multi[i], i); + channel_handler(STATE_SYNC(channel)->channel[i], i); } if (FD_ISSET(queue_get_eventfd(STATE_SYNC(tx_queue)), readfds)) @@ -341,7 +324,7 @@ static void run_sync(fd_set *readfds) interface_handler(); /* flush pending messages */ - mcast_buffered_pending_netmsg(STATE_SYNC(mcast_client)); + multichannel_send_flush(STATE_SYNC(channel)); } static void kill_sync(void) @@ -349,12 +332,10 @@ static void kill_sync(void) cache_destroy(STATE_SYNC(internal)); cache_destroy(STATE_SYNC(external)); - mcast_server_destroy_multi(STATE_SYNC(mcast_server)); - mcast_client_destroy_multi(STATE_SYNC(mcast_client)); + multichannel_close(STATE_SYNC(channel)); nlif_close(STATE_SYNC(interface)); - mcast_buffered_destroy(); queue_destroy(STATE_SYNC(tx_queue)); if (STATE_SYNC(sync)->kill) @@ -486,23 +467,20 @@ static int local_handler_sync(int fd, int type, void *data) cache_stats(STATE_SYNC(internal), fd); cache_stats(STATE_SYNC(external), fd); dump_traffic_stats(fd); - mcast_dump_stats(fd, STATE_SYNC(mcast_client), - STATE_SYNC(mcast_server)); + multichannel_stats(STATE_SYNC(channel), fd); dump_stats_sync(fd); break; case STATS_NETWORK: dump_stats_sync_extended(fd); - mcast_dump_stats(fd, STATE_SYNC(mcast_client), - STATE_SYNC(mcast_server)); + multichannel_stats(STATE_SYNC(channel), fd); break; case STATS_CACHE: cache_stats_extended(STATE_SYNC(internal), fd); cache_stats_extended(STATE_SYNC(external), fd); break; case STATS_MULTICAST: - mcast_dump_stats_extended(fd, STATE_SYNC(mcast_client), - STATE_SYNC(mcast_server), - STATE_SYNC(interface)); + multichannel_stats_extended(STATE_SYNC(channel), + STATE_SYNC(interface), fd); break; default: if (STATE_SYNC(sync)->local) diff --git a/src/sync-notrack.c b/src/sync-notrack.c index 57c3368..737ee52 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -134,7 +134,7 @@ static int tx_queue_xmit(struct queue_node *n, const void *data2) else nethdr_set_ctl(net); HDR_HOST2NETWORK(net); - mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); + multichannel_send(STATE_SYNC(channel), net); queue_del(n); queue_object_free((struct queue_object *)n); break; @@ -150,7 +150,7 @@ static int tx_queue_xmit(struct queue_node *n, const void *data2) type = object_status_to_network_type(obj->status);; net = BUILD_NETMSG(obj->ct, type); - mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); + multichannel_send(STATE_SYNC(channel), net); queue_del(n); cache_object_put(obj); break; -- cgit v1.2.3 From 338d8fc2da19f5d6a75c339d9e6ecac43b68a1e4 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 12 Mar 2009 21:19:19 +0100 Subject: sync-mode: rename mcast_track_*() by nethdr_track_*() This patch is a cleanup. It renames the mcast_track_*() functions by nethdr_track_*() because this functions are related to message sequence tracking. They are not stick to multicast at all. Signed-off-by: Pablo Neira Ayuso --- include/network.h | 6 +++--- src/network.c | 6 +++--- src/sync-alarm.c | 2 +- src/sync-ftfw.c | 6 +++--- src/sync-notrack.c | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) (limited to 'src/sync-notrack.c') diff --git a/include/network.h b/include/network.h index 7019d7d..b182339 100644 --- a/include/network.h +++ b/include/network.h @@ -100,9 +100,9 @@ enum { SEQ_BEFORE, }; -int mcast_track_seq(uint32_t seq, uint32_t *exp_seq); -void mcast_track_update_seq(uint32_t seq); -int mcast_track_is_seq_set(void); +int nethdr_track_seq(uint32_t seq, uint32_t *exp_seq); +void nethdr_track_update_seq(uint32_t seq); +int nethdr_track_is_seq_set(void); struct mcast_conf; diff --git a/src/network.c b/src/network.c index bdfa10c..6a66a2b 100644 --- a/src/network.c +++ b/src/network.c @@ -68,7 +68,7 @@ void nethdr_set_ctl(struct nethdr *net) static int local_seq_set = 0; /* this function only tracks, it does not update the last sequence received */ -int mcast_track_seq(uint32_t seq, uint32_t *exp_seq) +int nethdr_track_seq(uint32_t seq, uint32_t *exp_seq) { int ret = SEQ_UNKNOWN; @@ -104,7 +104,7 @@ out: return ret; } -void mcast_track_update_seq(uint32_t seq) +void nethdr_track_update_seq(uint32_t seq) { if (!local_seq_set) local_seq_set = 1; @@ -112,7 +112,7 @@ void mcast_track_update_seq(uint32_t seq) STATE_SYNC(last_seq_recv) = seq; } -int mcast_track_is_seq_set() +int nethdr_track_is_seq_set() { return local_seq_set; } diff --git a/src/sync-alarm.c b/src/sync-alarm.c index caa6bb2..4757026 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -102,7 +102,7 @@ static int alarm_recv(const struct nethdr *net) * just joined the cluster, instead they just get resynchronized in * RefreshTime seconds at worst case. */ - mcast_track_seq(net->seq, &exp_seq); + nethdr_track_seq(net->seq, &exp_seq); return 0; } diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index cacbb13..e026b1c 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -129,7 +129,7 @@ static void tx_queue_add_ctlmsg2(uint32_t flags) /* this function is called from the alarm framework */ static void do_alive_alarm(struct alarm_block *a, void *data) { - if (ack_from_set && mcast_track_is_seq_set()) { + if (ack_from_set && nethdr_track_is_seq_set()) { /* exp_seq contains the last update received */ tx_queue_add_ctlmsg(NET_F_ACK, ack_from, @@ -396,7 +396,7 @@ static int ftfw_recv(const struct nethdr *net) goto bypass; } - switch (mcast_track_seq(net->seq, &exp_seq)) { + switch (nethdr_track_seq(net->seq, &exp_seq)) { case SEQ_AFTER: ret = digest_msg(net); if (ret == MSG_BAD) { @@ -446,7 +446,7 @@ bypass: out: if ((ret == MSG_DATA || ret == MSG_CTL)) - mcast_track_update_seq(net->seq); + nethdr_track_update_seq(net->seq); return ret; } diff --git a/src/sync-notrack.c b/src/sync-notrack.c index 737ee52..6502bcd 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -114,12 +114,12 @@ static int notrack_recv(const struct nethdr *net) int ret; unsigned int exp_seq; - mcast_track_seq(net->seq, &exp_seq); + nethdr_track_seq(net->seq, &exp_seq); ret = digest_msg(net); if (ret != MSG_BAD) - mcast_track_update_seq(net->seq); + nethdr_track_update_seq(net->seq); return ret; } -- cgit v1.2.3 From 530eed5796faa5fd16c39743a4516bef0e26449c Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 17 Sep 2009 16:10:43 +0200 Subject: conntrackd: fix return value in notrack_local() In 9406f29b89f6727c3db5485d109466701393b4d4, we added different return values for the UNIX sockets that we use to extract the daemon statistics. Unfortunately, I forgot to change this as well. This patch fixes a problem that blocks the client socket indefinitely. Signed-off-by: Pablo Neira Ayuso --- src/sync-notrack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/sync-notrack.c') diff --git a/src/sync-notrack.c b/src/sync-notrack.c index 6502bcd..14ecde5 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -77,7 +77,7 @@ static int do_cache_to_tx(void *data1, void *data2) static int notrack_local(int fd, int type, void *data) { - int ret = 1; + int ret = LOCAL_RET_OK; switch(type) { case REQUEST_DUMP: -- cgit v1.2.3 From 84ebcb1c96cd84d6d09f0b3fe534b9a0c5a120d8 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 23 Sep 2009 18:14:09 +0200 Subject: conntrackd: add alive control messages to notrack mode This patch adds the alive control message to the notrack mode. This helps to diagnose problems in the synchronization and the state of the channel, specifically for TCP-based channels. Signed-off-by: Pablo Neira Ayuso --- src/sync-notrack.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'src/sync-notrack.c') diff --git a/src/sync-notrack.c b/src/sync-notrack.c index 14ecde5..d9f273e 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -26,6 +26,11 @@ #include +static struct alarm_block alive_alarm; + +/* XXX: alive message expiration configurable */ +#define ALIVE_INT 1 + struct cache_notrack { struct queue_node qnode; }; @@ -106,6 +111,9 @@ static int digest_msg(const struct nethdr *net) return MSG_CTL; } + if (IS_ALIVE(net)) + return MSG_CTL; + return MSG_BAD; } @@ -162,6 +170,7 @@ static int tx_queue_xmit(struct queue_node *n, const void *data2) static void notrack_xmit(void) { queue_iterate(STATE_SYNC(tx_queue), NULL, tx_queue_xmit); + add_alarm(&alive_alarm, ALIVE_INT, 0); } static void notrack_enqueue(struct cache_object *obj, int query) @@ -171,10 +180,40 @@ static void notrack_enqueue(struct cache_object *obj, int query) cache_object_get(obj); } +static void tx_queue_add_ctlmsg2(uint32_t flags) +{ + struct queue_object *qobj; + struct nethdr *ctl; + + qobj = queue_object_new(Q_ELEM_CTL, sizeof(struct nethdr_ack)); + if (qobj == NULL) + return; + + ctl = (struct nethdr *)qobj->data; + ctl->type = NET_T_CTL; + ctl->flags = flags; + + queue_add(STATE_SYNC(tx_queue), &qobj->qnode); +} + +static void do_alive_alarm(struct alarm_block *a, void *data) +{ + tx_queue_add_ctlmsg2(NET_F_ALIVE); + add_alarm(&alive_alarm, ALIVE_INT, 0); +} + +static int notrack_init(void) +{ + init_alarm(&alive_alarm, NULL, do_alive_alarm); + add_alarm(&alive_alarm, ALIVE_INT, 0); + return 0; +} + struct sync_mode sync_notrack = { .internal_cache_flags = NO_FEATURES, .external_cache_flags = NO_FEATURES, .internal_cache_extra = &cache_notrack_extra, + .init = notrack_init, .local = notrack_local, .recv = notrack_recv, .enqueue = notrack_enqueue, -- cgit v1.2.3 From 8ad5df6121c46753a6d12fafa5ab9da309ddb721 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 21 Oct 2009 01:43:07 +0200 Subject: conntrackd: add `DisableInternalCache' clause This patch adds the clause `DisableInternalCache' that allows you to bypass the internal cache. This clause can only be used with the notrack synchronization mode. Signed-off-by: Pablo Neira Ayuso --- include/Makefile.am | 2 +- include/conntrackd.h | 12 +-- include/internal.h | 39 +++++++++ src/Makefile.am | 1 + src/internal_bypass.c | 165 +++++++++++++++++++++++++++++++++++++ src/internal_cache.c | 220 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/read_config_lex.l | 1 + src/read_config_yy.y | 13 ++- src/run.c | 62 ++++++++------ src/stats-mode.c | 24 +++--- src/sync-alarm.c | 5 +- src/sync-ftfw.c | 19 +++-- src/sync-mode.c | 190 ++++--------------------------------------- src/sync-notrack.c | 53 ++++++++++-- 14 files changed, 572 insertions(+), 234 deletions(-) create mode 100644 include/internal.h create mode 100644 src/internal_bypass.c create mode 100644 src/internal_cache.c (limited to 'src/sync-notrack.c') diff --git a/include/Makefile.am b/include/Makefile.am index a89490e..cbbca6b 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -4,5 +4,5 @@ noinst_HEADERS = alarm.h jhash.h cache.h linux_list.h linux_rbtree.h \ debug.h log.h hash.h mcast.h conntrack.h \ network.h filter.h queue.h vector.h cidr.h \ traffic_stats.h netlink.h fds.h event.h bitops.h channel.h \ - process.h origin.h external.h date.h + process.h origin.h internal.h external.h date.h diff --git a/include/conntrackd.h b/include/conntrackd.h index 7737532..c7f33f0 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -6,6 +6,7 @@ #include "alarm.h" #include "filter.h" #include "channel.h" +#include "internal.h" #include #include @@ -99,6 +100,7 @@ struct ct_conf { int error_queue_length; } channelc; struct { + int internal_cache_disable; int external_cache_disable; } sync; struct { @@ -177,7 +179,6 @@ struct ct_general_state { #define STATE_SYNC(x) state.sync->x struct ct_sync_state { - struct cache *internal; /* internal events cache (netlink) */ struct external_handler *external; struct multichannel *channel; @@ -239,18 +240,11 @@ extern union ct_state state; extern struct ct_general_state st; struct ct_mode { + struct internal_handler *internal; int (*init)(void); void (*run)(fd_set *readfds); int (*local)(int fd, int type, void *data); void (*kill)(void); - void (*dump)(struct nf_conntrack *ct); - int (*resync)(enum nf_conntrack_msg_type type, - struct nf_conntrack *ct, - void *data); - int (*purge)(void); - void (*event_new)(struct nf_conntrack *ct, int origin); - void (*event_upd)(struct nf_conntrack *ct, int origin); - int (*event_dst)(struct nf_conntrack *ct, int origin); }; /* conntrackd modes */ diff --git a/include/internal.h b/include/internal.h new file mode 100644 index 0000000..1f11340 --- /dev/null +++ b/include/internal.h @@ -0,0 +1,39 @@ +#ifndef _INTERNAL_H_ +#define _INTERNAL_H_ + +#include + +struct nf_conntrack; + +enum { + INTERNAL_F_POPULATE = (1 << 0), + INTERNAL_F_RESYNC = (1 << 1), + INTERNAL_F_MAX = (1 << 2) +}; + +struct internal_handler { + void *data; + unsigned int flags; + + int (*init)(void); + void (*close)(void); + + void (*new)(struct nf_conntrack *ct, int origin_type); + void (*update)(struct nf_conntrack *ct, int origin_type); + int (*destroy)(struct nf_conntrack *ct, int origin_type); + + void (*dump)(int fd, int type); + void (*populate)(struct nf_conntrack *ct); + void (*purge)(void); + int (*resync)(enum nf_conntrack_msg_type type, + struct nf_conntrack *ct, void *data); + void (*flush)(void); + + void (*stats)(int fd); + void (*stats_ext)(int fd); +}; + +extern struct internal_handler internal_cache; +extern struct internal_handler internal_bypass; + +#endif diff --git a/src/Makefile.am b/src/Makefile.am index 8b36642..76f0e73 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -22,6 +22,7 @@ conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c rbtree.c \ channel.c multichannel.c channel_mcast.c channel_udp.c \ tcp.c channel_tcp.c \ external_cache.c external_inject.c \ + internal_cache.c internal_bypass.c \ read_config_yy.y read_config_lex.l # yacc and lex generate dirty code diff --git a/src/internal_bypass.c b/src/internal_bypass.c new file mode 100644 index 0000000..4caaf4f --- /dev/null +++ b/src/internal_bypass.c @@ -0,0 +1,165 @@ +/* + * (C) 2009 by Pablo Neira Ayuso + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This feature has been sponsored by 6WIND . + */ +#include "conntrackd.h" +#include "sync.h" +#include "log.h" +#include "cache.h" +#include "netlink.h" +#include "network.h" +#include "origin.h" + +static int _init(void) +{ + return 0; +} + +static void _close(void) +{ +} + +static int dump_cb(enum nf_conntrack_msg_type type, + struct nf_conntrack *ct, void *data) +{ + char buf[1024]; + int size, *fd = data; + + size = nfct_snprintf(buf, 1024, ct, NFCT_T_UNKNOWN, NFCT_O_DEFAULT, 0); + if (size < 1024) { + buf[size] = '\n'; + size++; + } + send(*fd, buf, size, 0); + + return NFCT_CB_CONTINUE; +} + +static void dump(int fd, int type) +{ + struct nfct_handle *h; + u_int32_t family = AF_UNSPEC; + int ret; + + h = nfct_open(CONNTRACK, 0); + if (h == NULL) { + dlog(LOG_ERR, "can't allocate memory for the internal cache"); + return; + } + nfct_callback_register(h, NFCT_T_ALL, dump_cb, &fd); + ret = nfct_query(h, NFCT_Q_DUMP, &family); + if (ret == -1) { + dlog(LOG_ERR, "can't dump kernel table"); + } + nfct_close(h); +} + +static void flush(void) +{ + nl_flush_conntrack_table(STATE(flush)); +} + +struct { + uint32_t new; + uint32_t upd; + uint32_t del; +} internal_bypass_stats; + +static void stats(int fd) +{ + char buf[512]; + int size; + + size = sprintf(buf, "internal bypass:\n" + "connections new:\t\t%12u\n" + "connections updated:\t\t%12u\n" + "connections destroyed:\t\t%12u\n\n", + internal_bypass_stats.new, + internal_bypass_stats.upd, + internal_bypass_stats.del); + + send(fd, buf, size, 0); +} + +/* unused, INTERNAL_F_POPULATE is unset. No cache, nothing to populate. */ +static void populate(struct nf_conntrack *ct) +{ +} + +/* unused, INTERNAL_F_RESYNC is unset. */ +static void purge(void) +{ +} + +/* unused, INTERNAL_F_RESYNC is unset. Nothing to resync, we have no cache. */ +static int resync(enum nf_conntrack_msg_type type, + struct nf_conntrack *ct, + void *data) +{ + return NFCT_CB_CONTINUE; +} + +static void +event_new_sync(struct nf_conntrack *ct, int origin) +{ + struct nethdr *net; + + /* this event has been triggered by me, skip */ + if (origin != CTD_ORIGIN_NOT_ME) + return; + + net = BUILD_NETMSG(ct, NET_T_STATE_NEW); + multichannel_send(STATE_SYNC(channel), net); + internal_bypass_stats.new++; +} + +static void +event_update_sync(struct nf_conntrack *ct, int origin) +{ + struct nethdr *net; + + /* this event has been triggered by me, skip */ + if (origin != CTD_ORIGIN_NOT_ME) + return; + + net = BUILD_NETMSG(ct, NET_T_STATE_UPD); + multichannel_send(STATE_SYNC(channel), net); + internal_bypass_stats.upd++; +} + +static int +event_destroy_sync(struct nf_conntrack *ct, int origin) +{ + struct nethdr *net; + + /* this event has been triggered by me, skip */ + if (origin != CTD_ORIGIN_NOT_ME) + return 1; + + net = BUILD_NETMSG(ct, NET_T_STATE_DEL); + multichannel_send(STATE_SYNC(channel), net); + internal_bypass_stats.del++; + + return 1; +} + +struct internal_handler internal_bypass = { + .init = _init, + .close = _close, + .dump = dump, + .flush = flush, + .stats = stats, + .stats_ext = stats, + .populate = populate, + .purge = purge, + .resync = resync, + .new = event_new_sync, + .update = event_update_sync, + .destroy = event_destroy_sync, +}; diff --git a/src/internal_cache.c b/src/internal_cache.c new file mode 100644 index 0000000..daadfd6 --- /dev/null +++ b/src/internal_cache.c @@ -0,0 +1,220 @@ +/* + * (C) 2009 by Pablo Neira Ayuso + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ +#include "conntrackd.h" +#include "sync.h" +#include "log.h" +#include "cache.h" +#include "netlink.h" +#include "network.h" +#include "origin.h" + +static inline void sync_send(struct cache_object *obj, int query) +{ + STATE_SYNC(sync)->enqueue(obj, query); +} + +static int _init(void) +{ + STATE(mode)->internal->data = + cache_create("internal", + STATE_SYNC(sync)->internal_cache_flags, + STATE_SYNC(sync)->internal_cache_extra); + + if (!STATE(mode)->internal->data) { + dlog(LOG_ERR, "can't allocate memory for the internal cache"); + return -1; + } + return 0; +} + +static void _close(void) +{ + cache_destroy(STATE(mode)->internal->data); +} + +static void dump(int fd, int type) +{ + cache_dump(STATE(mode)->internal->data, fd, NFCT_O_PLAIN); +} + +static void flush(void) +{ + cache_flush(STATE(mode)->internal->data); +} + +static void stats(int fd) +{ + cache_stats(STATE(mode)->internal->data, fd); +} + +static void stats_ext(int fd) +{ + cache_stats_extended(STATE(mode)->internal->data, fd); +} + +static void populate(struct nf_conntrack *ct) +{ + /* This is required by kernels < 2.6.20 */ + nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES); + nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS); + nfct_attr_unset(ct, ATTR_REPL_COUNTER_BYTES); + nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS); + nfct_attr_unset(ct, ATTR_USE); + + cache_update_force(STATE(mode)->internal->data, ct); +} + +static int purge_step(void *data1, void *data2) +{ + struct cache_object *obj = data2; + + STATE(get_retval) = 0; + nl_get_conntrack(STATE(get), obj->ct); /* modifies STATE(get_reval) */ + if (!STATE(get_retval)) { + if (obj->status != C_OBJ_DEAD) { + cache_object_set_status(obj, C_OBJ_DEAD); + sync_send(obj, NET_T_STATE_DEL); + cache_object_put(obj); + } + } + + return 0; +} + +static void purge(void) +{ + cache_iterate(STATE(mode)->internal->data, NULL, purge_step); +} + +static int resync(enum nf_conntrack_msg_type type, + struct nf_conntrack *ct, + void *data) +{ + struct cache_object *obj; + + if (ct_filter_conntrack(ct, 1)) + return NFCT_CB_CONTINUE; + + /* This is required by kernels < 2.6.20 */ + nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES); + nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS); + nfct_attr_unset(ct, ATTR_REPL_COUNTER_BYTES); + nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS); + nfct_attr_unset(ct, ATTR_USE); + + obj = cache_update_force(STATE(mode)->internal->data, ct); + if (obj == NULL) + return NFCT_CB_CONTINUE; + + switch (obj->status) { + case C_OBJ_NEW: + sync_send(obj, NET_T_STATE_NEW); + break; + case C_OBJ_ALIVE: + sync_send(obj, NET_T_STATE_UPD); + break; + } + return NFCT_CB_CONTINUE; +} + +static void +event_new_sync(struct nf_conntrack *ct, int origin) +{ + struct cache_object *obj; + int id; + + /* this event has been triggered by a direct inject, skip */ + if (origin == CTD_ORIGIN_INJECT) + return; + + /* required by linux kernel <= 2.6.20 */ + nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES); + nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS); + nfct_attr_unset(ct, ATTR_REPL_COUNTER_BYTES); + nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS); + + obj = cache_find(STATE(mode)->internal->data, ct, &id); + if (obj == NULL) { +retry: + obj = cache_object_new(STATE(mode)->internal->data, ct); + if (obj == NULL) + return; + if (cache_add(STATE(mode)->internal->data, obj, id) == -1) { + cache_object_free(obj); + return; + } + /* only synchronize events that have been triggered by other + * processes or the kernel, but don't propagate events that + * have been triggered by conntrackd itself, eg. commits. */ + if (origin == CTD_ORIGIN_NOT_ME) + sync_send(obj, NET_T_STATE_NEW); + } else { + cache_del(STATE(mode)->internal->data, obj); + cache_object_free(obj); + goto retry; + } +} + +static void +event_update_sync(struct nf_conntrack *ct, int origin) +{ + struct cache_object *obj; + + /* this event has been triggered by a direct inject, skip */ + if (origin == CTD_ORIGIN_INJECT) + return; + + obj = cache_update_force(STATE(mode)->internal->data, ct); + if (obj == NULL) + return; + + if (origin == CTD_ORIGIN_NOT_ME) + sync_send(obj, NET_T_STATE_UPD); +} + +static int +event_destroy_sync(struct nf_conntrack *ct, int origin) +{ + struct cache_object *obj; + int id; + + /* this event has been triggered by a direct inject, skip */ + if (origin == CTD_ORIGIN_INJECT) + return 0; + + /* we don't synchronize events for objects that are not in the cache */ + obj = cache_find(STATE(mode)->internal->data, ct, &id); + if (obj == NULL) + return 0; + + if (obj->status != C_OBJ_DEAD) { + cache_object_set_status(obj, C_OBJ_DEAD); + if (origin == CTD_ORIGIN_NOT_ME) { + sync_send(obj, NET_T_STATE_DEL); + } + cache_object_put(obj); + } + return 1; +} + +struct internal_handler internal_cache = { + .flags = INTERNAL_F_POPULATE | INTERNAL_F_RESYNC, + .init = _init, + .close = _close, + .dump = dump, + .flush = flush, + .stats = stats, + .stats_ext = stats_ext, + .populate = populate, + .purge = purge, + .resync = resync, + .new = event_new_sync, + .update = event_update_sync, + .destroy = event_destroy_sync, +}; diff --git a/src/read_config_lex.l b/src/read_config_lex.l index b4be6f0..b2d4bdb 100644 --- a/src/read_config_lex.l +++ b/src/read_config_lex.l @@ -136,6 +136,7 @@ notrack [N|n][O|o][T|t][R|r][A|a][C|c][K|k] "Type" { return T_TYPE; } "Priority" { return T_PRIO; } "NetlinkEventsReliable" { return T_NETLINK_EVENTS_RELIABLE; } +"DisableInternalCache" { return T_DISABLE_INTERNAL_CACHE; } "DisableExternalCache" { return T_DISABLE_EXTERNAL_CACHE; } "ErrorQueueLength" { return T_ERROR_QUEUE_LENGTH; } diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 5075cf0..157e945 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -72,7 +72,7 @@ static void __max_dedicated_links_reached(void); %token T_FROM T_USERSPACE T_KERNELSPACE T_EVENT_ITER_LIMIT T_DEFAULT %token T_NETLINK_OVERRUN_RESYNC T_NICE T_IPV4_DEST_ADDR T_IPV6_DEST_ADDR %token T_SCHEDULER T_TYPE T_PRIO T_NETLINK_EVENTS_RELIABLE -%token T_DISABLE_EXTERNAL_CACHE T_ERROR_QUEUE_LENGTH +%token T_DISABLE_INTERNAL_CACHE T_DISABLE_EXTERNAL_CACHE T_ERROR_QUEUE_LENGTH %token T_IP T_PATH_VAL %token T_NUMBER @@ -852,9 +852,20 @@ sync_mode_notrack_list: sync_mode_notrack_line: timeout | purge + | disable_internal_cache | disable_external_cache ; +disable_internal_cache: T_DISABLE_INTERNAL_CACHE T_ON +{ + conf.sync.internal_cache_disable = 1; +}; + +disable_internal_cache: T_DISABLE_INTERNAL_CACHE T_OFF +{ + conf.sync.internal_cache_disable = 0; +}; + disable_external_cache: T_DISABLE_EXTERNAL_CACHE T_ON { conf.sync.external_cache_disable = 1; diff --git a/src/run.c b/src/run.c index 54ab1a5..803bbcc 100644 --- a/src/run.c +++ b/src/run.c @@ -28,6 +28,7 @@ #include "process.h" #include "origin.h" #include "date.h" +#include "internal.h" #include #include @@ -56,7 +57,9 @@ void killer(int foo) local_server_destroy(&STATE(local)); STATE(mode)->kill(); - nfct_close(STATE(dump)); /* cache_wt needs this here */ + if (STATE(mode)->internal->flags & INTERNAL_F_POPULATE) { + nfct_close(STATE(dump)); + } destroy_fds(STATE(fds)); unlink(CONFIG(lockfile)); @@ -210,9 +213,13 @@ static int local_handler(int fd, void *data) } break; case RESYNC_MASTER: - STATE(stats).nl_kernel_table_resync++; - dlog(LOG_NOTICE, "resync with master table"); - nl_dump_conntrack_table(STATE(dump)); + if (STATE(mode)->internal->flags & INTERNAL_F_POPULATE) { + STATE(stats).nl_kernel_table_resync++; + dlog(LOG_NOTICE, "resync with master table"); + nl_dump_conntrack_table(STATE(dump)); + } else { + dlog(LOG_NOTICE, "resync is unsupported in this mode"); + } break; case STATS_RUNTIME: dump_stats_runtime(fd); @@ -238,8 +245,8 @@ static void do_overrun_resync_alarm(struct alarm_block *a, void *data) static void do_polling_alarm(struct alarm_block *a, void *data) { - if (STATE(mode)->purge) - STATE(mode)->purge(); + if (STATE(mode)->internal->purge) + STATE(mode)->internal->purge(); nl_send_resync(STATE(resync)); add_alarm(&STATE(polling_alarm), CONFIG(poll_kernel_secs), 0); @@ -264,13 +271,13 @@ static int event_handler(const struct nlmsghdr *nlh, switch(type) { case NFCT_T_NEW: - STATE(mode)->event_new(ct, origin_type); + STATE(mode)->internal->new(ct, origin_type); break; case NFCT_T_UPDATE: - STATE(mode)->event_upd(ct, origin_type); + STATE(mode)->internal->update(ct, origin_type); break; case NFCT_T_DESTROY: - if (STATE(mode)->event_dst(ct, origin_type)) + if (STATE(mode)->internal->destroy(ct, origin_type)) update_traffic_stats(ct); break; default: @@ -295,7 +302,7 @@ static int dump_handler(enum nf_conntrack_msg_type type, switch(type) { case NFCT_T_UPDATE: - STATE(mode)->dump(ct); + STATE(mode)->internal->populate(ct); break; default: STATE(stats).nl_dump_unknown_type++; @@ -371,23 +378,26 @@ init(void) } nfct_callback_register(STATE(resync), NFCT_T_ALL, - STATE(mode)->resync, + STATE(mode)->internal->resync, NULL); register_fd(nfct_fd(STATE(resync)), STATE(fds)); fcntl(nfct_fd(STATE(resync)), F_SETFL, O_NONBLOCK); - STATE(dump) = nfct_open(CONNTRACK, 0); - if (STATE(dump) == NULL) { - dlog(LOG_ERR, "can't open netlink handler: %s", - strerror(errno)); - dlog(LOG_ERR, "no ctnetlink kernel support?"); - return -1; - } - nfct_callback_register(STATE(dump), NFCT_T_ALL, dump_handler, NULL); + if (STATE(mode)->internal->flags & INTERNAL_F_POPULATE) { + STATE(dump) = nfct_open(CONNTRACK, 0); + if (STATE(dump) == NULL) { + dlog(LOG_ERR, "can't open netlink handler: %s", + strerror(errno)); + dlog(LOG_ERR, "no ctnetlink kernel support?"); + return -1; + } + nfct_callback_register(STATE(dump), NFCT_T_ALL, + dump_handler, NULL); - if (nl_dump_conntrack_table(STATE(dump)) == -1) { - dlog(LOG_ERR, "can't get kernel conntrack table"); - return -1; + if (nl_dump_conntrack_table(STATE(dump)) == -1) { + dlog(LOG_ERR, "can't get kernel conntrack table"); + return -1; + } } STATE(get) = nfct_open(CONNTRACK, 0); @@ -499,7 +509,9 @@ static void __run(struct timeval *next_alarm) * we resync ourselves. */ nl_resize_socket_buffer(STATE(event)); - if (CONFIG(nl_overrun_resync) > 0) { + if (CONFIG(nl_overrun_resync) > 0 && + STATE(mode)->internal->flags & + INTERNAL_F_RESYNC) { add_alarm(&STATE(resync_alarm), CONFIG(nl_overrun_resync),0); } @@ -523,8 +535,8 @@ static void __run(struct timeval *next_alarm) } if (FD_ISSET(nfct_fd(STATE(resync)), &readfds)) { nfct_catch(STATE(resync)); - if (STATE(mode)->purge) - STATE(mode)->purge(); + if (STATE(mode)->internal->purge) + STATE(mode)->internal->purge(); } } else { /* using polling mode */ diff --git a/src/stats-mode.c b/src/stats-mode.c index 5cfb638..0403ce2 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -21,6 +21,7 @@ #include "cache.h" #include "log.h" #include "conntrackd.h" +#include "internal.h" #include #include @@ -87,7 +88,7 @@ static int local_handler_stats(int fd, int type, void *data) return ret; } -static void dump_stats(struct nf_conntrack *ct) +static void populate_stats(struct nf_conntrack *ct) { nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES); nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS); @@ -134,11 +135,9 @@ static int purge_step(void *data1, void *data2) return 0; } -static int purge_stats(void) +static void purge_stats(void) { cache_iterate(STATE_STATS(cache), NULL, purge_step); - - return 0; } static void @@ -188,15 +187,20 @@ event_destroy_stats(struct nf_conntrack *ct, int origin) return 0; } +static struct internal_handler internal_cache_stats = { + .flags = INTERNAL_F_POPULATE | INTERNAL_F_RESYNC, + .populate = populate_stats, + .resync = resync_stats, + .purge = purge_stats, + .new = event_new_stats, + .update = event_update_stats, + .destroy = event_destroy_stats +}; + struct ct_mode stats_mode = { .init = init_stats, .run = NULL, .local = local_handler_stats, .kill = kill_stats, - .dump = dump_stats, - .resync = resync_stats, - .purge = purge_stats, - .event_new = event_new_stats, - .event_upd = event_update_stats, - .event_dst = event_destroy_stats + .internal = &internal_cache_stats, }; diff --git a/src/sync-alarm.c b/src/sync-alarm.c index 4757026..0fc7943 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -109,7 +109,8 @@ static int alarm_recv(const struct nethdr *net) static void alarm_enqueue(struct cache_object *obj, int query) { - struct cache_alarm *ca = cache_get_extra(STATE_SYNC(internal), obj); + struct cache_alarm *ca = + cache_get_extra(STATE(mode)->internal->data, obj); if (queue_add(STATE_SYNC(tx_queue), &ca->qnode)) cache_object_get(obj); } @@ -134,7 +135,7 @@ static int tx_queue_xmit(struct queue_node *n, const void *data) int type; ca = (struct cache_alarm *)n; - obj = cache_data_get_object(STATE_SYNC(internal), ca); + obj = cache_data_get_object(STATE(mode)->internal->data, ca); type = object_status_to_network_type(obj->status); net = BUILD_NETMSG(obj->ct, type); multichannel_send(STATE_SYNC(channel), net); diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 0d31e17..86edeab 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -166,7 +166,8 @@ static void ftfw_kill(void) static int do_cache_to_tx(void *data1, void *data2) { struct cache_object *obj = data2; - struct cache_ftfw *cn = cache_get_extra(STATE_SYNC(internal), obj); + struct cache_ftfw *cn = + cache_get_extra(STATE(mode)->internal->data, obj); if (queue_in(rs_queue, &cn->qnode)) { queue_del(&cn->qnode); @@ -224,7 +225,8 @@ static int ftfw_local(int fd, int type, void *data) break; case SEND_BULK: dlog(LOG_NOTICE, "sending bulk update"); - cache_iterate(STATE_SYNC(internal), NULL, do_cache_to_tx); + cache_iterate(STATE(mode)->internal->data, + NULL, do_cache_to_tx); break; case STATS_RSQUEUE: ftfw_local_queue(fd); @@ -303,7 +305,7 @@ static int rs_queue_empty(struct queue_node *n, const void *data) cn = (struct cache_ftfw *) n; if (h == NULL) { queue_del(n); - obj = cache_data_get_object(STATE_SYNC(internal), cn); + obj = cache_data_get_object(STATE(mode)->internal->data, cn); cache_object_put(obj); return 0; } @@ -314,7 +316,7 @@ static int rs_queue_empty(struct queue_node *n, const void *data) dp("queue: deleting from queue (seq=%u)\n", cn->seq); queue_del(n); - obj = cache_data_get_object(STATE_SYNC(internal), cn); + obj = cache_data_get_object(STATE(mode)->internal->data, cn); cache_object_put(obj); break; } @@ -347,7 +349,7 @@ static int digest_msg(const struct nethdr *net) } else if (IS_RESYNC(net)) { dp("RESYNC ALL\n"); - cache_iterate(STATE_SYNC(internal), NULL, do_cache_to_tx); + cache_iterate(STATE(mode)->internal->data, NULL, do_cache_to_tx); return MSG_CTL; } else if (IS_ALIVE(net)) @@ -464,7 +466,7 @@ static void rs_queue_purge_full(void) struct cache_object *obj; cn = (struct cache_ftfw *)n; - obj = cache_data_get_object(STATE_SYNC(internal), cn); + obj = cache_data_get_object(STATE(mode)->internal->data, cn); cache_object_put(obj); break; } @@ -512,7 +514,7 @@ static int tx_queue_xmit(struct queue_node *n, const void *data) struct nethdr *net; cn = (struct cache_ftfw *)n; - obj = cache_data_get_object(STATE_SYNC(internal), cn); + obj = cache_data_get_object(STATE(mode)->internal->data, cn); type = object_status_to_network_type(obj->status); net = BUILD_NETMSG(obj->ct, type); nethdr_set_hello(net); @@ -546,7 +548,8 @@ static void ftfw_xmit(void) static void ftfw_enqueue(struct cache_object *obj, int type) { - struct cache_ftfw *cn = cache_get_extra(STATE_SYNC(internal), obj); + struct cache_ftfw *cn = + cache_get_extra(STATE(mode)->internal->data, obj); if (queue_in(rs_queue, &cn->qnode)) { queue_del(&cn->qnode); queue_add(STATE_SYNC(tx_queue), &cn->qnode); diff --git a/src/sync-mode.c b/src/sync-mode.c index 63fae68..ecc2f0d 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -28,6 +28,7 @@ #include "queue.h" #include "process.h" #include "origin.h" +#include "internal.h" #include "external.h" #include @@ -246,7 +247,7 @@ static void do_reset_cache_alarm(struct alarm_block *a, void *data) exit(EXIT_SUCCESS); } /* this is not required if events don't get lost */ - cache_flush(STATE_SYNC(internal)); + STATE(mode)->internal->flush(); } static int init_sync(void) @@ -276,15 +277,15 @@ static int init_sync(void) if (STATE_SYNC(sync)->init) STATE_SYNC(sync)->init(); - STATE_SYNC(internal) = - cache_create("internal", - STATE_SYNC(sync)->internal_cache_flags, - STATE_SYNC(sync)->internal_cache_extra); + if (CONFIG(sync).internal_cache_disable == 0) { + STATE(mode)->internal = &internal_cache; + } else { + STATE(mode)->internal = &internal_bypass; + dlog(LOG_NOTICE, "disabling internal cache"); - if (!STATE_SYNC(internal)) { - dlog(LOG_ERR, "can't allocate memory for the internal cache"); - return -1; } + if (STATE(mode)->internal->init() == -1) + return -1; if (CONFIG(sync).external_cache_disable == 0) { STATE_SYNC(external) = &external_cache; @@ -389,7 +390,7 @@ static void run_sync(fd_set *readfds) static void kill_sync(void) { - cache_destroy(STATE_SYNC(internal)); + STATE(mode)->internal->close(); STATE_SYNC(external)->close(); multichannel_close(STATE_SYNC(channel)); @@ -466,7 +467,7 @@ static int local_handler_sync(int fd, int type, void *data) case DUMP_INTERNAL: ret = fork_process_new(CTD_PROC_ANY, 0, NULL, NULL); if (ret == 0) { - cache_dump(STATE_SYNC(internal), fd, NFCT_O_PLAIN); + STATE(mode)->internal->dump(fd, NFCT_O_PLAIN); exit(EXIT_SUCCESS); } break; @@ -480,7 +481,7 @@ static int local_handler_sync(int fd, int type, void *data) case DUMP_INT_XML: ret = fork_process_new(CTD_PROC_ANY, 0, NULL, NULL); if (ret == 0) { - cache_dump(STATE_SYNC(internal), fd, NFCT_O_XML); + STATE(mode)->internal->dump(fd, NFCT_O_XML); exit(EXIT_SUCCESS); } break; @@ -512,14 +513,14 @@ static int local_handler_sync(int fd, int type, void *data) /* inmediate flush, remove pending flush scheduled if any */ del_alarm(&STATE_SYNC(reset_cache_alarm)); dlog(LOG_NOTICE, "flushing caches"); - cache_flush(STATE_SYNC(internal)); + STATE(mode)->internal->flush(); STATE_SYNC(external)->flush(); break; case FLUSH_INT_CACHE: /* inmediate flush, remove pending flush scheduled if any */ del_alarm(&STATE_SYNC(reset_cache_alarm)); dlog(LOG_NOTICE, "flushing internal cache"); - cache_flush(STATE_SYNC(internal)); + STATE(mode)->internal->flush(); break; case FLUSH_EXT_CACHE: dlog(LOG_NOTICE, "flushing external cache"); @@ -529,7 +530,7 @@ static int local_handler_sync(int fd, int type, void *data) killer(0); break; case STATS: - cache_stats(STATE_SYNC(internal), fd); + STATE(mode)->internal->stats(fd); STATE_SYNC(external)->stats(fd); dump_traffic_stats(fd); multichannel_stats(STATE_SYNC(channel), fd); @@ -540,7 +541,7 @@ static int local_handler_sync(int fd, int type, void *data) multichannel_stats(STATE_SYNC(channel), fd); break; case STATS_CACHE: - cache_stats_extended(STATE_SYNC(internal), fd); + STATE(mode)->internal->stats_ext(fd); STATE_SYNC(external)->stats_ext(fd); break; case STATS_LINK: @@ -559,167 +560,10 @@ static int local_handler_sync(int fd, int type, void *data) return ret; } -static void sync_send(struct cache_object *obj, int query) -{ - STATE_SYNC(sync)->enqueue(obj, query); -} - -static void dump_sync(struct nf_conntrack *ct) -{ - /* This is required by kernels < 2.6.20 */ - nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES); - nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS); - nfct_attr_unset(ct, ATTR_REPL_COUNTER_BYTES); - nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS); - nfct_attr_unset(ct, ATTR_USE); - - cache_update_force(STATE_SYNC(internal), ct); -} - -static int purge_step(void *data1, void *data2) -{ - struct cache_object *obj = data2; - - STATE(get_retval) = 0; - nl_get_conntrack(STATE(get), obj->ct); /* modifies STATE(get_reval) */ - if (!STATE(get_retval)) { - if (obj->status != C_OBJ_DEAD) { - cache_object_set_status(obj, C_OBJ_DEAD); - sync_send(obj, NET_T_STATE_DEL); - cache_object_put(obj); - } - } - - return 0; -} - -static int purge_sync(void) -{ - cache_iterate(STATE_SYNC(internal), NULL, purge_step); - - return 0; -} - -static int resync_sync(enum nf_conntrack_msg_type type, - struct nf_conntrack *ct, - void *data) -{ - struct cache_object *obj; - - if (ct_filter_conntrack(ct, 1)) - return NFCT_CB_CONTINUE; - - /* This is required by kernels < 2.6.20 */ - nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES); - nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS); - nfct_attr_unset(ct, ATTR_REPL_COUNTER_BYTES); - nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS); - nfct_attr_unset(ct, ATTR_USE); - - obj = cache_update_force(STATE_SYNC(internal), ct); - if (obj == NULL) - return NFCT_CB_CONTINUE; - - switch (obj->status) { - case C_OBJ_NEW: - sync_send(obj, NET_T_STATE_NEW); - break; - case C_OBJ_ALIVE: - sync_send(obj, NET_T_STATE_UPD); - break; - } - return NFCT_CB_CONTINUE; -} - -static void -event_new_sync(struct nf_conntrack *ct, int origin) -{ - struct cache_object *obj; - int id; - - /* this event has been triggered by a direct inject, skip */ - if (origin == CTD_ORIGIN_INJECT) - return; - - /* required by linux kernel <= 2.6.20 */ - nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES); - nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS); - nfct_attr_unset(ct, ATTR_REPL_COUNTER_BYTES); - nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS); - - obj = cache_find(STATE_SYNC(internal), ct, &id); - if (obj == NULL) { -retry: - obj = cache_object_new(STATE_SYNC(internal), ct); - if (obj == NULL) - return; - if (cache_add(STATE_SYNC(internal), obj, id) == -1) { - cache_object_free(obj); - return; - } - /* only synchronize events that have been triggered by other - * processes or the kernel, but don't propagate events that - * have been triggered by conntrackd itself, eg. commits. */ - if (origin == CTD_ORIGIN_NOT_ME) - sync_send(obj, NET_T_STATE_NEW); - } else { - cache_del(STATE_SYNC(internal), obj); - cache_object_free(obj); - goto retry; - } -} - -static void -event_update_sync(struct nf_conntrack *ct, int origin) -{ - struct cache_object *obj; - - /* this event has been triggered by a direct inject, skip */ - if (origin == CTD_ORIGIN_INJECT) - return; - - obj = cache_update_force(STATE_SYNC(internal), ct); - if (obj == NULL) - return; - - if (origin == CTD_ORIGIN_NOT_ME) - sync_send(obj, NET_T_STATE_UPD); -} - -static int -event_destroy_sync(struct nf_conntrack *ct, int origin) -{ - struct cache_object *obj; - int id; - - /* this event has been triggered by a direct inject, skip */ - if (origin == CTD_ORIGIN_INJECT) - return 0; - - /* we don't synchronize events for objects that are not in the cache */ - obj = cache_find(STATE_SYNC(internal), ct, &id); - if (obj == NULL) - return 0; - - if (obj->status != C_OBJ_DEAD) { - cache_object_set_status(obj, C_OBJ_DEAD); - if (origin == CTD_ORIGIN_NOT_ME) { - sync_send(obj, NET_T_STATE_DEL); - } - cache_object_put(obj); - } - return 1; -} - struct ct_mode sync_mode = { .init = init_sync, .run = run_sync, .local = local_handler_sync, .kill = kill_sync, - .dump = dump_sync, - .resync = resync_sync, - .purge = purge_sync, - .event_new = event_new_sync, - .event_upd = event_update_sync, - .event_dst = event_destroy_sync + /* the internal handler is set in run-time. */ }; diff --git a/src/sync-notrack.c b/src/sync-notrack.c index d9f273e..c4ad941 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -74,12 +74,44 @@ static void tx_queue_add_ctlmsg(uint32_t flags, uint32_t from, uint32_t to) static int do_cache_to_tx(void *data1, void *data2) { struct cache_object *obj = data2; - struct cache_notrack *cn = cache_get_extra(STATE_SYNC(internal), obj); + struct cache_notrack *cn = + cache_get_extra(STATE(mode)->internal->data, obj); if (queue_add(STATE_SYNC(tx_queue), &cn->qnode)) cache_object_get(obj); return 0; } +static int kernel_resync_cb(enum nf_conntrack_msg_type type, + struct nf_conntrack *ct, void *data) +{ + struct nethdr *net; + + net = BUILD_NETMSG(ct, NET_T_STATE_NEW); + multichannel_send(STATE_SYNC(channel), net); + + return NFCT_CB_CONTINUE; +} + +/* Only used if the internal cache is disabled. */ +static void kernel_resync(void) +{ + struct nfct_handle *h; + u_int32_t family = AF_UNSPEC; + int ret; + + h = nfct_open(CONNTRACK, 0); + if (h == NULL) { + dlog(LOG_ERR, "can't allocate memory for the internal cache"); + return; + } + nfct_callback_register(h, NFCT_T_ALL, kernel_resync_cb, NULL); + ret = nfct_query(h, NFCT_Q_DUMP, &family); + if (ret == -1) { + dlog(LOG_ERR, "can't dump kernel table"); + } + nfct_close(h); +} + static int notrack_local(int fd, int type, void *data) { int ret = LOCAL_RET_OK; @@ -91,7 +123,12 @@ static int notrack_local(int fd, int type, void *data) break; case SEND_BULK: dlog(LOG_NOTICE, "sending bulk update"); - cache_iterate(STATE_SYNC(internal), NULL, do_cache_to_tx); + if (CONFIG(sync).internal_cache_disable) { + kernel_resync(); + } else { + cache_iterate(STATE(mode)->internal->data, + NULL, do_cache_to_tx); + } break; default: ret = 0; @@ -107,7 +144,12 @@ static int digest_msg(const struct nethdr *net) return MSG_DATA; if (IS_RESYNC(net)) { - cache_iterate(STATE_SYNC(internal), NULL, do_cache_to_tx); + if (CONFIG(sync).internal_cache_disable) { + kernel_resync(); + } else { + cache_iterate(STATE(mode)->internal->data, + NULL, do_cache_to_tx); + } return MSG_CTL; } @@ -154,7 +196,7 @@ static int tx_queue_xmit(struct queue_node *n, const void *data2) struct nethdr *net; cn = (struct cache_ftfw *)n; - obj = cache_data_get_object(STATE_SYNC(internal), cn); + obj = cache_data_get_object(STATE(mode)->internal->data, cn); type = object_status_to_network_type(obj->status);; net = BUILD_NETMSG(obj->ct, type); @@ -175,7 +217,8 @@ static void notrack_xmit(void) static void notrack_enqueue(struct cache_object *obj, int query) { - struct cache_notrack *cn = cache_get_extra(STATE_SYNC(internal), obj); + struct cache_notrack *cn = + cache_get_extra(STATE(mode)->internal->data, obj); if (queue_add(STATE_SYNC(tx_queue), &cn->qnode)) cache_object_get(obj); } -- cgit v1.2.3 From 8da00687d65f06160827e4cd469c330d3a73a9d9 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 4 Jan 2012 14:16:57 +0100 Subject: conntrackd: fix checking of return value of queue_add() Most callers of queue_add() assume that it returns != 0 in case of success. However, it may return -1 in case that the queue gets full. In that case, most callers have to: - release the object that they want to enqueue. - decrement the refcount, in case they have bumped it. However, most of these callers are using the tx_queue which currently has no limit in size at all. This fix is necessary in case that I decide to limit the size of the transmission queue in the future (which makes a lot of sense indeed). Signed-off-by: Pablo Neira Ayuso --- src/sync-alarm.c | 2 +- src/sync-ftfw.c | 10 ++++++---- src/sync-notrack.c | 10 ++++++---- 3 files changed, 13 insertions(+), 9 deletions(-) (limited to 'src/sync-notrack.c') diff --git a/src/sync-alarm.c b/src/sync-alarm.c index 0fc7943..b555dd5 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -111,7 +111,7 @@ static void alarm_enqueue(struct cache_object *obj, int query) { struct cache_alarm *ca = cache_get_extra(STATE(mode)->internal->data, obj); - if (queue_add(STATE_SYNC(tx_queue), &ca->qnode)) + if (queue_add(STATE_SYNC(tx_queue), &ca->qnode) > 0) cache_object_get(obj); } diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 86edeab..581b5ca 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -107,7 +107,8 @@ static void tx_queue_add_ctlmsg(uint32_t flags, uint32_t from, uint32_t to) ack->from = from; ack->to = to; - queue_add(STATE_SYNC(tx_queue), &qobj->qnode); + if (queue_add(STATE_SYNC(tx_queue), &qobj->qnode) < 0) + queue_object_free(qobj); } static void tx_queue_add_ctlmsg2(uint32_t flags) @@ -123,7 +124,8 @@ static void tx_queue_add_ctlmsg2(uint32_t flags) ctl->type = NET_T_CTL; ctl->flags = flags; - queue_add(STATE_SYNC(tx_queue), &qobj->qnode); + if (queue_add(STATE_SYNC(tx_queue), &qobj->qnode) < 0) + queue_object_free(qobj); } /* this function is called from the alarm framework */ @@ -173,7 +175,7 @@ static int do_cache_to_tx(void *data1, void *data2) queue_del(&cn->qnode); queue_add(STATE_SYNC(tx_queue), &cn->qnode); } else { - if (queue_add(STATE_SYNC(tx_queue), &cn->qnode)) + if (queue_add(STATE_SYNC(tx_queue), &cn->qnode) > 0) cache_object_get(obj); } return 0; @@ -554,7 +556,7 @@ static void ftfw_enqueue(struct cache_object *obj, int type) queue_del(&cn->qnode); queue_add(STATE_SYNC(tx_queue), &cn->qnode); } else { - if (queue_add(STATE_SYNC(tx_queue), &cn->qnode)) + if (queue_add(STATE_SYNC(tx_queue), &cn->qnode) > 0) cache_object_get(obj); } } diff --git a/src/sync-notrack.c b/src/sync-notrack.c index c4ad941..06af58b 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -68,7 +68,8 @@ static void tx_queue_add_ctlmsg(uint32_t flags, uint32_t from, uint32_t to) ack->from = from; ack->to = to; - queue_add(STATE_SYNC(tx_queue), &qobj->qnode); + if (queue_add(STATE_SYNC(tx_queue), &qobj->qnode) < 0) + queue_object_free(qobj); } static int do_cache_to_tx(void *data1, void *data2) @@ -76,7 +77,7 @@ static int do_cache_to_tx(void *data1, void *data2) struct cache_object *obj = data2; struct cache_notrack *cn = cache_get_extra(STATE(mode)->internal->data, obj); - if (queue_add(STATE_SYNC(tx_queue), &cn->qnode)) + if (queue_add(STATE_SYNC(tx_queue), &cn->qnode) > 0) cache_object_get(obj); return 0; } @@ -219,7 +220,7 @@ static void notrack_enqueue(struct cache_object *obj, int query) { struct cache_notrack *cn = cache_get_extra(STATE(mode)->internal->data, obj); - if (queue_add(STATE_SYNC(tx_queue), &cn->qnode)) + if (queue_add(STATE_SYNC(tx_queue), &cn->qnode) > 0) cache_object_get(obj); } @@ -236,7 +237,8 @@ static void tx_queue_add_ctlmsg2(uint32_t flags) ctl->type = NET_T_CTL; ctl->flags = flags; - queue_add(STATE_SYNC(tx_queue), &qobj->qnode); + if (queue_add(STATE_SYNC(tx_queue), &qobj->qnode) < 0) + queue_object_free(qobj); } static void do_alive_alarm(struct alarm_block *a, void *data) -- cgit v1.2.3 From 65be3d49b0f4350a227dedd70ac17c7c9cf6274e Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 4 Jan 2012 14:28:50 +0100 Subject: conntrackd: generalize caching infrastructure This patch generalizes the caching infrastructure to store different object types. This patch is the first in the series to prepare support for the synchronization of expectations. Signed-off-by: Pablo Neira Ayuso --- include/cache.h | 57 +++++++- include/internal.h | 27 ++-- src/Makefile.am | 2 +- src/cache-ct.c | 358 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/cache.c | 154 +++++++++------------- src/cache_iterators.c | 268 ------------------------------------- src/external_cache.c | 4 +- src/internal_bypass.c | 67 +++++----- src/internal_cache.c | 104 ++++++++------- src/run.c | 23 ++-- src/stats-mode.c | 42 +++--- src/sync-alarm.c | 11 +- src/sync-ftfw.c | 23 ++-- src/sync-mode.c | 19 +-- src/sync-notrack.c | 12 +- 15 files changed, 647 insertions(+), 524 deletions(-) create mode 100644 src/cache-ct.c delete mode 100644 src/cache_iterators.c (limited to 'src/sync-notrack.c') diff --git a/include/cache.h b/include/cache.h index ddf2049..a42e395 100644 --- a/include/cache.h +++ b/include/cache.h @@ -27,7 +27,7 @@ enum { struct cache; struct cache_object { struct hashtable_node hashnode; - struct nf_conntrack *ct; + void *ptr; struct cache *cache; int status; int refcnt; @@ -48,14 +48,22 @@ extern struct cache_feature timer_feature; #define CACHE_MAX_NAMELEN 32 +enum cache_type { + CACHE_T_NONE = 0, + CACHE_T_CT, + CACHE_T_MAX +}; + struct cache { char name[CACHE_MAX_NAMELEN]; + enum cache_type type; struct hashtable *h; unsigned int num_features; struct cache_feature **features; unsigned int feature_type[CACHE_MAX_FEATURE]; unsigned int *feature_offset; + struct cache_ops *ops; struct cache_extra *extra; unsigned int extra_offset; size_t object_size; @@ -94,22 +102,48 @@ struct cache_extra { void (*destroy)(struct cache_object *obj, void *data); }; +struct nfct_handle; + +/* cache options depends on the object type: conntrack or expectation. */ +struct cache_ops { + /* hashing and comparison of objects. */ + uint32_t (*hash)(const void *data, const struct hashtable *table); + int (*cmp)(const void *data1, const void *data2); + + /* object allocation, copy and release. */ + void *(*alloc)(void); + void (*copy)(void *dst, void *src, unsigned int flags); + void (*free)(void *ptr); + + /* dump and commit. */ + int (*dump_step)(void *data1, void *n); + int (*commit)(struct cache *c, struct nfct_handle *h, int clientfd); + + /* build network message from object. */ + struct nethdr *(*build_msg)(const struct cache_object *obj, int type); +}; + +/* templates to configure conntrack caching. */ +extern struct cache_ops cache_sync_internal_ct_ops; +extern struct cache_ops cache_sync_external_ct_ops; +extern struct cache_ops cache_stats_ct_ops; + struct nf_conntrack; -struct cache *cache_create(const char *name, unsigned int features, struct cache_extra *extra); +struct cache *cache_create(const char *name, enum cache_type type, unsigned int features, struct cache_extra *extra, struct cache_ops *ops); void cache_destroy(struct cache *e); -struct cache_object *cache_object_new(struct cache *c, struct nf_conntrack *ct); +struct cache_object *cache_object_new(struct cache *c, void *ptr); void cache_object_free(struct cache_object *obj); void cache_object_get(struct cache_object *obj); int cache_object_put(struct cache_object *obj); void cache_object_set_status(struct cache_object *obj, int status); int cache_add(struct cache *c, struct cache_object *obj, int id); -void cache_update(struct cache *c, struct cache_object *obj, int id, struct nf_conntrack *ct); -struct cache_object *cache_update_force(struct cache *c, struct nf_conntrack *ct); +void cache_update(struct cache *c, struct cache_object *obj, int id, void *ptr); +struct cache_object *cache_update_force(struct cache *c, void *ptr); void cache_del(struct cache *c, struct cache_object *obj); -struct cache_object *cache_find(struct cache *c, struct nf_conntrack *ct, int *pos); +struct cache_object *cache_find(struct cache *c, void *ptr, int *pos); void cache_stats(const struct cache *c, int fd); void cache_stats_extended(const struct cache *c, int fd); struct cache_object *cache_data_get_object(struct cache *c, void *data); @@ -120,7 +154,18 @@ void cache_iterate_limit(struct cache *c, void *data, uint32_t from, uint32_t st /* iterators */ struct nfct_handle; +struct __dump_container { + int fd; + int type; +}; + void cache_dump(struct cache *c, int fd, int type); + +struct __commit_container { + struct nfct_handle *h; + struct cache *c; +}; + int cache_commit(struct cache *c, struct nfct_handle *h, int clientfd); void cache_flush(struct cache *c); void cache_bulk(struct cache *c); diff --git a/include/internal.h b/include/internal.h index 1f11340..f50eb79 100644 --- a/include/internal.h +++ b/include/internal.h @@ -12,25 +12,28 @@ enum { }; struct internal_handler { - void *data; unsigned int flags; int (*init)(void); void (*close)(void); - void (*new)(struct nf_conntrack *ct, int origin_type); - void (*update)(struct nf_conntrack *ct, int origin_type); - int (*destroy)(struct nf_conntrack *ct, int origin_type); + struct { + void *data; - void (*dump)(int fd, int type); - void (*populate)(struct nf_conntrack *ct); - void (*purge)(void); - int (*resync)(enum nf_conntrack_msg_type type, - struct nf_conntrack *ct, void *data); - void (*flush)(void); + void (*new)(struct nf_conntrack *ct, int origin_type); + void (*upd)(struct nf_conntrack *ct, int origin_type); + int (*del)(struct nf_conntrack *ct, int origin_type); - void (*stats)(int fd); - void (*stats_ext)(int fd); + void (*dump)(int fd, int type); + void (*populate)(struct nf_conntrack *ct); + void (*purge)(void); + int (*resync)(enum nf_conntrack_msg_type type, + struct nf_conntrack *ct, void *data); + void (*flush)(void); + + void (*stats)(int fd); + void (*stats_ext)(int fd); + } ct; }; extern struct internal_handler internal_cache; diff --git a/src/Makefile.am b/src/Makefile.am index 70e496d..a0abeee 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -12,7 +12,7 @@ conntrack_LDADD = ../extensions/libct_proto_tcp.la ../extensions/libct_proto_udp conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c rbtree.c \ local.c log.c mcast.c udp.c netlink.c vector.c \ filter.c fds.c event.c process.c origin.c date.c \ - cache.c cache_iterators.c \ + cache.c cache-ct.c \ cache_timer.c \ sync-mode.c sync-alarm.c sync-ftfw.c sync-notrack.c \ traffic_stats.c stats-mode.c \ diff --git a/src/cache-ct.c b/src/cache-ct.c new file mode 100644 index 0000000..2c6fd4e --- /dev/null +++ b/src/cache-ct.c @@ -0,0 +1,358 @@ +/* + * (C) 2006-2011 by Pablo Neira Ayuso + * (C) 2011 by Vyatta Inc. + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "cache.h" +#include "hash.h" +#include "log.h" +#include "conntrackd.h" +#include "netlink.h" +#include "event.h" +#include "jhash.h" +#include "network.h" + +#include +#include +#include +#include + +static uint32_t +cache_hash4_ct(const struct nf_conntrack *ct, const struct hashtable *table) +{ + uint32_t a[4] = { + [0] = nfct_get_attr_u32(ct, ATTR_IPV4_SRC), + [1] = nfct_get_attr_u32(ct, ATTR_IPV4_DST), + [2] = nfct_get_attr_u8(ct, ATTR_L3PROTO) << 16 | + nfct_get_attr_u8(ct, ATTR_L4PROTO), + [3] = nfct_get_attr_u16(ct, ATTR_PORT_SRC) << 16 | + nfct_get_attr_u16(ct, ATTR_PORT_DST), + }; + + /* + * Instead of returning hash % table->hashsize (implying a divide) + * we return the high 32 bits of the (hash * table->hashsize) that will + * give results between [0 and hashsize-1] and same hash distribution, + * but using a multiply, less expensive than a divide. See: + * http://www.mail-archive.com/netdev@vger.kernel.org/msg56623.html + */ + return ((uint64_t)jhash2(a, 4, 0) * table->hashsize) >> 32; +} + +static uint32_t +cache_hash6_ct(const struct nf_conntrack *ct, const struct hashtable *table) +{ + uint32_t a[10]; + + memcpy(&a[0], nfct_get_attr(ct, ATTR_IPV6_SRC), sizeof(uint32_t)*4); + memcpy(&a[4], nfct_get_attr(ct, ATTR_IPV6_SRC), sizeof(uint32_t)*4); + a[8] = nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO) << 16 | + nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO); + a[9] = nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC) << 16 | + nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST); + + return ((uint64_t)jhash2(a, 10, 0) * table->hashsize) >> 32; +} + +static uint32_t +cache_ct_hash(const void *data, const struct hashtable *table) +{ + int ret = 0; + const struct nf_conntrack *ct = data; + + switch(nfct_get_attr_u8(ct, ATTR_L3PROTO)) { + case AF_INET: + ret = cache_hash4_ct(ct, table); + break; + case AF_INET6: + ret = cache_hash6_ct(ct, table); + break; + default: + dlog(LOG_ERR, "unknown layer 3 proto in hash"); + break; + } + return ret; +} + +static int cache_ct_cmp(const void *data1, const void *data2) +{ + const struct cache_object *obj = data1; + const struct nf_conntrack *ct = data2; + + return nfct_cmp(obj->ptr, ct, NFCT_CMP_ORIG) && + nfct_get_attr_u32(obj->ptr, ATTR_ID) == + nfct_get_attr_u32(ct, ATTR_ID); +} + +static void *cache_ct_alloc(void) +{ + return nfct_new(); +} + +static void cache_ct_free(void *ptr) +{ + nfct_destroy(ptr); +} + +static void cache_ct_copy(void *dst, void *src, unsigned int flags) +{ + nfct_copy(dst, src, flags); +} + +static int cache_ct_dump_step(void *data1, void *n) +{ + char buf[1024]; + int size; + struct __dump_container *container = data1; + struct cache_object *obj = n; + char *data = obj->data; + unsigned i; + + /* + * XXX: Do not dump the entries that are scheduled to expire. + * These entries talk about already destroyed connections + * that we keep for some time just in case that we have to + * resent some lost messages. We do not show them to the + * user as he may think that the firewall replicas are not + * in sync. The branch below is a hack as it is quite + * specific and it breaks conntrackd modularity. Probably + * there's a nicer way to do this but until I come up with it... + */ + if (CONFIG(flags) & CTD_SYNC_FTFW && obj->status == C_OBJ_DEAD) + return 0; + + /* do not show cached timeout, this may confuse users */ + if (nfct_attr_is_set(obj->ptr, ATTR_TIMEOUT)) + nfct_attr_unset(obj->ptr, ATTR_TIMEOUT); + + memset(buf, 0, sizeof(buf)); + size = nfct_snprintf(buf, + sizeof(buf), + obj->ptr, + NFCT_T_UNKNOWN, + container->type, + 0); + + for (i = 0; i < obj->cache->num_features; i++) { + if (obj->cache->features[i]->dump) { + size += obj->cache->features[i]->dump(obj, + data, + buf+size, + container->type); + data += obj->cache->features[i]->size; + } + } + if (container->type != NFCT_O_XML) { + long tm = time(NULL); + size += sprintf(buf+size, " [active since %lds]", + tm - obj->lifetime); + } + size += sprintf(buf+size, "\n"); + if (send(container->fd, buf, size, 0) == -1) { + if (errno != EPIPE) + return -1; + } + + return 0; +} + +static void +cache_ct_commit_step(struct __commit_container *tmp, struct cache_object *obj) +{ + int ret, retry = 1, timeout; + struct nf_conntrack *ct = obj->ptr; + + if (CONFIG(commit_timeout)) { + timeout = CONFIG(commit_timeout); + } else { + timeout = time(NULL) - obj->lastupdate; + if (timeout < 0) { + /* XXX: Arbitrarily set the timer to one minute, how + * can this happen? For example, an adjustment due to + * daylight-saving. Probably other situations can + * trigger this. */ + timeout = 60; + } + /* calculate an estimation of the current timeout */ + timeout = nfct_get_attr_u32(ct, ATTR_TIMEOUT) - timeout; + if (timeout < 0) { + timeout = 60; + } + } + +retry: + if (nl_create_conntrack(tmp->h, ct, timeout) == -1) { + if (errno == EEXIST && retry == 1) { + ret = nl_destroy_conntrack(tmp->h, ct); + if (ret == 0 || (ret == -1 && errno == ENOENT)) { + if (retry) { + retry = 0; + goto retry; + } + } + dlog(LOG_ERR, "commit-destroy: %s", strerror(errno)); + dlog_ct(STATE(log), ct, NFCT_O_PLAIN); + tmp->c->stats.commit_fail++; + } else { + dlog(LOG_ERR, "commit-create: %s", strerror(errno)); + dlog_ct(STATE(log), ct, NFCT_O_PLAIN); + tmp->c->stats.commit_fail++; + } + } else { + tmp->c->stats.commit_ok++; + } +} + +static int cache_ct_commit_related(void *data, void *n) +{ + struct cache_object *obj = n; + + if (ct_is_related(obj->ptr)) + cache_ct_commit_step(data, obj); + + /* keep iterating even if we have found errors */ + return 0; +} + +static int cache_ct_commit_master(void *data, void *n) +{ + struct cache_object *obj = n; + + if (ct_is_related(obj->ptr)) + return 0; + + cache_ct_commit_step(data, obj); + return 0; +} + +static int cache_ct_commit(struct cache *c, struct nfct_handle *h, int clientfd) +{ + unsigned int commit_ok, commit_fail; + struct __commit_container tmp = { + .h = h, + .c = c, + }; + struct timeval commit_stop, res; + + /* we already have one commit in progress, skip this. The clientfd + * descriptor has to be closed by the caller. */ + if (clientfd && STATE_SYNC(commit).clientfd != -1) + return 0; + + switch(STATE_SYNC(commit).state) { + case COMMIT_STATE_INACTIVE: + gettimeofday(&STATE_SYNC(commit).stats.start, NULL); + STATE_SYNC(commit).stats.ok = c->stats.commit_ok; + STATE_SYNC(commit).stats.fail = c->stats.commit_fail; + STATE_SYNC(commit).clientfd = clientfd; + case COMMIT_STATE_MASTER: + STATE_SYNC(commit).current = + hashtable_iterate_limit(c->h, &tmp, + STATE_SYNC(commit).current, + CONFIG(general).commit_steps, + cache_ct_commit_master); + if (STATE_SYNC(commit).current < CONFIG(hashsize)) { + STATE_SYNC(commit).state = COMMIT_STATE_MASTER; + /* give it another step as soon as possible */ + write_evfd(STATE_SYNC(commit).evfd); + return 1; + } + STATE_SYNC(commit).current = 0; + STATE_SYNC(commit).state = COMMIT_STATE_RELATED; + case COMMIT_STATE_RELATED: + STATE_SYNC(commit).current = + hashtable_iterate_limit(c->h, &tmp, + STATE_SYNC(commit).current, + CONFIG(general).commit_steps, + cache_ct_commit_related); + if (STATE_SYNC(commit).current < CONFIG(hashsize)) { + STATE_SYNC(commit).state = COMMIT_STATE_RELATED; + /* give it another step as soon as possible */ + write_evfd(STATE_SYNC(commit).evfd); + return 1; + } + /* calculate the time that commit has taken */ + gettimeofday(&commit_stop, NULL); + timersub(&commit_stop, &STATE_SYNC(commit).stats.start, &res); + + /* calculate new entries committed */ + commit_ok = c->stats.commit_ok - STATE_SYNC(commit).stats.ok; + commit_fail = + c->stats.commit_fail - STATE_SYNC(commit).stats.fail; + + /* log results */ + dlog(LOG_NOTICE, "Committed %u new entries", commit_ok); + + if (commit_fail) + dlog(LOG_NOTICE, "%u entries can't be " + "committed", commit_fail); + + dlog(LOG_NOTICE, "commit has taken %lu.%06lu seconds", + res.tv_sec, res.tv_usec); + + /* prepare the state machine for new commits */ + STATE_SYNC(commit).current = 0; + STATE_SYNC(commit).state = COMMIT_STATE_INACTIVE; + + /* Close the client socket now that we're done. */ + close(STATE_SYNC(commit).clientfd); + STATE_SYNC(commit).clientfd = -1; + } + return 1; +} + +static struct nethdr * +cache_ct_build_msg(const struct cache_object *obj, int type) +{ + return BUILD_NETMSG_FROM_CT(obj->ptr, type); +} + +/* template to cache conntracks coming from the kernel. */ +struct cache_ops cache_sync_internal_ct_ops = { + .hash = cache_ct_hash, + .cmp = cache_ct_cmp, + .alloc = cache_ct_alloc, + .free = cache_ct_free, + .copy = cache_ct_copy, + .dump_step = cache_ct_dump_step, + .commit = NULL, + .build_msg = cache_ct_build_msg, +}; + +/* template to cache conntracks coming from the network. */ +struct cache_ops cache_sync_external_ct_ops = { + .hash = cache_ct_hash, + .cmp = cache_ct_cmp, + .alloc = cache_ct_alloc, + .free = cache_ct_free, + .copy = cache_ct_copy, + .dump_step = cache_ct_dump_step, + .commit = cache_ct_commit, + .build_msg = NULL, +}; + +/* template to cache conntracks for the statistics mode. */ +struct cache_ops cache_stats_ct_ops = { + .hash = cache_ct_hash, + .cmp = cache_ct_cmp, + .alloc = cache_ct_alloc, + .free = cache_ct_free, + .copy = cache_ct_copy, + .dump_step = cache_ct_dump_step, + .commit = NULL, + .build_msg = NULL, +}; diff --git a/src/cache.c b/src/cache.c index f411121..efdab0e 100644 --- a/src/cache.c +++ b/src/cache.c @@ -1,5 +1,6 @@ /* - * (C) 2006-2009 by Pablo Neira Ayuso + * (C) 2006-2011 by Pablo Neira Ayuso + * (C) 2011 by Vyatta Inc. * * 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 @@ -28,80 +29,14 @@ #include #include -static uint32_t -__hash4(const struct nf_conntrack *ct, const struct hashtable *table) -{ - uint32_t a[4] = { - [0] = nfct_get_attr_u32(ct, ATTR_IPV4_SRC), - [1] = nfct_get_attr_u32(ct, ATTR_IPV4_DST), - [2] = nfct_get_attr_u8(ct, ATTR_L3PROTO) << 16 | - nfct_get_attr_u8(ct, ATTR_L4PROTO), - [3] = nfct_get_attr_u16(ct, ATTR_PORT_SRC) << 16 | - nfct_get_attr_u16(ct, ATTR_PORT_DST), - }; - - /* - * Instead of returning hash % table->hashsize (implying a divide) - * we return the high 32 bits of the (hash * table->hashsize) that will - * give results between [0 and hashsize-1] and same hash distribution, - * but using a multiply, less expensive than a divide. See: - * http://www.mail-archive.com/netdev@vger.kernel.org/msg56623.html - */ - return ((uint64_t)jhash2(a, 4, 0) * table->hashsize) >> 32; -} - -static uint32_t -__hash6(const struct nf_conntrack *ct, const struct hashtable *table) -{ - uint32_t a[10]; - - memcpy(&a[0], nfct_get_attr(ct, ATTR_IPV6_SRC), sizeof(uint32_t)*4); - memcpy(&a[4], nfct_get_attr(ct, ATTR_IPV6_SRC), sizeof(uint32_t)*4); - a[8] = nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO) << 16 | - nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO); - a[9] = nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC) << 16 | - nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST); - - return ((uint64_t)jhash2(a, 10, 0) * table->hashsize) >> 32; -} - -static uint32_t hash(const void *data, const struct hashtable *table) -{ - int ret = 0; - const struct nf_conntrack *ct = data; - - switch(nfct_get_attr_u8(ct, ATTR_L3PROTO)) { - case AF_INET: - ret = __hash4(ct, table); - break; - case AF_INET6: - ret = __hash6(ct, table); - break; - default: - dlog(LOG_ERR, "unknown layer 3 proto in hash"); - break; - } - - return ret; -} - -static int compare(const void *data1, const void *data2) -{ - const struct cache_object *obj = data1; - const struct nf_conntrack *ct = data2; - - return nfct_cmp(obj->ct, ct, NFCT_CMP_ORIG) && - nfct_get_attr_u32(obj->ct, ATTR_ID) == - nfct_get_attr_u32(ct, ATTR_ID); -} - struct cache_feature *cache_feature[CACHE_MAX_FEATURE] = { [TIMER_FEATURE] = &timer_feature, }; -struct cache *cache_create(const char *name, +struct cache *cache_create(const char *name, enum cache_type type, unsigned int features, - struct cache_extra *extra) + struct cache_extra *extra, + struct cache_ops *ops) { size_t size = sizeof(struct cache_object); int i, j = 0; @@ -110,12 +45,16 @@ struct cache *cache_create(const char *name, unsigned int feature_offset[CACHE_MAX_FEATURE] = {}; unsigned int feature_type[CACHE_MAX_FEATURE] = {}; + if (type == CACHE_T_NONE || type >= CACHE_T_MAX) + return NULL; + c = malloc(sizeof(struct cache)); if (!c) return NULL; memset(c, 0, sizeof(struct cache)); strcpy(c->name, name); + c->type = type; for (i = 0; i < CACHE_MAX_FEATURE; i++) { if ((1 << i) & features) { @@ -150,11 +89,19 @@ struct cache *cache_create(const char *name, } memcpy(c->feature_offset, feature_offset, sizeof(unsigned int) * j); + if (!ops || !ops->hash || !ops->cmp || + !ops->alloc || !ops->copy || !ops->free) { + free(c->feature_offset); + free(c->features); + free(c); + return NULL; + } + c->ops = ops; + c->h = hashtable_create(CONFIG(hashsize), CONFIG(limit), - hash, - compare); - + c->ops->hash, + c->ops->cmp); if (!c->h) { free(c->features); free(c->feature_offset); @@ -175,7 +122,7 @@ void cache_destroy(struct cache *c) free(c); } -struct cache_object *cache_object_new(struct cache *c, struct nf_conntrack *ct) +struct cache_object *cache_object_new(struct cache *c, void *ptr) { struct cache_object *obj; @@ -187,13 +134,14 @@ struct cache_object *cache_object_new(struct cache *c, struct nf_conntrack *ct) } obj->cache = c; - if ((obj->ct = nfct_new()) == NULL) { + obj->ptr = c->ops->alloc(); + if (obj->ptr == NULL) { free(obj); errno = ENOMEM; c->stats.add_fail_enomem++; return NULL; } - nfct_copy(obj->ct, ct, NFCT_CP_OVERRIDE); + c->ops->copy(obj->ptr, ptr, NFCT_CP_OVERRIDE); obj->status = C_OBJ_NONE; c->stats.objects++; @@ -203,7 +151,8 @@ struct cache_object *cache_object_new(struct cache *c, struct nf_conntrack *ct) void cache_object_free(struct cache_object *obj) { obj->cache->stats.objects--; - nfct_destroy(obj->ct); + obj->cache->ops->free(obj->ptr); + free(obj); } @@ -271,13 +220,12 @@ int cache_add(struct cache *c, struct cache_object *obj, int id) return 0; } -void cache_update(struct cache *c, struct cache_object *obj, int id, - struct nf_conntrack *ct) +void cache_update(struct cache *c, struct cache_object *obj, int id, void *ptr) { char *data = obj->data; unsigned int i; - nfct_copy(obj->ct, ct, NFCT_CP_META); + c->ops->copy(obj->ptr, ptr, NFCT_CP_META); for (i = 0; i < c->num_features; i++) { c->features[i]->update(obj, data); @@ -322,23 +270,22 @@ void cache_del(struct cache *c, struct cache_object *obj) __del(c, obj); } -struct cache_object * -cache_update_force(struct cache *c, struct nf_conntrack *ct) +struct cache_object *cache_update_force(struct cache *c, void *ptr) { struct cache_object *obj; int id; - obj = cache_find(c, ct, &id); + obj = cache_find(c, ptr, &id); if (obj) { if (obj->status != C_OBJ_DEAD) { - cache_update(c, obj, id, ct); + cache_update(c, obj, id, ptr); return obj; } else { cache_del(c, obj); cache_object_free(obj); } } - obj = cache_object_new(c, ct); + obj = cache_object_new(c, ptr); if (obj == NULL) return NULL; @@ -350,11 +297,10 @@ cache_update_force(struct cache *c, struct nf_conntrack *ct) return obj; } -struct cache_object * -cache_find(struct cache *c, struct nf_conntrack *ct, int *id) +struct cache_object *cache_find(struct cache *c, void *ptr, int *id) { - *id = hashtable_hash(c->h, ct); - return ((struct cache_object *) hashtable_find(c->h, ct, *id)); + *id = hashtable_hash(c->h, ptr); + return ((struct cache_object *) hashtable_find(c->h, ptr, *id)); } struct cache_object *cache_data_get_object(struct cache *c, void *data) @@ -432,3 +378,33 @@ void cache_iterate_limit(struct cache *c, void *data, { hashtable_iterate_limit(c->h, data, from, steps, iterate); } + +void cache_dump(struct cache *c, int fd, int type) +{ + struct __dump_container tmp = { + .fd = fd, + .type = type + }; + hashtable_iterate(c->h, (void *) &tmp, c->ops->dump_step); +} + +int cache_commit(struct cache *c, struct nfct_handle *h, int clientfd) +{ + return c->ops->commit(c, h, clientfd); +} + +static int do_flush(void *data, void *n) +{ + struct cache *c = data; + struct cache_object *obj = n; + + cache_del(c, obj); + cache_object_free(obj); + return 0; +} + +void cache_flush(struct cache *c) +{ + hashtable_iterate(c->h, c, do_flush); + c->stats.flush++; +} diff --git a/src/cache_iterators.c b/src/cache_iterators.c deleted file mode 100644 index 3248c70..0000000 --- a/src/cache_iterators.c +++ /dev/null @@ -1,268 +0,0 @@ -/* - * (C) 2006-2007 by Pablo Neira Ayuso - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "cache.h" -#include "hash.h" -#include "log.h" -#include "conntrackd.h" -#include "netlink.h" -#include "event.h" - -#include -#include -#include -#include -#include - -struct __dump_container { - int fd; - int type; -}; - -static int do_dump(void *data1, void *n) -{ - char buf[1024]; - int size; - struct __dump_container *container = data1; - struct cache_object *obj = n; - char *data = obj->data; - unsigned i; - - /* - * XXX: Do not dump the entries that are scheduled to expire. - * These entries talk about already destroyed connections - * that we keep for some time just in case that we have to - * resent some lost messages. We do not show them to the - * user as he may think that the firewall replicas are not - * in sync. The branch below is a hack as it is quite - * specific and it breaks conntrackd modularity. Probably - * there's a nicer way to do this but until I come up with it... - */ - if (CONFIG(flags) & CTD_SYNC_FTFW && obj->status == C_OBJ_DEAD) - return 0; - - /* do not show cached timeout, this may confuse users */ - if (nfct_attr_is_set(obj->ct, ATTR_TIMEOUT)) - nfct_attr_unset(obj->ct, ATTR_TIMEOUT); - - memset(buf, 0, sizeof(buf)); - size = nfct_snprintf(buf, - sizeof(buf), - obj->ct, - NFCT_T_UNKNOWN, - container->type, - 0); - - for (i = 0; i < obj->cache->num_features; i++) { - if (obj->cache->features[i]->dump) { - size += obj->cache->features[i]->dump(obj, - data, - buf+size, - container->type); - data += obj->cache->features[i]->size; - } - } - if (container->type != NFCT_O_XML) { - long tm = time(NULL); - size += sprintf(buf+size, " [active since %lds]", - tm - obj->lifetime); - } - size += sprintf(buf+size, "\n"); - if (send(container->fd, buf, size, 0) == -1) { - if (errno != EPIPE) - return -1; - } - - return 0; -} - -void cache_dump(struct cache *c, int fd, int type) -{ - struct __dump_container tmp = { - .fd = fd, - .type = type - }; - - hashtable_iterate(c->h, (void *) &tmp, do_dump); -} - -struct __commit_container { - struct nfct_handle *h; - struct cache *c; -}; - -static void -__do_commit_step(struct __commit_container *tmp, struct cache_object *obj) -{ - int ret, retry = 1, timeout; - struct nf_conntrack *ct = obj->ct; - - if (CONFIG(commit_timeout)) { - timeout = CONFIG(commit_timeout); - } else { - timeout = time(NULL) - obj->lastupdate; - if (timeout < 0) { - /* XXX: Arbitrarily set the timer to one minute, how - * can this happen? For example, an adjustment due to - * daylight-saving. Probably other situations can - * trigger this. */ - timeout = 60; - } - /* calculate an estimation of the current timeout */ - timeout = nfct_get_attr_u32(ct, ATTR_TIMEOUT) - timeout; - if (timeout < 0) { - timeout = 60; - } - } - -retry: - if (nl_create_conntrack(tmp->h, ct, timeout) == -1) { - if (errno == EEXIST && retry == 1) { - ret = nl_destroy_conntrack(tmp->h, ct); - if (ret == 0 || (ret == -1 && errno == ENOENT)) { - if (retry) { - retry = 0; - goto retry; - } - } - dlog(LOG_ERR, "commit-destroy: %s", strerror(errno)); - dlog_ct(STATE(log), ct, NFCT_O_PLAIN); - tmp->c->stats.commit_fail++; - } else { - dlog(LOG_ERR, "commit-create: %s", strerror(errno)); - dlog_ct(STATE(log), ct, NFCT_O_PLAIN); - tmp->c->stats.commit_fail++; - } - } else { - tmp->c->stats.commit_ok++; - } -} - -static int do_commit_related(void *data, void *n) -{ - struct cache_object *obj = n; - - if (ct_is_related(obj->ct)) - __do_commit_step(data, obj); - - /* keep iterating even if we have found errors */ - return 0; -} - -static int do_commit_master(void *data, void *n) -{ - struct cache_object *obj = n; - - if (ct_is_related(obj->ct)) - return 0; - - __do_commit_step(data, obj); - return 0; -} - -int cache_commit(struct cache *c, struct nfct_handle *h, int clientfd) -{ - unsigned int commit_ok, commit_fail; - struct __commit_container tmp = { - .h = h, - .c = c, - }; - struct timeval commit_stop, res; - - /* we already have one commit in progress, skip this. The clientfd - * descriptor has to be closed by the caller. */ - if (clientfd && STATE_SYNC(commit).clientfd != -1) - return 0; - - switch(STATE_SYNC(commit).state) { - case COMMIT_STATE_INACTIVE: - gettimeofday(&STATE_SYNC(commit).stats.start, NULL); - STATE_SYNC(commit).stats.ok = c->stats.commit_ok; - STATE_SYNC(commit).stats.fail = c->stats.commit_fail; - STATE_SYNC(commit).clientfd = clientfd; - case COMMIT_STATE_MASTER: - STATE_SYNC(commit).current = - hashtable_iterate_limit(c->h, &tmp, - STATE_SYNC(commit).current, - CONFIG(general).commit_steps, - do_commit_master); - if (STATE_SYNC(commit).current < CONFIG(hashsize)) { - STATE_SYNC(commit).state = COMMIT_STATE_MASTER; - /* give it another step as soon as possible */ - write_evfd(STATE_SYNC(commit).evfd); - return 1; - } - STATE_SYNC(commit).current = 0; - STATE_SYNC(commit).state = COMMIT_STATE_RELATED; - case COMMIT_STATE_RELATED: - STATE_SYNC(commit).current = - hashtable_iterate_limit(c->h, &tmp, - STATE_SYNC(commit).current, - CONFIG(general).commit_steps, - do_commit_related); - if (STATE_SYNC(commit).current < CONFIG(hashsize)) { - STATE_SYNC(commit).state = COMMIT_STATE_RELATED; - /* give it another step as soon as possible */ - write_evfd(STATE_SYNC(commit).evfd); - return 1; - } - /* calculate the time that commit has taken */ - gettimeofday(&commit_stop, NULL); - timersub(&commit_stop, &STATE_SYNC(commit).stats.start, &res); - - /* calculate new entries committed */ - commit_ok = c->stats.commit_ok - STATE_SYNC(commit).stats.ok; - commit_fail = - c->stats.commit_fail - STATE_SYNC(commit).stats.fail; - - /* log results */ - dlog(LOG_NOTICE, "Committed %u new entries", commit_ok); - - if (commit_fail) - dlog(LOG_NOTICE, "%u entries can't be " - "committed", commit_fail); - - dlog(LOG_NOTICE, "commit has taken %lu.%06lu seconds", - res.tv_sec, res.tv_usec); - - /* prepare the state machine for new commits */ - STATE_SYNC(commit).current = 0; - STATE_SYNC(commit).state = COMMIT_STATE_INACTIVE; - - /* Close the client socket now that we're done. */ - close(STATE_SYNC(commit).clientfd); - STATE_SYNC(commit).clientfd = -1; - } - return 1; -} - -static int do_flush(void *data, void *n) -{ - struct cache *c = data; - struct cache_object *obj = n; - - cache_del(c, obj); - cache_object_free(obj); - return 0; -} - -void cache_flush(struct cache *c) -{ - hashtable_iterate(c->h, c, do_flush); - c->stats.flush++; -} diff --git a/src/external_cache.c b/src/external_cache.c index 59c706a..073f309 100644 --- a/src/external_cache.c +++ b/src/external_cache.c @@ -28,9 +28,9 @@ static struct cache *external; static int external_cache_init(void) { - external = cache_create("external", + external = cache_create("external", CACHE_T_CT, STATE_SYNC(sync)->external_cache_flags, - NULL); + NULL, &cache_sync_external_ct_ops); if (external == NULL) { dlog(LOG_ERR, "can't allocate memory for the external cache"); return -1; diff --git a/src/internal_bypass.c b/src/internal_bypass.c index 1e1478f..8ecec34 100644 --- a/src/internal_bypass.c +++ b/src/internal_bypass.c @@ -1,6 +1,7 @@ /* - * (C) 2009 by Pablo Neira Ayuso - * + * (C) 2006-2011 by Pablo Neira Ayuso + * (C) 2011 by Vyatta Inc. + * * 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 * the Free Software Foundation; either version 2 of the License, or @@ -16,17 +17,18 @@ #include "network.h" #include "origin.h" -static int _init(void) +static int internal_bypass_init(void) { return 0; } -static void _close(void) +static void internal_bypass_close(void) { } -static int dump_cb(enum nf_conntrack_msg_type type, - struct nf_conntrack *ct, void *data) +static int +internal_bypass_ct_dump_cb(enum nf_conntrack_msg_type type, + struct nf_conntrack *ct, void *data) { char buf[1024]; int size, *fd = data; @@ -44,7 +46,7 @@ static int dump_cb(enum nf_conntrack_msg_type type, return NFCT_CB_CONTINUE; } -static void dump(int fd, int type) +static void internal_bypass_ct_dump(int fd, int type) { struct nfct_handle *h; u_int32_t family = AF_UNSPEC; @@ -55,7 +57,7 @@ static void dump(int fd, int type) dlog(LOG_ERR, "can't allocate memory for the internal cache"); return; } - nfct_callback_register(h, NFCT_T_ALL, dump_cb, &fd); + nfct_callback_register(h, NFCT_T_ALL, internal_bypass_ct_dump_cb, &fd); ret = nfct_query(h, NFCT_Q_DUMP, &family); if (ret == -1) { dlog(LOG_ERR, "can't dump kernel table"); @@ -63,7 +65,7 @@ static void dump(int fd, int type) nfct_close(h); } -static void flush(void) +static void internal_bypass_ct_flush(void) { nl_flush_conntrack_table(STATE(flush)); } @@ -74,7 +76,7 @@ struct { uint32_t del; } internal_bypass_stats; -static void stats(int fd) +static void internal_bypass_ct_stats(int fd) { char buf[512]; int size; @@ -91,25 +93,24 @@ static void stats(int fd) } /* unused, INTERNAL_F_POPULATE is unset. No cache, nothing to populate. */ -static void populate(struct nf_conntrack *ct) +static void internal_bypass_ct_populate(struct nf_conntrack *ct) { } /* unused, INTERNAL_F_RESYNC is unset. */ -static void purge(void) +static void internal_bypass_ct_purge(void) { } /* unused, INTERNAL_F_RESYNC is unset. Nothing to resync, we have no cache. */ -static int resync(enum nf_conntrack_msg_type type, - struct nf_conntrack *ct, - void *data) +static int +internal_bypass_ct_resync(enum nf_conntrack_msg_type type, + struct nf_conntrack *ct, void *data) { return NFCT_CB_CONTINUE; } -static void -event_new_sync(struct nf_conntrack *ct, int origin) +static void internal_bypass_ct_event_new(struct nf_conntrack *ct, int origin) { struct nethdr *net; @@ -122,8 +123,7 @@ event_new_sync(struct nf_conntrack *ct, int origin) internal_bypass_stats.new++; } -static void -event_update_sync(struct nf_conntrack *ct, int origin) +static void internal_bypass_ct_event_upd(struct nf_conntrack *ct, int origin) { struct nethdr *net; @@ -136,8 +136,7 @@ event_update_sync(struct nf_conntrack *ct, int origin) internal_bypass_stats.upd++; } -static int -event_destroy_sync(struct nf_conntrack *ct, int origin) +static int internal_bypass_ct_event_del(struct nf_conntrack *ct, int origin) { struct nethdr *net; @@ -153,16 +152,18 @@ event_destroy_sync(struct nf_conntrack *ct, int origin) } struct internal_handler internal_bypass = { - .init = _init, - .close = _close, - .dump = dump, - .flush = flush, - .stats = stats, - .stats_ext = stats, - .populate = populate, - .purge = purge, - .resync = resync, - .new = event_new_sync, - .update = event_update_sync, - .destroy = event_destroy_sync, + .init = internal_bypass_init, + .close = internal_bypass_close, + .ct = { + .dump = internal_bypass_ct_dump, + .flush = internal_bypass_ct_flush, + .stats = internal_bypass_ct_stats, + .stats_ext = internal_bypass_ct_stats, + .populate = internal_bypass_ct_populate, + .purge = internal_bypass_ct_purge, + .resync = internal_bypass_ct_resync, + .new = internal_bypass_ct_event_new, + .upd = internal_bypass_ct_event_upd, + .del = internal_bypass_ct_event_del, + }, }; diff --git a/src/internal_cache.c b/src/internal_cache.c index e50e1db..7a698e6 100644 --- a/src/internal_cache.c +++ b/src/internal_cache.c @@ -1,6 +1,7 @@ /* - * (C) 2009 by Pablo Neira Ayuso - * + * (C) 2006-2011 by Pablo Neira Ayuso + * (C) 2011 by Vyatta Inc. + * * 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 * the Free Software Foundation; either version 2 of the License, or @@ -19,46 +20,47 @@ static inline void sync_send(struct cache_object *obj, int query) STATE_SYNC(sync)->enqueue(obj, query); } -static int _init(void) +static int internal_cache_init(void) { - STATE(mode)->internal->data = - cache_create("internal", + STATE(mode)->internal->ct.data = + cache_create("internal", CACHE_T_CT, STATE_SYNC(sync)->internal_cache_flags, - STATE_SYNC(sync)->internal_cache_extra); + STATE_SYNC(sync)->internal_cache_extra, + &cache_sync_internal_ct_ops); - if (!STATE(mode)->internal->data) { + if (!STATE(mode)->internal->ct.data) { dlog(LOG_ERR, "can't allocate memory for the internal cache"); return -1; } return 0; } -static void _close(void) +static void internal_cache_close(void) { - cache_destroy(STATE(mode)->internal->data); + cache_destroy(STATE(mode)->internal->ct.data); } -static void dump(int fd, int type) +static void internal_cache_ct_dump(int fd, int type) { - cache_dump(STATE(mode)->internal->data, fd, type); + cache_dump(STATE(mode)->internal->ct.data, fd, type); } -static void flush(void) +static void internal_cache_ct_flush(void) { - cache_flush(STATE(mode)->internal->data); + cache_flush(STATE(mode)->internal->ct.data); } -static void stats(int fd) +static void internal_cache_ct_stats(int fd) { - cache_stats(STATE(mode)->internal->data, fd); + cache_stats(STATE(mode)->internal->ct.data, fd); } -static void stats_ext(int fd) +static void internal_cache_ct_stats_ext(int fd) { - cache_stats_extended(STATE(mode)->internal->data, fd); + cache_stats_extended(STATE(mode)->internal->ct.data, fd); } -static void populate(struct nf_conntrack *ct) +static void internal_cache_ct_populate(struct nf_conntrack *ct) { /* This is required by kernels < 2.6.20 */ nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES); @@ -67,15 +69,15 @@ static void populate(struct nf_conntrack *ct) nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS); nfct_attr_unset(ct, ATTR_USE); - cache_update_force(STATE(mode)->internal->data, ct); + cache_update_force(STATE(mode)->internal->ct.data, ct); } -static int purge_step(void *data1, void *data2) +static int internal_cache_ct_purge_step(void *data1, void *data2) { struct cache_object *obj = data2; STATE(get_retval) = 0; - nl_get_conntrack(STATE(get), obj->ct); /* modifies STATE(get_reval) */ + nl_get_conntrack(STATE(get), obj->ptr); /* modifies STATE(get_reval) */ if (!STATE(get_retval)) { if (obj->status != C_OBJ_DEAD) { cache_object_set_status(obj, C_OBJ_DEAD); @@ -87,14 +89,15 @@ static int purge_step(void *data1, void *data2) return 0; } -static void purge(void) +static void internal_cache_ct_purge(void) { - cache_iterate(STATE(mode)->internal->data, NULL, purge_step); + cache_iterate(STATE(mode)->internal->ct.data, NULL, + internal_cache_ct_purge_step); } -static int resync(enum nf_conntrack_msg_type type, - struct nf_conntrack *ct, - void *data) +static int +internal_cache_ct_resync(enum nf_conntrack_msg_type type, + struct nf_conntrack *ct, void *data) { struct cache_object *obj; @@ -108,7 +111,7 @@ static int resync(enum nf_conntrack_msg_type type, nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS); nfct_attr_unset(ct, ATTR_USE); - obj = cache_update_force(STATE(mode)->internal->data, ct); + obj = cache_update_force(STATE(mode)->internal->ct.data, ct); if (obj == NULL) return NFCT_CB_CONTINUE; @@ -123,8 +126,7 @@ static int resync(enum nf_conntrack_msg_type type, return NFCT_CB_CONTINUE; } -static void -event_new_sync(struct nf_conntrack *ct, int origin) +static void internal_cache_ct_event_new(struct nf_conntrack *ct, int origin) { struct cache_object *obj; int id; @@ -139,13 +141,13 @@ event_new_sync(struct nf_conntrack *ct, int origin) nfct_attr_unset(ct, ATTR_REPL_COUNTER_BYTES); nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS); - obj = cache_find(STATE(mode)->internal->data, ct, &id); + obj = cache_find(STATE(mode)->internal->ct.data, ct, &id); if (obj == NULL) { retry: - obj = cache_object_new(STATE(mode)->internal->data, ct); + obj = cache_object_new(STATE(mode)->internal->ct.data, ct); if (obj == NULL) return; - if (cache_add(STATE(mode)->internal->data, obj, id) == -1) { + if (cache_add(STATE(mode)->internal->ct.data, obj, id) == -1) { cache_object_free(obj); return; } @@ -155,14 +157,13 @@ retry: if (origin == CTD_ORIGIN_NOT_ME) sync_send(obj, NET_T_STATE_NEW); } else { - cache_del(STATE(mode)->internal->data, obj); + cache_del(STATE(mode)->internal->ct.data, obj); cache_object_free(obj); goto retry; } } -static void -event_update_sync(struct nf_conntrack *ct, int origin) +static void internal_cache_ct_event_upd(struct nf_conntrack *ct, int origin) { struct cache_object *obj; @@ -170,7 +171,7 @@ event_update_sync(struct nf_conntrack *ct, int origin) if (origin == CTD_ORIGIN_INJECT) return; - obj = cache_update_force(STATE(mode)->internal->data, ct); + obj = cache_update_force(STATE(mode)->internal->ct.data, ct); if (obj == NULL) return; @@ -178,8 +179,7 @@ event_update_sync(struct nf_conntrack *ct, int origin) sync_send(obj, NET_T_STATE_UPD); } -static int -event_destroy_sync(struct nf_conntrack *ct, int origin) +static int internal_cache_ct_event_del(struct nf_conntrack *ct, int origin) { struct cache_object *obj; int id; @@ -189,7 +189,7 @@ event_destroy_sync(struct nf_conntrack *ct, int origin) return 0; /* we don't synchronize events for objects that are not in the cache */ - obj = cache_find(STATE(mode)->internal->data, ct, &id); + obj = cache_find(STATE(mode)->internal->ct.data, ct, &id); if (obj == NULL) return 0; @@ -205,16 +205,18 @@ event_destroy_sync(struct nf_conntrack *ct, int origin) struct internal_handler internal_cache = { .flags = INTERNAL_F_POPULATE | INTERNAL_F_RESYNC, - .init = _init, - .close = _close, - .dump = dump, - .flush = flush, - .stats = stats, - .stats_ext = stats_ext, - .populate = populate, - .purge = purge, - .resync = resync, - .new = event_new_sync, - .update = event_update_sync, - .destroy = event_destroy_sync, + .init = internal_cache_init, + .close = internal_cache_close, + .ct = { + .dump = internal_cache_ct_dump, + .flush = internal_cache_ct_flush, + .stats = internal_cache_ct_stats, + .stats_ext = internal_cache_ct_stats_ext, + .populate = internal_cache_ct_populate, + .purge = internal_cache_ct_purge, + .resync = internal_cache_ct_resync, + .new = internal_cache_ct_event_new, + .upd = internal_cache_ct_event_upd, + .del = internal_cache_ct_event_del, + }, }; diff --git a/src/run.c b/src/run.c index 265a949..f8d3fad 100644 --- a/src/run.c +++ b/src/run.c @@ -1,6 +1,7 @@ /* - * (C) 2006-2009 by Pablo Neira Ayuso - * + * (C) 2006-2011 by Pablo Neira Ayuso + * (C) 2011 by Vyatta Inc. + * * 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 * the Free Software Foundation; either version 2 of the License, or @@ -241,8 +242,8 @@ static void do_overrun_resync_alarm(struct alarm_block *a, void *data) static void do_polling_alarm(struct alarm_block *a, void *data) { - if (STATE(mode)->internal->purge) - STATE(mode)->internal->purge(); + if (STATE(mode)->internal->ct.purge) + STATE(mode)->internal->ct.purge(); nl_send_resync(STATE(resync)); add_alarm(&STATE(polling_alarm), CONFIG(poll_kernel_secs), 0); @@ -267,13 +268,13 @@ static int event_handler(const struct nlmsghdr *nlh, switch(type) { case NFCT_T_NEW: - STATE(mode)->internal->new(ct, origin_type); + STATE(mode)->internal->ct.new(ct, origin_type); break; case NFCT_T_UPDATE: - STATE(mode)->internal->update(ct, origin_type); + STATE(mode)->internal->ct.upd(ct, origin_type); break; case NFCT_T_DESTROY: - if (STATE(mode)->internal->destroy(ct, origin_type)) + if (STATE(mode)->internal->ct.del(ct, origin_type)) update_traffic_stats(ct); break; default: @@ -298,7 +299,7 @@ static int dump_handler(enum nf_conntrack_msg_type type, switch(type) { case NFCT_T_UPDATE: - STATE(mode)->internal->populate(ct); + STATE(mode)->internal->ct.populate(ct); break; default: STATE(stats).nl_dump_unknown_type++; @@ -363,7 +364,7 @@ init(void) } nfct_callback_register(STATE(resync), NFCT_T_ALL, - STATE(mode)->internal->resync, + STATE(mode)->internal->ct.resync, NULL); register_fd(nfct_fd(STATE(resync)), STATE(fds)); fcntl(nfct_fd(STATE(resync)), F_SETFL, O_NONBLOCK); @@ -537,8 +538,8 @@ static void run_events(struct timeval *next_alarm) /* we previously requested a resync due to buffer overrun. */ if (FD_ISSET(nfct_fd(STATE(resync)), &readfds)) { nfct_catch(STATE(resync)); - if (STATE(mode)->internal->purge) - STATE(mode)->internal->purge(); + if (STATE(mode)->internal->ct.purge) + STATE(mode)->internal->ct.purge(); } if (STATE(mode)->run) diff --git a/src/stats-mode.c b/src/stats-mode.c index 0403ce2..c7a81e3 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -1,6 +1,7 @@ /* - * (C) 2006-2007 by Pablo Neira Ayuso - * + * (C) 2006-2011 by Pablo Neira Ayuso + * (C) 2011 by Vyatta Inc. + * * 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 * the Free Software Foundation; either version 2 of the License, or @@ -37,7 +38,9 @@ static int init_stats(void) } memset(state.stats, 0, sizeof(struct ct_stats_state)); - STATE_STATS(cache) = cache_create("stats", NO_FEATURES, NULL); + STATE_STATS(cache) = cache_create("stats", CACHE_T_CT, + NO_FEATURES, NULL, + &cache_stats_ct_ops); if (!STATE_STATS(cache)) { dlog(LOG_ERR, "can't allocate memory for the " "external cache"); @@ -88,7 +91,7 @@ static int local_handler_stats(int fd, int type, void *data) return ret; } -static void populate_stats(struct nf_conntrack *ct) +static void stats_populate(struct nf_conntrack *ct) { nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES); nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS); @@ -100,7 +103,7 @@ static void populate_stats(struct nf_conntrack *ct) cache_update_force(STATE_STATS(cache), ct); } -static int resync_stats(enum nf_conntrack_msg_type type, +static int stats_resync(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *data) { @@ -125,23 +128,22 @@ static int purge_step(void *data1, void *data2) struct cache_object *obj = data2; STATE(get_retval) = 0; - nl_get_conntrack(STATE(get), obj->ct); /* modifies STATE(get_retval) */ + nl_get_conntrack(STATE(get), obj->ptr); /* modifies STATE(get_retval) */ if (!STATE(get_retval)) { cache_del(STATE_STATS(cache), obj); - dlog_ct(STATE(stats_log), obj->ct, NFCT_O_PLAIN); + dlog_ct(STATE(stats_log), obj->ptr, NFCT_O_PLAIN); cache_object_free(obj); } return 0; } -static void purge_stats(void) +static void stats_purge(void) { cache_iterate(STATE_STATS(cache), NULL, purge_step); } -static void -event_new_stats(struct nf_conntrack *ct, int origin) +static void stats_event_new(struct nf_conntrack *ct, int origin) { int id; struct cache_object *obj; @@ -162,15 +164,13 @@ event_new_stats(struct nf_conntrack *ct, int origin) return; } -static void -event_update_stats(struct nf_conntrack *ct, int origin) +static void stats_event_upd(struct nf_conntrack *ct, int origin) { nfct_attr_unset(ct, ATTR_TIMEOUT); cache_update_force(STATE_STATS(cache), ct); } -static int -event_destroy_stats(struct nf_conntrack *ct, int origin) +static int stats_event_del(struct nf_conntrack *ct, int origin) { int id; struct cache_object *obj; @@ -189,12 +189,14 @@ event_destroy_stats(struct nf_conntrack *ct, int origin) static struct internal_handler internal_cache_stats = { .flags = INTERNAL_F_POPULATE | INTERNAL_F_RESYNC, - .populate = populate_stats, - .resync = resync_stats, - .purge = purge_stats, - .new = event_new_stats, - .update = event_update_stats, - .destroy = event_destroy_stats + .ct = { + .populate = stats_populate, + .resync = stats_resync, + .purge = stats_purge, + .new = stats_event_new, + .upd = stats_event_upd, + .del = stats_event_del, + }, }; struct ct_mode stats_mode = { diff --git a/src/sync-alarm.c b/src/sync-alarm.c index b555dd5..8d6b34d 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -1,6 +1,7 @@ /* - * (C) 2006-2007 by Pablo Neira Ayuso - * + * (C) 2006-2011 by Pablo Neira Ayuso + * (C) 2011 by Vyatta Inc. + * * 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 * the Free Software Foundation; either version 2 of the License, or @@ -110,7 +111,7 @@ static int alarm_recv(const struct nethdr *net) static void alarm_enqueue(struct cache_object *obj, int query) { struct cache_alarm *ca = - cache_get_extra(STATE(mode)->internal->data, obj); + cache_get_extra(STATE(mode)->internal->ct.data, obj); if (queue_add(STATE_SYNC(tx_queue), &ca->qnode) > 0) cache_object_get(obj); } @@ -135,9 +136,9 @@ static int tx_queue_xmit(struct queue_node *n, const void *data) int type; ca = (struct cache_alarm *)n; - obj = cache_data_get_object(STATE(mode)->internal->data, ca); + obj = cache_data_get_object(STATE(mode)->internal->ct.data, ca); type = object_status_to_network_type(obj->status); - net = BUILD_NETMSG(obj->ct, type); + net = obj->cache->ops->build_msg(obj, type); multichannel_send(STATE_SYNC(channel), net); cache_object_put(obj); break; diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 581b5ca..55eda0b 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -1,6 +1,7 @@ /* - * (C) 2006-2008 by Pablo Neira Ayuso - * + * (C) 2006-2011 by Pablo Neira Ayuso + * (C) 2011 by Vyatta Inc. + * * 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 * the Free Software Foundation; either version 2 of the License, or @@ -169,7 +170,7 @@ static int do_cache_to_tx(void *data1, void *data2) { struct cache_object *obj = data2; struct cache_ftfw *cn = - cache_get_extra(STATE(mode)->internal->data, obj); + cache_get_extra(STATE(mode)->internal->ct.data, obj); if (queue_in(rs_queue, &cn->qnode)) { queue_del(&cn->qnode); @@ -227,7 +228,7 @@ static int ftfw_local(int fd, int type, void *data) break; case SEND_BULK: dlog(LOG_NOTICE, "sending bulk update"); - cache_iterate(STATE(mode)->internal->data, + cache_iterate(STATE(mode)->internal->ct.data, NULL, do_cache_to_tx); break; case STATS_RSQUEUE: @@ -307,7 +308,7 @@ static int rs_queue_empty(struct queue_node *n, const void *data) cn = (struct cache_ftfw *) n; if (h == NULL) { queue_del(n); - obj = cache_data_get_object(STATE(mode)->internal->data, cn); + obj = cache_data_get_object(STATE(mode)->internal->ct.data, cn); cache_object_put(obj); return 0; } @@ -318,7 +319,7 @@ static int rs_queue_empty(struct queue_node *n, const void *data) dp("queue: deleting from queue (seq=%u)\n", cn->seq); queue_del(n); - obj = cache_data_get_object(STATE(mode)->internal->data, cn); + obj = cache_data_get_object(STATE(mode)->internal->ct.data, cn); cache_object_put(obj); break; } @@ -351,7 +352,7 @@ static int digest_msg(const struct nethdr *net) } else if (IS_RESYNC(net)) { dp("RESYNC ALL\n"); - cache_iterate(STATE(mode)->internal->data, NULL, do_cache_to_tx); + cache_iterate(STATE(mode)->internal->ct.data, NULL, do_cache_to_tx); return MSG_CTL; } else if (IS_ALIVE(net)) @@ -468,7 +469,7 @@ static void rs_queue_purge_full(void) struct cache_object *obj; cn = (struct cache_ftfw *)n; - obj = cache_data_get_object(STATE(mode)->internal->data, cn); + obj = cache_data_get_object(STATE(mode)->internal->ct.data, cn); cache_object_put(obj); break; } @@ -516,9 +517,9 @@ static int tx_queue_xmit(struct queue_node *n, const void *data) struct nethdr *net; cn = (struct cache_ftfw *)n; - obj = cache_data_get_object(STATE(mode)->internal->data, cn); + obj = cache_data_get_object(STATE(mode)->internal->ct.data, cn); type = object_status_to_network_type(obj->status); - net = BUILD_NETMSG(obj->ct, type); + net = obj->cache->ops->build_msg(obj, type); nethdr_set_hello(net); dp("tx_list sq: %u fl:%u len:%u\n", @@ -551,7 +552,7 @@ static void ftfw_xmit(void) static void ftfw_enqueue(struct cache_object *obj, int type) { struct cache_ftfw *cn = - cache_get_extra(STATE(mode)->internal->data, obj); + cache_get_extra(STATE(mode)->internal->ct.data, obj); if (queue_in(rs_queue, &cn->qnode)) { queue_del(&cn->qnode); queue_add(STATE_SYNC(tx_queue), &cn->qnode); diff --git a/src/sync-mode.c b/src/sync-mode.c index 5351110..34d9706 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -1,6 +1,7 @@ /* - * (C) 2006-2007 by Pablo Neira Ayuso - * + * (C) 2006-2011 by Pablo Neira Ayuso + * (C) 2011 by Vyatta Inc. + * * 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 * the Free Software Foundation; either version 2 of the License, or @@ -251,7 +252,7 @@ static void do_reset_cache_alarm(struct alarm_block *a, void *data) exit(EXIT_SUCCESS); } /* this is not required if events don't get lost */ - STATE(mode)->internal->flush(); + STATE(mode)->internal->ct.flush(); } static int init_sync(void) @@ -471,7 +472,7 @@ static int local_handler_sync(int fd, int type, void *data) switch(type) { case DUMP_INTERNAL: if (fork_process_new(CTD_PROC_ANY, 0, NULL, NULL) == 0) { - STATE(mode)->internal->dump(fd, NFCT_O_PLAIN); + STATE(mode)->internal->ct.dump(fd, NFCT_O_PLAIN); exit(EXIT_SUCCESS); } break; @@ -483,7 +484,7 @@ static int local_handler_sync(int fd, int type, void *data) break; case DUMP_INT_XML: if (fork_process_new(CTD_PROC_ANY, 0, NULL, NULL) == 0) { - STATE(mode)->internal->dump(fd, NFCT_O_XML); + STATE(mode)->internal->ct.dump(fd, NFCT_O_XML); exit(EXIT_SUCCESS); } break; @@ -512,14 +513,14 @@ static int local_handler_sync(int fd, int type, void *data) /* inmediate flush, remove pending flush scheduled if any */ del_alarm(&STATE_SYNC(reset_cache_alarm)); dlog(LOG_NOTICE, "flushing caches"); - STATE(mode)->internal->flush(); + STATE(mode)->internal->ct.flush(); STATE_SYNC(external)->flush(); break; case FLUSH_INT_CACHE: /* inmediate flush, remove pending flush scheduled if any */ del_alarm(&STATE_SYNC(reset_cache_alarm)); dlog(LOG_NOTICE, "flushing internal cache"); - STATE(mode)->internal->flush(); + STATE(mode)->internal->ct.flush(); break; case FLUSH_EXT_CACHE: dlog(LOG_NOTICE, "flushing external cache"); @@ -529,7 +530,7 @@ static int local_handler_sync(int fd, int type, void *data) killer(0); break; case STATS: - STATE(mode)->internal->stats(fd); + STATE(mode)->internal->ct.stats(fd); STATE_SYNC(external)->stats(fd); dump_traffic_stats(fd); multichannel_stats(STATE_SYNC(channel), fd); @@ -540,7 +541,7 @@ static int local_handler_sync(int fd, int type, void *data) multichannel_stats(STATE_SYNC(channel), fd); break; case STATS_CACHE: - STATE(mode)->internal->stats_ext(fd); + STATE(mode)->internal->ct.stats_ext(fd); STATE_SYNC(external)->stats_ext(fd); break; case STATS_LINK: diff --git a/src/sync-notrack.c b/src/sync-notrack.c index 06af58b..e25cfd8 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -76,7 +76,7 @@ static int do_cache_to_tx(void *data1, void *data2) { struct cache_object *obj = data2; struct cache_notrack *cn = - cache_get_extra(STATE(mode)->internal->data, obj); + cache_get_extra(STATE(mode)->internal->ct.data, obj); if (queue_add(STATE_SYNC(tx_queue), &cn->qnode) > 0) cache_object_get(obj); return 0; @@ -127,7 +127,7 @@ static int notrack_local(int fd, int type, void *data) if (CONFIG(sync).internal_cache_disable) { kernel_resync(); } else { - cache_iterate(STATE(mode)->internal->data, + cache_iterate(STATE(mode)->internal->ct.data, NULL, do_cache_to_tx); } break; @@ -148,7 +148,7 @@ static int digest_msg(const struct nethdr *net) if (CONFIG(sync).internal_cache_disable) { kernel_resync(); } else { - cache_iterate(STATE(mode)->internal->data, + cache_iterate(STATE(mode)->internal->ct.data, NULL, do_cache_to_tx); } return MSG_CTL; @@ -197,9 +197,9 @@ static int tx_queue_xmit(struct queue_node *n, const void *data2) struct nethdr *net; cn = (struct cache_ftfw *)n; - obj = cache_data_get_object(STATE(mode)->internal->data, cn); + obj = cache_data_get_object(STATE(mode)->internal->ct.data, cn); type = object_status_to_network_type(obj->status);; - net = BUILD_NETMSG(obj->ct, type); + net = obj->cache->ops->build_msg(obj, type); multichannel_send(STATE_SYNC(channel), net); queue_del(n); @@ -219,7 +219,7 @@ static void notrack_xmit(void) static void notrack_enqueue(struct cache_object *obj, int query) { struct cache_notrack *cn = - cache_get_extra(STATE(mode)->internal->data, obj); + cache_get_extra(STATE(mode)->internal->ct.data, obj); if (queue_add(STATE_SYNC(tx_queue), &cn->qnode) > 0) cache_object_get(obj); } -- cgit v1.2.3 From 931c0eff309d8c7277ebe6d670fd72d8fbe3c674 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 4 Jan 2012 14:30:02 +0100 Subject: conntrackd: generalize/cleanup network message building/parsing This patch generalizes the network message building and parsing to prepare the upcoming expectation support. Basically, it renames: - NET_T_STATE_* by NET_T_STATE_CT_*, as I plan to add NET_T_STATE_EXP_* - BUILD_NETMSG by BUILD_NETMSG_FROM_CT, and build_payload by ct2msg. I plan to add exp2msg. - parse_payload by msg2ct, since I plan to add msg2exp. - modify object_status_to_network_type to prepare the support of expectations. - add prefix ct_ to all parsing functions in parse.c, as we will have similar functions to convert messages to expectation objects. Signed-off-by: Pablo Neira Ayuso --- include/cache.h | 3 +- include/network.h | 21 +++++++------ src/build.c | 81 ++++++++++++++++++++++++------------------------ src/internal_bypass.c | 6 ++-- src/internal_cache.c | 12 ++++---- src/network.c | 19 +++++++----- src/parse.c | 85 ++++++++++++++++++++++++++------------------------- src/sync-alarm.c | 4 +-- src/sync-ftfw.c | 2 +- src/sync-mode.c | 44 +++++++++++++++++--------- src/sync-notrack.c | 9 +++--- 11 files changed, 155 insertions(+), 131 deletions(-) (limited to 'src/sync-notrack.c') diff --git a/include/cache.h b/include/cache.h index a42e395..02bb386 100644 --- a/include/cache.h +++ b/include/cache.h @@ -21,7 +21,8 @@ enum { C_OBJ_NONE = 0, /* not in the cache */ C_OBJ_NEW, /* just added to the cache */ C_OBJ_ALIVE, /* in the cache, alive */ - C_OBJ_DEAD /* still in the cache, but dead */ + C_OBJ_DEAD, /* still in the cache, but dead */ + C_OBJ_MAX }; struct cache; diff --git a/include/network.h b/include/network.h index 567317b..d0531b9 100644 --- a/include/network.h +++ b/include/network.h @@ -25,10 +25,10 @@ struct nethdr { #define NETHDR_SIZ nethdr_align(sizeof(struct nethdr)) enum nethdr_type { - NET_T_STATE_NEW = 0, - NET_T_STATE_UPD, - NET_T_STATE_DEL, - NET_T_STATE_MAX = NET_T_STATE_DEL, + NET_T_STATE_CT_NEW = 0, + NET_T_STATE_CT_UPD, + NET_T_STATE_CT_DEL, + NET_T_STATE_MAX = NET_T_STATE_CT_DEL, NET_T_CTL = 10, }; @@ -37,7 +37,9 @@ int nethdr_size(int len); void nethdr_set(struct nethdr *net, int type); void nethdr_set_ack(struct nethdr *net); void nethdr_set_ctl(struct nethdr *net); -int object_status_to_network_type(int status); + +struct cache_object; +int object_status_to_network_type(struct cache_object *obj); #define NETHDR_DATA(x) \ (struct netattr *)(((char *)x) + NETHDR_SIZ) @@ -79,13 +81,13 @@ enum { MSG_BAD, }; -#define BUILD_NETMSG(ct, query) \ +#define BUILD_NETMSG_FROM_CT(ct, query) \ ({ \ static char __net[4096]; \ struct nethdr *__hdr = (struct nethdr *) __net; \ memset(__hdr, 0, NETHDR_SIZ); \ nethdr_set(__hdr, query); \ - build_payload(ct, __hdr); \ + ct2msg(ct, __hdr); \ HDR_HOST2NETWORK(__hdr); \ __hdr; \ }) @@ -234,8 +236,7 @@ struct nta_attr_natseqadj { uint32_t repl_seq_offset_after; }; -void build_payload(const struct nf_conntrack *ct, struct nethdr *n); - -int parse_payload(struct nf_conntrack *ct, struct nethdr *n, size_t remain); +void ct2msg(const struct nf_conntrack *ct, struct nethdr *n); +int msg2ct(struct nf_conntrack *ct, struct nethdr *n, size_t remain); #endif diff --git a/src/build.c b/src/build.c index a495872..9c3687c 100644 --- a/src/build.c +++ b/src/build.c @@ -1,6 +1,7 @@ /* - * (C) 2006-2008 by Pablo Neira Ayuso - * + * (C) 2006-2011 by Pablo Neira Ayuso + * (C) 2011 by Vyatta Inc. + * * 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 * the Free Software Foundation; either version 2 of the License, or @@ -42,14 +43,14 @@ addattr(struct nethdr *n, int attr, const void *data, size_t len) } static inline void -__build_u8(const struct nf_conntrack *ct, int a, struct nethdr *n, int b) +ct_build_u8(const struct nf_conntrack *ct, int a, struct nethdr *n, int b) { void *ptr = put_header(n, b, sizeof(uint8_t)); memcpy(ptr, nfct_get_attr(ct, a), sizeof(uint8_t)); } static inline void -__build_u16(const struct nf_conntrack *ct, int a, struct nethdr *n, int b) +ct_build_u16(const struct nf_conntrack *ct, int a, struct nethdr *n, int b) { uint16_t data = nfct_get_attr_u16(ct, a); data = htons(data); @@ -57,7 +58,7 @@ __build_u16(const struct nf_conntrack *ct, int a, struct nethdr *n, int b) } static inline void -__build_u32(const struct nf_conntrack *ct, int a, struct nethdr *n, int b) +ct_build_u32(const struct nf_conntrack *ct, int a, struct nethdr *n, int b) { uint32_t data = nfct_get_attr_u32(ct, a); data = htonl(data); @@ -65,7 +66,7 @@ __build_u32(const struct nf_conntrack *ct, int a, struct nethdr *n, int b) } static inline void -__build_group(const struct nf_conntrack *ct, int a, struct nethdr *n, +ct_build_group(const struct nf_conntrack *ct, int a, struct nethdr *n, int b, int size) { void *ptr = put_header(n, b, size); @@ -73,7 +74,7 @@ __build_group(const struct nf_conntrack *ct, int a, struct nethdr *n, } static inline void -__build_natseqadj(const struct nf_conntrack *ct, struct nethdr *n) +ct_build_natseqadj(const struct nf_conntrack *ct, struct nethdr *n) { struct nta_attr_natseqadj data = { .orig_seq_correction_pos = @@ -99,54 +100,54 @@ static enum nf_conntrack_attr nat_type[] = static void build_l4proto_tcp(const struct nf_conntrack *ct, struct nethdr *n) { - __build_group(ct, ATTR_GRP_ORIG_PORT, n, NTA_PORT, + ct_build_group(ct, ATTR_GRP_ORIG_PORT, n, NTA_PORT, sizeof(struct nfct_attr_grp_port)); if (!nfct_attr_is_set(ct, ATTR_TCP_STATE)) return; - __build_u8(ct, ATTR_TCP_STATE, n, NTA_TCP_STATE); + ct_build_u8(ct, ATTR_TCP_STATE, n, NTA_TCP_STATE); if (CONFIG(sync).tcp_window_tracking) { - __build_u8(ct, ATTR_TCP_WSCALE_ORIG, n, NTA_TCP_WSCALE_ORIG); - __build_u8(ct, ATTR_TCP_WSCALE_REPL, n, NTA_TCP_WSCALE_REPL); + ct_build_u8(ct, ATTR_TCP_WSCALE_ORIG, n, NTA_TCP_WSCALE_ORIG); + ct_build_u8(ct, ATTR_TCP_WSCALE_REPL, n, NTA_TCP_WSCALE_REPL); } } static void build_l4proto_sctp(const struct nf_conntrack *ct, struct nethdr *n) { - __build_group(ct, ATTR_GRP_ORIG_PORT, n, NTA_PORT, + ct_build_group(ct, ATTR_GRP_ORIG_PORT, n, NTA_PORT, sizeof(struct nfct_attr_grp_port)); if (!nfct_attr_is_set(ct, ATTR_SCTP_STATE)) return; - __build_u8(ct, ATTR_SCTP_STATE, n, NTA_SCTP_STATE); - __build_u32(ct, ATTR_SCTP_VTAG_ORIG, n, NTA_SCTP_VTAG_ORIG); - __build_u32(ct, ATTR_SCTP_VTAG_REPL, n, NTA_SCTP_VTAG_REPL); + ct_build_u8(ct, ATTR_SCTP_STATE, n, NTA_SCTP_STATE); + ct_build_u32(ct, ATTR_SCTP_VTAG_ORIG, n, NTA_SCTP_VTAG_ORIG); + ct_build_u32(ct, ATTR_SCTP_VTAG_REPL, n, NTA_SCTP_VTAG_REPL); } static void build_l4proto_dccp(const struct nf_conntrack *ct, struct nethdr *n) { - __build_group(ct, ATTR_GRP_ORIG_PORT, n, NTA_PORT, + ct_build_group(ct, ATTR_GRP_ORIG_PORT, n, NTA_PORT, sizeof(struct nfct_attr_grp_port)); if (!nfct_attr_is_set(ct, ATTR_DCCP_STATE)) return; - __build_u8(ct, ATTR_DCCP_STATE, n, NTA_DCCP_STATE); - __build_u8(ct, ATTR_DCCP_ROLE, n, NTA_DCCP_ROLE); + ct_build_u8(ct, ATTR_DCCP_STATE, n, NTA_DCCP_STATE); + ct_build_u8(ct, ATTR_DCCP_ROLE, n, NTA_DCCP_ROLE); } static void build_l4proto_icmp(const struct nf_conntrack *ct, struct nethdr *n) { - __build_u8(ct, ATTR_ICMP_TYPE, n, NTA_ICMP_TYPE); - __build_u8(ct, ATTR_ICMP_CODE, n, NTA_ICMP_CODE); - __build_u16(ct, ATTR_ICMP_ID, n, NTA_ICMP_ID); + ct_build_u8(ct, ATTR_ICMP_TYPE, n, NTA_ICMP_TYPE); + ct_build_u8(ct, ATTR_ICMP_CODE, n, NTA_ICMP_CODE); + ct_build_u16(ct, ATTR_ICMP_ID, n, NTA_ICMP_ID); } static void build_l4proto_udp(const struct nf_conntrack *ct, struct nethdr *n) { - __build_group(ct, ATTR_GRP_ORIG_PORT, n, NTA_PORT, + ct_build_group(ct, ATTR_GRP_ORIG_PORT, n, NTA_PORT, sizeof(struct nfct_attr_grp_port)); } @@ -165,45 +166,45 @@ static struct build_l4proto { [IPPROTO_UDP] = { .build = build_l4proto_udp }, }; -void build_payload(const struct nf_conntrack *ct, struct nethdr *n) +void ct2msg(const struct nf_conntrack *ct, struct nethdr *n) { uint8_t l4proto = nfct_get_attr_u8(ct, ATTR_L4PROTO); if (nfct_attr_grp_is_set(ct, ATTR_GRP_ORIG_IPV4)) { - __build_group(ct, ATTR_GRP_ORIG_IPV4, n, NTA_IPV4, + ct_build_group(ct, ATTR_GRP_ORIG_IPV4, n, 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, n, NTA_IPV6, + ct_build_group(ct, ATTR_GRP_ORIG_IPV6, n, NTA_IPV6, sizeof(struct nfct_attr_grp_ipv6)); } - __build_u32(ct, ATTR_STATUS, n, NTA_STATUS); - __build_u8(ct, ATTR_L4PROTO, n, NTA_L4PROTO); + ct_build_u32(ct, ATTR_STATUS, n, NTA_STATUS); + ct_build_u8(ct, ATTR_L4PROTO, n, NTA_L4PROTO); if (l4proto_fcn[l4proto].build) l4proto_fcn[l4proto].build(ct, n); if (!CONFIG(commit_timeout) && nfct_attr_is_set(ct, ATTR_TIMEOUT)) - __build_u32(ct, ATTR_TIMEOUT, n, NTA_TIMEOUT); + ct_build_u32(ct, ATTR_TIMEOUT, n, NTA_TIMEOUT); if (nfct_attr_is_set(ct, ATTR_MARK)) - __build_u32(ct, ATTR_MARK, n, NTA_MARK); + ct_build_u32(ct, ATTR_MARK, n, NTA_MARK); /* setup the master conntrack */ if (nfct_attr_grp_is_set(ct, ATTR_GRP_MASTER_IPV4)) { - __build_group(ct, ATTR_GRP_MASTER_IPV4, n, NTA_MASTER_IPV4, + ct_build_group(ct, ATTR_GRP_MASTER_IPV4, n, NTA_MASTER_IPV4, sizeof(struct nfct_attr_grp_ipv4)); - __build_u8(ct, ATTR_MASTER_L4PROTO, n, NTA_MASTER_L4PROTO); + ct_build_u8(ct, ATTR_MASTER_L4PROTO, n, NTA_MASTER_L4PROTO); if (nfct_attr_grp_is_set(ct, ATTR_GRP_MASTER_PORT)) { - __build_group(ct, ATTR_GRP_MASTER_PORT, + ct_build_group(ct, ATTR_GRP_MASTER_PORT, n, 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, n, NTA_MASTER_IPV6, + ct_build_group(ct, ATTR_GRP_MASTER_IPV6, n, NTA_MASTER_IPV6, sizeof(struct nfct_attr_grp_ipv6)); - __build_u8(ct, ATTR_MASTER_L4PROTO, n, NTA_MASTER_L4PROTO); + ct_build_u8(ct, ATTR_MASTER_L4PROTO, n, NTA_MASTER_L4PROTO); if (nfct_attr_grp_is_set(ct, ATTR_GRP_MASTER_PORT)) { - __build_group(ct, ATTR_GRP_MASTER_PORT, + ct_build_group(ct, ATTR_GRP_MASTER_PORT, n, NTA_MASTER_PORT, sizeof(struct nfct_attr_grp_port)); } @@ -211,15 +212,15 @@ void build_payload(const struct nf_conntrack *ct, struct nethdr *n) /* NAT */ if (nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) - __build_u32(ct, ATTR_REPL_IPV4_DST, n, NTA_SNAT_IPV4); + ct_build_u32(ct, ATTR_REPL_IPV4_DST, n, NTA_SNAT_IPV4); if (nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) - __build_u32(ct, ATTR_REPL_IPV4_SRC, n, NTA_DNAT_IPV4); + ct_build_u32(ct, ATTR_REPL_IPV4_SRC, n, NTA_DNAT_IPV4); if (nfct_getobjopt(ct, NFCT_GOPT_IS_SPAT)) - __build_u16(ct, ATTR_REPL_PORT_DST, n, NTA_SPAT_PORT); + ct_build_u16(ct, ATTR_REPL_PORT_DST, n, NTA_SPAT_PORT); if (nfct_getobjopt(ct, NFCT_GOPT_IS_DPAT)) - __build_u16(ct, ATTR_REPL_PORT_SRC, n, NTA_DPAT_PORT); + ct_build_u16(ct, ATTR_REPL_PORT_SRC, n, NTA_DPAT_PORT); /* NAT sequence adjustment */ if (nfct_attr_is_set_array(ct, nat_type, 6)) - __build_natseqadj(ct, n); + ct_build_natseqadj(ct, n); } diff --git a/src/internal_bypass.c b/src/internal_bypass.c index 8ecec34..98717f3 100644 --- a/src/internal_bypass.c +++ b/src/internal_bypass.c @@ -118,7 +118,7 @@ static void internal_bypass_ct_event_new(struct nf_conntrack *ct, int origin) if (origin != CTD_ORIGIN_NOT_ME) return; - net = BUILD_NETMSG(ct, NET_T_STATE_NEW); + net = BUILD_NETMSG_FROM_CT(ct, NET_T_STATE_CT_NEW); multichannel_send(STATE_SYNC(channel), net); internal_bypass_stats.new++; } @@ -131,7 +131,7 @@ static void internal_bypass_ct_event_upd(struct nf_conntrack *ct, int origin) if (origin != CTD_ORIGIN_NOT_ME) return; - net = BUILD_NETMSG(ct, NET_T_STATE_UPD); + net = BUILD_NETMSG_FROM_CT(ct, NET_T_STATE_CT_UPD); multichannel_send(STATE_SYNC(channel), net); internal_bypass_stats.upd++; } @@ -144,7 +144,7 @@ static int internal_bypass_ct_event_del(struct nf_conntrack *ct, int origin) if (origin != CTD_ORIGIN_NOT_ME) return 1; - net = BUILD_NETMSG(ct, NET_T_STATE_DEL); + net = BUILD_NETMSG_FROM_CT(ct, NET_T_STATE_CT_DEL); multichannel_send(STATE_SYNC(channel), net); internal_bypass_stats.del++; diff --git a/src/internal_cache.c b/src/internal_cache.c index 7a698e6..952327d 100644 --- a/src/internal_cache.c +++ b/src/internal_cache.c @@ -81,7 +81,7 @@ static int internal_cache_ct_purge_step(void *data1, void *data2) if (!STATE(get_retval)) { if (obj->status != C_OBJ_DEAD) { cache_object_set_status(obj, C_OBJ_DEAD); - sync_send(obj, NET_T_STATE_DEL); + sync_send(obj, NET_T_STATE_CT_DEL); cache_object_put(obj); } } @@ -117,10 +117,10 @@ internal_cache_ct_resync(enum nf_conntrack_msg_type type, switch (obj->status) { case C_OBJ_NEW: - sync_send(obj, NET_T_STATE_NEW); + sync_send(obj, NET_T_STATE_CT_NEW); break; case C_OBJ_ALIVE: - sync_send(obj, NET_T_STATE_UPD); + sync_send(obj, NET_T_STATE_CT_UPD); break; } return NFCT_CB_CONTINUE; @@ -155,7 +155,7 @@ retry: * processes or the kernel, but don't propagate events that * have been triggered by conntrackd itself, eg. commits. */ if (origin == CTD_ORIGIN_NOT_ME) - sync_send(obj, NET_T_STATE_NEW); + sync_send(obj, NET_T_STATE_CT_NEW); } else { cache_del(STATE(mode)->internal->ct.data, obj); cache_object_free(obj); @@ -176,7 +176,7 @@ static void internal_cache_ct_event_upd(struct nf_conntrack *ct, int origin) return; if (origin == CTD_ORIGIN_NOT_ME) - sync_send(obj, NET_T_STATE_UPD); + sync_send(obj, NET_T_STATE_CT_UPD); } static int internal_cache_ct_event_del(struct nf_conntrack *ct, int origin) @@ -196,7 +196,7 @@ static int internal_cache_ct_event_del(struct nf_conntrack *ct, int origin) if (obj->status != C_OBJ_DEAD) { cache_object_set_status(obj, C_OBJ_DEAD); if (origin == CTD_ORIGIN_NOT_ME) { - sync_send(obj, NET_T_STATE_DEL); + sync_send(obj, NET_T_STATE_CT_DEL); } cache_object_put(obj); } diff --git a/src/network.c b/src/network.c index 6a66a2b..cadc466 100644 --- a/src/network.c +++ b/src/network.c @@ -1,6 +1,7 @@ /* - * (C) 2006-2007 by Pablo Neira Ayuso - * + * (C) 2006-2011 by Pablo Neira Ayuso + * (C) 2011 by Vyatta Inc. + * * 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 * the Free Software Foundation; either version 2 of the License, or @@ -119,13 +120,15 @@ int nethdr_track_is_seq_set() #include "cache.h" -static int status2type[] = { - [C_OBJ_NEW] = NET_T_STATE_NEW, - [C_OBJ_ALIVE] = NET_T_STATE_UPD, - [C_OBJ_DEAD] = NET_T_STATE_DEL, +static int status2type[CACHE_T_MAX][C_OBJ_MAX] = { + [CACHE_T_CT] = { + [C_OBJ_NEW] = NET_T_STATE_CT_NEW, + [C_OBJ_ALIVE] = NET_T_STATE_CT_UPD, + [C_OBJ_DEAD] = NET_T_STATE_CT_DEL, + }, }; -int object_status_to_network_type(int status) +int object_status_to_network_type(struct cache_object *obj) { - return status2type[status]; + return status2type[obj->cache->type][obj->status]; } diff --git a/src/parse.c b/src/parse.c index 7e60597..0718128 100644 --- a/src/parse.c +++ b/src/parse.c @@ -1,6 +1,7 @@ /* - * (C) 2006-2007 by Pablo Neira Ayuso - * + * (C) 2006-2011 by Pablo Neira Ayuso + * (C) 2011 by Vyatta Inc. + * * 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 * the Free Software Foundation; either version 2 of the License, or @@ -24,184 +25,184 @@ #define ssizeof(x) (int)sizeof(x) #endif -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); +static void ct_parse_u8(struct nf_conntrack *ct, int attr, void *data); +static void ct_parse_u16(struct nf_conntrack *ct, int attr, void *data); +static void ct_parse_u32(struct nf_conntrack *ct, int attr, void *data); +static void ct_parse_group(struct nf_conntrack *ct, int attr, void *data); +static void ct_parse_nat_seq_adj(struct nf_conntrack *ct, int attr, void *data); -struct parser { +struct ct_parser { void (*parse)(struct nf_conntrack *ct, int attr, void *data); int attr; int size; }; -static struct parser h[NTA_MAX] = { +static struct ct_parser h[NTA_MAX] = { [NTA_IPV4] = { - .parse = parse_group, + .parse = ct_parse_group, .attr = ATTR_GRP_ORIG_IPV4, .size = NTA_SIZE(sizeof(struct nfct_attr_grp_ipv4)), }, [NTA_IPV6] = { - .parse = parse_group, + .parse = ct_parse_group, .attr = ATTR_GRP_ORIG_IPV6, .size = NTA_SIZE(sizeof(struct nfct_attr_grp_ipv6)), }, [NTA_PORT] = { - .parse = parse_group, + .parse = ct_parse_group, .attr = ATTR_GRP_ORIG_PORT, .size = NTA_SIZE(sizeof(struct nfct_attr_grp_port)), }, [NTA_L4PROTO] = { - .parse = parse_u8, + .parse = ct_parse_u8, .attr = ATTR_L4PROTO, .size = NTA_SIZE(sizeof(uint8_t)), }, [NTA_TCP_STATE] = { - .parse = parse_u8, + .parse = ct_parse_u8, .attr = ATTR_TCP_STATE, .size = NTA_SIZE(sizeof(uint8_t)), }, [NTA_STATUS] = { - .parse = parse_u32, + .parse = ct_parse_u32, .attr = ATTR_STATUS, .size = NTA_SIZE(sizeof(uint32_t)), }, [NTA_MARK] = { - .parse = parse_u32, + .parse = ct_parse_u32, .attr = ATTR_MARK, .size = NTA_SIZE(sizeof(uint32_t)), }, [NTA_TIMEOUT] = { - .parse = parse_u32, + .parse = ct_parse_u32, .attr = ATTR_TIMEOUT, .size = NTA_SIZE(sizeof(uint32_t)), }, [NTA_MASTER_IPV4] = { - .parse = parse_group, + .parse = ct_parse_group, .attr = ATTR_GRP_MASTER_IPV4, .size = NTA_SIZE(sizeof(struct nfct_attr_grp_ipv4)), }, [NTA_MASTER_IPV6] = { - .parse = parse_group, + .parse = ct_parse_group, .attr = ATTR_GRP_MASTER_IPV6, .size = NTA_SIZE(sizeof(struct nfct_attr_grp_ipv6)), }, [NTA_MASTER_L4PROTO] = { - .parse = parse_u8, + .parse = ct_parse_u8, .attr = ATTR_MASTER_L4PROTO, .size = NTA_SIZE(sizeof(uint8_t)), }, [NTA_MASTER_PORT] = { - .parse = parse_group, + .parse = ct_parse_group, .attr = ATTR_GRP_MASTER_PORT, .size = NTA_SIZE(sizeof(struct nfct_attr_grp_port)), }, [NTA_SNAT_IPV4] = { - .parse = parse_u32, + .parse = ct_parse_u32, .attr = ATTR_SNAT_IPV4, .size = NTA_SIZE(sizeof(uint32_t)), }, [NTA_DNAT_IPV4] = { - .parse = parse_u32, + .parse = ct_parse_u32, .attr = ATTR_DNAT_IPV4, .size = NTA_SIZE(sizeof(uint32_t)), }, [NTA_SPAT_PORT] = { - .parse = parse_u16, + .parse = ct_parse_u16, .attr = ATTR_SNAT_PORT, .size = NTA_SIZE(sizeof(uint16_t)), }, [NTA_DPAT_PORT] = { - .parse = parse_u16, + .parse = ct_parse_u16, .attr = ATTR_DNAT_PORT, .size = NTA_SIZE(sizeof(uint16_t)), }, [NTA_NAT_SEQ_ADJ] = { - .parse = parse_nat_seq_adj, + .parse = ct_parse_nat_seq_adj, .size = NTA_SIZE(sizeof(struct nta_attr_natseqadj)), }, [NTA_SCTP_STATE] = { - .parse = parse_u8, + .parse = ct_parse_u8, .attr = ATTR_SCTP_STATE, .size = NTA_SIZE(sizeof(uint8_t)), }, [NTA_SCTP_VTAG_ORIG] = { - .parse = parse_u32, + .parse = ct_parse_u32, .attr = ATTR_SCTP_VTAG_ORIG, .size = NTA_SIZE(sizeof(uint32_t)), }, [NTA_SCTP_VTAG_REPL] = { - .parse = parse_u32, + .parse = ct_parse_u32, .attr = ATTR_SCTP_VTAG_REPL, .size = NTA_SIZE(sizeof(uint32_t)), }, [NTA_DCCP_STATE] = { - .parse = parse_u8, + .parse = ct_parse_u8, .attr = ATTR_DCCP_STATE, .size = NTA_SIZE(sizeof(uint8_t)), }, [NTA_DCCP_ROLE] = { - .parse = parse_u8, + .parse = ct_parse_u8, .attr = ATTR_DCCP_ROLE, .size = NTA_SIZE(sizeof(uint8_t)), }, [NTA_ICMP_TYPE] = { - .parse = parse_u8, + .parse = ct_parse_u8, .attr = ATTR_ICMP_TYPE, .size = NTA_SIZE(sizeof(uint8_t)), }, [NTA_ICMP_CODE] = { - .parse = parse_u8, + .parse = ct_parse_u8, .attr = ATTR_ICMP_CODE, .size = NTA_SIZE(sizeof(uint8_t)), }, [NTA_ICMP_ID] = { - .parse = parse_u16, + .parse = ct_parse_u16, .attr = ATTR_ICMP_ID, .size = NTA_SIZE(sizeof(uint16_t)), }, [NTA_TCP_WSCALE_ORIG] = { - .parse = parse_u8, + .parse = ct_parse_u8, .attr = ATTR_TCP_WSCALE_ORIG, .size = NTA_SIZE(sizeof(uint8_t)), }, [NTA_TCP_WSCALE_REPL] = { - .parse = parse_u8, + .parse = ct_parse_u8, .attr = ATTR_TCP_WSCALE_REPL, .size = NTA_SIZE(sizeof(uint8_t)), }, }; static void -parse_u8(struct nf_conntrack *ct, int attr, void *data) +ct_parse_u8(struct nf_conntrack *ct, int attr, void *data) { uint8_t *value = (uint8_t *) data; nfct_set_attr_u8(ct, h[attr].attr, *value); } static void -parse_u16(struct nf_conntrack *ct, int attr, void *data) +ct_parse_u16(struct nf_conntrack *ct, int attr, void *data) { uint16_t *value = (uint16_t *) data; nfct_set_attr_u16(ct, h[attr].attr, ntohs(*value)); } static void -parse_u32(struct nf_conntrack *ct, int attr, void *data) +ct_parse_u32(struct nf_conntrack *ct, int attr, void *data) { uint32_t *value = (uint32_t *) data; nfct_set_attr_u32(ct, h[attr].attr, ntohl(*value)); } static void -parse_group(struct nf_conntrack *ct, int attr, void *data) +ct_parse_group(struct nf_conntrack *ct, int attr, void *data) { nfct_set_attr_grp(ct, h[attr].attr, data); } static void -parse_nat_seq_adj(struct nf_conntrack *ct, int attr, void *data) +ct_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, @@ -218,7 +219,7 @@ parse_nat_seq_adj(struct nf_conntrack *ct, int attr, void *data) ntohl(this->repl_seq_offset_after)); } -int parse_payload(struct nf_conntrack *ct, struct nethdr *net, size_t remain) +int msg2ct(struct nf_conntrack *ct, struct nethdr *net, size_t remain) { int len; struct netattr *attr; diff --git a/src/sync-alarm.c b/src/sync-alarm.c index 8d6b34d..65154a1 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -42,7 +42,7 @@ static void refresher(struct alarm_block *a, void *data) random() % CONFIG(refresh) + 1, ((random() % 5 + 1) * 200000) - 1); - alarm_enqueue(obj, NET_T_STATE_UPD); + alarm_enqueue(obj, NET_T_STATE_CT_UPD); } static void cache_alarm_add(struct cache_object *obj, void *data) @@ -137,7 +137,7 @@ static int tx_queue_xmit(struct queue_node *n, const void *data) ca = (struct cache_alarm *)n; obj = cache_data_get_object(STATE(mode)->internal->ct.data, ca); - type = object_status_to_network_type(obj->status); + type = object_status_to_network_type(obj); net = obj->cache->ops->build_msg(obj, type); multichannel_send(STATE_SYNC(channel), net); cache_object_put(obj); diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 55eda0b..cff4d25 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -518,7 +518,7 @@ static int tx_queue_xmit(struct queue_node *n, const void *data) cn = (struct cache_ftfw *)n; obj = cache_data_get_object(STATE(mode)->internal->ct.data, cn); - type = object_status_to_network_type(obj->status); + type = object_status_to_network_type(obj); net = obj->cache->ops->build_msg(obj, type); nethdr_set_hello(net); diff --git a/src/sync-mode.c b/src/sync-mode.c index 7f019f7..17533f8 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -41,6 +41,24 @@ #include #include +static struct nf_conntrack *msg2ct_alloc(struct nethdr *net, size_t remain) +{ + struct nf_conntrack *ct; + + /* TODO: add stats on ENOMEM errors in the future. */ + ct = nfct_new(); + if (ct == NULL) + return NULL; + + if (msg2ct(ct, net, remain) == -1) { + STATE_SYNC(error).msg_rcv_malformed++; + STATE_SYNC(error).msg_rcv_bad_payload++; + nfct_destroy(ct); + return NULL; + } + return ct; +} + static void do_channel_handler_step(int i, struct nethdr *net, size_t remain) { @@ -74,26 +92,24 @@ do_channel_handler_step(int i, struct nethdr *net, size_t remain) STATE_SYNC(error).msg_rcv_bad_type++; return; } - /* TODO: add stats on ENOMEM errors in the future. */ - ct = nfct_new(); - if (ct == NULL) - return; - - if (parse_payload(ct, net, remain) == -1) { - STATE_SYNC(error).msg_rcv_malformed++; - STATE_SYNC(error).msg_rcv_bad_payload++; - nfct_destroy(ct); - return; - } switch(net->type) { - case NET_T_STATE_NEW: + case NET_T_STATE_CT_NEW: + ct = msg2ct_alloc(net, remain); + if (ct == NULL) + return; STATE_SYNC(external)->ct.new(ct); break; - case NET_T_STATE_UPD: + case NET_T_STATE_CT_UPD: + ct = msg2ct_alloc(net, remain); + if (ct == NULL) + return; STATE_SYNC(external)->ct.upd(ct); break; - case NET_T_STATE_DEL: + case NET_T_STATE_CT_DEL: + ct = msg2ct_alloc(net, remain); + if (ct == NULL) + return; STATE_SYNC(external)->ct.del(ct); break; default: diff --git a/src/sync-notrack.c b/src/sync-notrack.c index e25cfd8..6c798ac 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -1,6 +1,7 @@ /* - * (C) 2008 by Pablo Neira Ayuso - * + * (C) 2006-2011 by Pablo Neira Ayuso + * (C) 2011 by Vyatta Inc. + * * 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 * the Free Software Foundation; either version 2 of the License, or @@ -87,7 +88,7 @@ static int kernel_resync_cb(enum nf_conntrack_msg_type type, { struct nethdr *net; - net = BUILD_NETMSG(ct, NET_T_STATE_NEW); + net = BUILD_NETMSG_FROM_CT(ct, NET_T_STATE_CT_NEW); multichannel_send(STATE_SYNC(channel), net); return NFCT_CB_CONTINUE; @@ -198,7 +199,7 @@ static int tx_queue_xmit(struct queue_node *n, const void *data2) cn = (struct cache_ftfw *)n; obj = cache_data_get_object(STATE(mode)->internal->ct.data, cn); - type = object_status_to_network_type(obj->status);; + type = object_status_to_network_type(obj);; net = obj->cache->ops->build_msg(obj, type); multichannel_send(STATE_SYNC(channel), net); -- cgit v1.2.3 From 79ab299bfb20b7fc1982ca90d77d8b908b824fea Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 4 Jan 2012 14:31:41 +0100 Subject: conntrackd: simplify cache_get_extra function This patch simplifies cache_get_extra which now takes only one parameter that is the cache_object. With it, the extra area can be calculated. Signed-off-by: Pablo Neira Ayuso --- include/cache.h | 2 +- src/cache.c | 4 ++-- src/sync-alarm.c | 3 +-- src/sync-ftfw.c | 6 ++---- src/sync-notrack.c | 6 ++---- 5 files changed, 8 insertions(+), 13 deletions(-) (limited to 'src/sync-notrack.c') diff --git a/include/cache.h b/include/cache.h index 02bb386..65f7e3a 100644 --- a/include/cache.h +++ b/include/cache.h @@ -148,7 +148,7 @@ struct cache_object *cache_find(struct cache *c, void *ptr, int *pos); void cache_stats(const struct cache *c, int fd); void cache_stats_extended(const struct cache *c, int fd); struct cache_object *cache_data_get_object(struct cache *c, void *data); -void *cache_get_extra(struct cache *, void *); +void *cache_get_extra(struct cache_object *); void cache_iterate(struct cache *c, void *data, int (*iterate)(void *data1, void *data2)); void cache_iterate_limit(struct cache *c, void *data, uint32_t from, uint32_t steps, int (*iterate)(void *data1, void *data2)); diff --git a/src/cache.c b/src/cache.c index efdab0e..f515ba0 100644 --- a/src/cache.c +++ b/src/cache.c @@ -308,9 +308,9 @@ struct cache_object *cache_data_get_object(struct cache *c, void *data) return (struct cache_object *)((char*)data - c->extra_offset); } -void *cache_get_extra(struct cache *c, void *data) +void *cache_get_extra(struct cache_object *obj) { - return (char*)data + c->extra_offset; + return (char*)obj + obj->cache->extra_offset; } void cache_stats(const struct cache *c, int fd) diff --git a/src/sync-alarm.c b/src/sync-alarm.c index 65154a1..03481fd 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -110,8 +110,7 @@ static int alarm_recv(const struct nethdr *net) static void alarm_enqueue(struct cache_object *obj, int query) { - struct cache_alarm *ca = - cache_get_extra(STATE(mode)->internal->ct.data, obj); + struct cache_alarm *ca = cache_get_extra(obj); if (queue_add(STATE_SYNC(tx_queue), &ca->qnode) > 0) cache_object_get(obj); } diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index cff4d25..c7cc4aa 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -169,8 +169,7 @@ static void ftfw_kill(void) static int do_cache_to_tx(void *data1, void *data2) { struct cache_object *obj = data2; - struct cache_ftfw *cn = - cache_get_extra(STATE(mode)->internal->ct.data, obj); + struct cache_ftfw *cn = cache_get_extra(obj); if (queue_in(rs_queue, &cn->qnode)) { queue_del(&cn->qnode); @@ -551,8 +550,7 @@ static void ftfw_xmit(void) static void ftfw_enqueue(struct cache_object *obj, int type) { - struct cache_ftfw *cn = - cache_get_extra(STATE(mode)->internal->ct.data, obj); + struct cache_ftfw *cn = cache_get_extra(obj); if (queue_in(rs_queue, &cn->qnode)) { queue_del(&cn->qnode); queue_add(STATE_SYNC(tx_queue), &cn->qnode); diff --git a/src/sync-notrack.c b/src/sync-notrack.c index 6c798ac..a8cc6bf 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -76,8 +76,7 @@ static void tx_queue_add_ctlmsg(uint32_t flags, uint32_t from, uint32_t to) static int do_cache_to_tx(void *data1, void *data2) { struct cache_object *obj = data2; - struct cache_notrack *cn = - cache_get_extra(STATE(mode)->internal->ct.data, obj); + struct cache_notrack *cn = cache_get_extra(obj); if (queue_add(STATE_SYNC(tx_queue), &cn->qnode) > 0) cache_object_get(obj); return 0; @@ -219,8 +218,7 @@ static void notrack_xmit(void) static void notrack_enqueue(struct cache_object *obj, int query) { - struct cache_notrack *cn = - cache_get_extra(STATE(mode)->internal->ct.data, obj); + struct cache_notrack *cn = cache_get_extra(obj); if (queue_add(STATE_SYNC(tx_queue), &cn->qnode) > 0) cache_object_get(obj); } -- cgit v1.2.3 From 75a7cd3c722e1abca14fc375bec8ab30c34ab284 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 16 Nov 2011 02:10:31 +0100 Subject: conntrackd: remove cache_data_get_object and replace by direct pointer We now include one pointer to the object in the extra section. This is required to generalize this code for the expectation support. We consume 4-8 bytes extra, but we will not need more changes to support expectations which is a good idea. --- include/cache.h | 1 - src/cache.c | 5 ----- src/sync-alarm.c | 10 +++++----- src/sync-ftfw.c | 19 +++++++------------ src/sync-notrack.c | 14 +++++++------- 5 files changed, 19 insertions(+), 30 deletions(-) (limited to 'src/sync-notrack.c') diff --git a/include/cache.h b/include/cache.h index 65f7e3a..abebb97 100644 --- a/include/cache.h +++ b/include/cache.h @@ -147,7 +147,6 @@ void cache_del(struct cache *c, struct cache_object *obj); struct cache_object *cache_find(struct cache *c, void *ptr, int *pos); void cache_stats(const struct cache *c, int fd); void cache_stats_extended(const struct cache *c, int fd); -struct cache_object *cache_data_get_object(struct cache *c, void *data); void *cache_get_extra(struct cache_object *); void cache_iterate(struct cache *c, void *data, int (*iterate)(void *data1, void *data2)); void cache_iterate_limit(struct cache *c, void *data, uint32_t from, uint32_t steps, int (*iterate)(void *data1, void *data2)); diff --git a/src/cache.c b/src/cache.c index f515ba0..7c41e54 100644 --- a/src/cache.c +++ b/src/cache.c @@ -303,11 +303,6 @@ struct cache_object *cache_find(struct cache *c, void *ptr, int *id) return ((struct cache_object *) hashtable_find(c->h, ptr, *id)); } -struct cache_object *cache_data_get_object(struct cache *c, void *data) -{ - return (struct cache_object *)((char*)data - c->extra_offset); -} - void *cache_get_extra(struct cache_object *obj) { return (char*)obj + obj->cache->extra_offset; diff --git a/src/sync-alarm.c b/src/sync-alarm.c index 03481fd..acaf5e6 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -29,6 +29,7 @@ struct cache_alarm { struct queue_node qnode; + struct cache_object *obj; struct alarm_block alarm; }; @@ -50,6 +51,7 @@ static void cache_alarm_add(struct cache_object *obj, void *data) struct cache_alarm *ca = data; queue_node_init(&ca->qnode, Q_ELEM_OBJ); + ca->obj = obj; init_alarm(&ca->alarm, obj, refresher); add_alarm(&ca->alarm, random() % CONFIG(refresh) + 1, @@ -131,15 +133,13 @@ static int tx_queue_xmit(struct queue_node *n, const void *data) break; case Q_ELEM_OBJ: { struct cache_alarm *ca; - struct cache_object *obj; int type; ca = (struct cache_alarm *)n; - obj = cache_data_get_object(STATE(mode)->internal->ct.data, ca); - type = object_status_to_network_type(obj); - net = obj->cache->ops->build_msg(obj, type); + type = object_status_to_network_type(ca->obj); + net = ca->obj->cache->ops->build_msg(ca->obj, type); multichannel_send(STATE_SYNC(channel), net); - cache_object_put(obj); + cache_object_put(ca->obj); break; } } diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index c7cc4aa..fa76c0c 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -55,12 +55,14 @@ static int say_hello_back; struct cache_ftfw { struct queue_node qnode; + struct cache_object *obj; uint32_t seq; }; static void cache_ftfw_add(struct cache_object *obj, void *data) { struct cache_ftfw *cn = data; + cn->obj = obj; /* These nodes are not inserted in the list */ queue_node_init(&cn->qnode, Q_ELEM_OBJ); } @@ -302,13 +304,11 @@ static int rs_queue_empty(struct queue_node *n, const void *data) } case Q_ELEM_OBJ: { struct cache_ftfw *cn; - struct cache_object *obj; cn = (struct cache_ftfw *) n; if (h == NULL) { queue_del(n); - obj = cache_data_get_object(STATE(mode)->internal->ct.data, cn); - cache_object_put(obj); + cache_object_put(cn->obj); return 0; } if (before(cn->seq, h->from)) @@ -318,8 +318,7 @@ static int rs_queue_empty(struct queue_node *n, const void *data) dp("queue: deleting from queue (seq=%u)\n", cn->seq); queue_del(n); - obj = cache_data_get_object(STATE(mode)->internal->ct.data, cn); - cache_object_put(obj); + cache_object_put(cn->obj); break; } } @@ -465,11 +464,9 @@ static void rs_queue_purge_full(void) } case Q_ELEM_OBJ: { struct cache_ftfw *cn; - struct cache_object *obj; cn = (struct cache_ftfw *)n; - obj = cache_data_get_object(STATE(mode)->internal->ct.data, cn); - cache_object_put(obj); + cache_object_put(cn->obj); break; } } @@ -511,14 +508,12 @@ static int tx_queue_xmit(struct queue_node *n, const void *data) } case Q_ELEM_OBJ: { struct cache_ftfw *cn; - struct cache_object *obj; int type; struct nethdr *net; cn = (struct cache_ftfw *)n; - obj = cache_data_get_object(STATE(mode)->internal->ct.data, cn); - type = object_status_to_network_type(obj); - net = obj->cache->ops->build_msg(obj, type); + type = object_status_to_network_type(cn->obj); + net = cn->obj->cache->ops->build_msg(cn->obj, type); nethdr_set_hello(net); dp("tx_list sq: %u fl:%u len:%u\n", diff --git a/src/sync-notrack.c b/src/sync-notrack.c index a8cc6bf..06ad1f0 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -34,12 +34,14 @@ static struct alarm_block alive_alarm; struct cache_notrack { struct queue_node qnode; + struct cache_object *obj; }; static void cache_notrack_add(struct cache_object *obj, void *data) { struct cache_notrack *cn = data; queue_node_init(&cn->qnode, Q_ELEM_OBJ); + cn->obj = obj; } static void cache_notrack_del(struct cache_object *obj, void *data) @@ -191,19 +193,17 @@ static int tx_queue_xmit(struct queue_node *n, const void *data2) break; } case Q_ELEM_OBJ: { - struct cache_ftfw *cn; - struct cache_object *obj; + struct cache_notrack *cn; int type; struct nethdr *net; - cn = (struct cache_ftfw *)n; - obj = cache_data_get_object(STATE(mode)->internal->ct.data, cn); - type = object_status_to_network_type(obj);; - net = obj->cache->ops->build_msg(obj, type); + cn = (struct cache_notrack *)n; + type = object_status_to_network_type(cn->obj); + net = cn->obj->cache->ops->build_msg(cn->obj, type); multichannel_send(STATE_SYNC(channel), net); queue_del(n); - cache_object_put(obj); + cache_object_put(cn->obj); break; } } -- cgit v1.2.3 From 79a777c60cfe02197c135adcc4edb2f63ae9a695 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 19 Dec 2011 17:13:25 +0100 Subject: conntrackd: support for expectation synchronization This patch adds support to synchronize expectations between firewalls. This addition aims to re-use as much as possible of the existing infrastructure for stability reasons. The expectation support has been tested with the FTP helper. This extension requires libnetfilter_conntrack 1.0.0. If this is the first time you're playing with conntrackd, I *strongly* recommend you to get working setup of conntrackd without expectation support before as described in the documentation. Then, enabling expectation support is rather easy. To know more about expectations, if you're not familiar with them, I suggest you to read: "Netfilter's Connection Tracking System" http://people.netfilter.org/pablo/docs/login.pdf Reprinted from ;login: The Magazine of USENIX, vol. 31, no. 3 (Berkeley, CA: USENIX Association, 2006, pp40-45.) In short, expectations allow one Linux firewall to filter multi-flow traffic like FTP, SIP and H.323. In my testbed, there are two firewalls in a primary-backup configuration running keepalived. The use a couple of floating cluster IP address (192.168.0.100 and 192.168.1.100) that are used by the client. These firewalls protect one FTP server (192.168.1.2) that will be accessed by one client. In ASCII art, it looks like this: 192.168.0.100 192.168.1.100 eth1 eth2 fw-1 / \ FTP -- client ------ ------ server -- 192.168.0.2 \ / 192.168.1.2 fw-2 This is the rule-set for the firewalls: -A POSTROUTING -t nat -s 192.168.0.2/32 -d 192.168.1.2/32 -j SNAT --to-source 192.168.1.100 -A INPUT -p tcp -m tcp --dport 22 -j ACCEPT -A INPUT -m state --state INVALID -j DROP -A FORWARD -m state --state RELATED -j ACCEPT -A FORWARD -i eth2 -m state --state ESTABLISHED -j ACCEPT -A FORWARD -i eth1 -p tcp -m tcp --dport 21 --tcp-flags FIN,SYN,RST,ACK SYN -m state --state NEW -j ACCEPT -A FORWARD -i eth1 -p tcp -m state --state ESTABLISHED -j ACCEPT -A FORWARD -m state --state INVALID -j LOG --log-prefix "invalid: " The following steps detail how to check that the expectation support works fine for conntrackd: 1) You have to enable the expectation support in the configuration file with the following option: Sync { ... Options { ExpectationSync { ftp sip h323 } } } This enables expectation synchronization for the FTP, SIP and H.323 helpers. You can alternatively use: Sync { ... Options { ExpectationSync On } } To enable expectation synchronization for all helpers. 2) Make sure you have loaded the FTP helper in both firewalls. root@fw1# modprobe nf_conntrack_ftp root@fw2# modprobe nf_conntrack_ftp 3) Switch to the client. Start one FTP control connection to one server that is protected by the firewalls, enter passive mode: (term-1) user@client$ nc 192.168.1.2 21 220 dummy FTP server USER anonymous 331 Please specify the password. PASS nothing 230 Login successful. PASV 227 Entering Passive Mode (192,168,1,2,163,11). This means that port 163*256+11=41739 will be used for the data traffic. Read this if you are not familiar with the FTP protocol: http://www.freefire.org/articles/ftpexample.php 3) Switch to fw-1 (primary) to check that the expectation is in the internal cache. root@fw1# conntrackd -i exp proto=6 src=192.168.0.2 dst=192.168.1.2 sport=0 dport=41739 mask-src=255.255.255.255 mask-dst=255.255.255.255 sport=0 dport=65535 master-src=192.168.0.2 master-dst=192.168.1.2 sport=36390 dport=21 [active since 5s] 4) Switch to fw-2 (backup) to check that the expectation has been successfully replicated. root@fw2# conntrackd -e exp proto=6 src=192.168.0.2 dst=192.168.1.2 sport=0 dport=41739 mask-src=255.255.255.255 mask-dst=255.255.255.255 sport=0 dport=65535 master-src=192.168.0.2 master-dst=192.168.1.2 sport=36390 dport=21 [active since 8s] 5) Make the primary firewall fw-1 fail. Now fw-2 becomes primary. 6) Switch to fw-2 (primary) to commit the external cache into the kernel. root@fw2# conntrackd -c exp The logs should display that the commit was successful: root@fw2# tail -100f /var/log/conntrackd.log [Wed Dec 7 22:16:31 2011] (pid=19195) [notice] committing external cache: expectations [Wed Dec 7 22:16:31 2011] (pid=19195) [notice] Committed 1 new entries [Wed Dec 7 22:16:31 2011] (pid=19195) [notice] commit has taken 0.000366 seconds 7) Switch to the client. Open a new terminal and connect to the port that has been announced by the server: (term-2) user@client$ nc -vvv 192.168.1.2 41739 (UNKNOWN) [192.168.1.2] 41739 (?) open 8) Switch to term-1 and ask for the file listing: [...] 227 Entering Passive Mode (192,168,1,2,163,11). LIST 9) Switch to term-2, it should display the listing. That means everything has worked fine. You may want to try disabling the expectation support and repeating the steps to check that *it does not work* without the state-synchronization. You can also display expectation statistics by means of: root@fwX# conntrackd -s exp This update requires no changes in the primary-backup.sh script that is used by the HA manager to interact with conntrackd. Thus, we provide a backward compatible command line interface. Regarding the Filter clause and expectations, we use the master conntrack to filter expectation events. The filtering is performed in user-space. No kernel-space filtering support for expectations yet (this support should go in libnetfilter_conntrack at some point). This patch also includes support to disable caching and to allow direct injection of expectations. Signed-off-by: Pablo Neira Ayuso --- configure.ac | 2 +- conntrackd.8 | 12 +- doc/sync/alarm/conntrackd.conf | 16 ++ doc/sync/ftfw/conntrackd.conf | 16 ++ doc/sync/notrack/conntrackd.conf | 16 ++ include/cache.h | 4 + include/conntrackd.h | 19 +++ include/external.h | 11 ++ include/filter.h | 7 + include/internal.h | 17 +++ include/log.h | 2 + include/netlink.h | 7 + include/network.h | 40 ++++- src/Makefile.am | 2 +- src/build.c | 99 +++++++++++++ src/cache-ct.c | 6 +- src/cache-exp.c | 308 +++++++++++++++++++++++++++++++++++++++ src/external_cache.c | 85 +++++++++++ src/external_inject.c | 95 +++++++++++- src/filter.c | 76 ++++++++++ src/internal_bypass.c | 146 ++++++++++++++++++- src/internal_cache.c | 173 ++++++++++++++++++++++ src/log.c | 37 +++++ src/main.c | 69 +++++++-- src/netlink.c | 63 +++++++- src/network.c | 5 + src/parse.c | 192 ++++++++++++++++++++++++ src/read_config_lex.l | 1 + src/read_config_yy.y | 50 ++++++- src/run.c | 206 +++++++++++++++++++++++--- src/sync-ftfw.c | 7 +- src/sync-mode.c | 165 ++++++++++++++++++--- src/sync-notrack.c | 6 +- 33 files changed, 1889 insertions(+), 71 deletions(-) create mode 100644 src/cache-exp.c (limited to 'src/sync-notrack.c') diff --git a/configure.ac b/configure.ac index 0481e23..26a7e02 100644 --- a/configure.ac +++ b/configure.ac @@ -52,7 +52,7 @@ else fi PKG_CHECK_MODULES([LIBNFNETLINK], [libnfnetlink >= 1.0.0]) -PKG_CHECK_MODULES([LIBNETFILTER_CONNTRACK], [libnetfilter_conntrack >= 0.9.1]) +PKG_CHECK_MODULES([LIBNETFILTER_CONNTRACK], [libnetfilter_conntrack >= 1.0.0]) AC_CHECK_HEADERS([linux/capability.h],, [AC_MSG_ERROR([Cannot find linux/capabibility.h])]) diff --git a/conntrackd.8 b/conntrackd.8 index 0c9054e..f07ad7a 100644 --- a/conntrackd.8 +++ b/conntrackd.8 @@ -24,10 +24,10 @@ Run conntrackd in daemon mode. .B conntrackd can be used in client mode to request several information and operations to a running daemon .TP -.BI "-i " +.BI "-i "[ct|expect]" Dump the internal cache, i.e. show local states .TP -.BI "-e " +.BI "-e "[ct|expect]" Dump the external cache, i.e. show foreign states .TP .BI "-x " @@ -37,7 +37,7 @@ with "-i" and "-e" parameters. .BI "-f " "[|internal|external]" Flush the internal and/or external cache .TP -.BI "-F " +.BI "-F [ct|expect]" Flush the kernel conntrack table (if you use a Linux kernel >= 2.6.29, this option will not flush your internal and external cache). .TP @@ -48,15 +48,17 @@ ask conntrackd to send the state-entries that it owns to others. .BI "-k " Kill the daemon .TP -.BI "-s " "[|network|cache|runtime|link|rsqueue|process|queue]" +.BI "-s " "[|network|cache|runtime|link|rsqueue|process|queue|ct|expect]" Dump statistics. If no parameter is passed, it displays the general statistics. If "network" is passed as parameter it displays the networking statistics. If "cache" is passed as parameter, it shows the extended cache statistics. If "runtime" is passed as parameter, it shows the run-time statistics. If "process" is passed as parameter, it shows existing child processes (if any). If "queue" is passed as parameter, it shows queue statistics. +If "ct" is passed, it displays the general statistics. +If "expect" is passed as parameter, it shows expectation statistics. .TP -.BI "-R " +.BI "-R " "[ct|expect]" Force a resync against the kernel connection tracking table .TP .BI "-t " diff --git a/doc/sync/alarm/conntrackd.conf b/doc/sync/alarm/conntrackd.conf index d05b499..deed291 100644 --- a/doc/sync/alarm/conntrackd.conf +++ b/doc/sync/alarm/conntrackd.conf @@ -191,6 +191,22 @@ Sync { # This feature requires a Linux kernel >= 2.6.36. # # TCPWindowTracking Off + + # Set this option on if you want to enable the synchronization + # of expectations. You have to specify the list of helpers that + # you want to enable. Default is off. + # + # ExpectationSync { + # ftp + # h323 + # sip + # } + # + # You can use this alternatively: + # + # ExpectationSync On + # + # If you want to synchronize expectations of all helpers. # } } diff --git a/doc/sync/ftfw/conntrackd.conf b/doc/sync/ftfw/conntrackd.conf index c52f214..0304f0f 100644 --- a/doc/sync/ftfw/conntrackd.conf +++ b/doc/sync/ftfw/conntrackd.conf @@ -214,6 +214,22 @@ Sync { # This feature requires a Linux kernel >= 2.6.36. # # TCPWindowTracking Off + + # Set this option on if you want to enable the synchronization + # of expectations. You have to specify the list of helpers that + # you want to enable. Default is off. + # + # ExpectationSync { + # ftp + # h323 + # sip + # } + # + # You can use this alternatively: + # + # ExpectationSync On + # + # If you want to synchronize expectations of all helpers. # } } diff --git a/doc/sync/notrack/conntrackd.conf b/doc/sync/notrack/conntrackd.conf index 4d77266..34e7b32 100644 --- a/doc/sync/notrack/conntrackd.conf +++ b/doc/sync/notrack/conntrackd.conf @@ -253,6 +253,22 @@ Sync { # This feature requires a Linux kernel >= 2.6.36. # # TCPWindowTracking Off + + # Set this option on if you want to enable the synchronization + # of expectations. You have to specify the list of helpers that + # you want to enable. Default is off. + # + # ExpectationSync { + # ftp + # h323 + # sip + # } + # + # You can use this alternatively: + # + # ExpectationSync On + # + # If you want to synchronize expectations of all helpers. # } } diff --git a/include/cache.h b/include/cache.h index abebb97..3af2741 100644 --- a/include/cache.h +++ b/include/cache.h @@ -52,6 +52,7 @@ extern struct cache_feature timer_feature; enum cache_type { CACHE_T_NONE = 0, CACHE_T_CT, + CACHE_T_EXP, CACHE_T_MAX }; @@ -128,6 +129,9 @@ struct cache_ops { extern struct cache_ops cache_sync_internal_ct_ops; extern struct cache_ops cache_sync_external_ct_ops; extern struct cache_ops cache_stats_ct_ops; +/* templates to configure expectation caching. */ +extern struct cache_ops cache_sync_internal_exp_ops; +extern struct cache_ops cache_sync_external_exp_ops; struct nf_conntrack; diff --git a/include/conntrackd.h b/include/conntrackd.h index 697d3d7..8baa088 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -37,6 +37,16 @@ #define CT_FLUSH_EXT_CACHE 34 /* flush external cache */ #define STATS_PROCESS 35 /* child process stats */ #define STATS_QUEUE 36 /* queue stats */ +#define EXP_STATS 37 /* dump statistics */ +#define EXP_FLUSH_MASTER 38 /* flush kernel expect table */ +#define EXP_RESYNC_MASTER 39 /* resync with kernel exp table */ +#define EXP_DUMP_INTERNAL 40 /* dump internal expect cache */ +#define EXP_DUMP_EXTERNAL 41 /* dump external expect cache */ +#define EXP_COMMIT 42 /* commit expectations */ +#define ALL_FLUSH_MASTER 43 /* flush all kernel tables */ +#define ALL_RESYNC_MASTER 44 /* resync w/all kernel tables */ +#define ALL_FLUSH_CACHE 45 /* flush all caches */ +#define ALL_COMMIT 46 /* commit all tables */ #define DEFAULT_CONFIGFILE "/etc/conntrackd/conntrackd.conf" #define DEFAULT_LOCKFILE "/var/lock/conntrackd.lock" @@ -56,6 +66,7 @@ #define CTD_SYNC_ALARM (1UL << 3) #define CTD_SYNC_NOTRACK (1UL << 4) #define CTD_POLL (1UL << 5) +#define CTD_EXPECT (1UL << 6) /* FILENAME_MAX is 4096 on my system, perhaps too much? */ #ifndef FILENAME_MAXLEN @@ -105,6 +116,8 @@ struct ct_conf { int tcp_window_tracking; } sync; struct { + int subsys_id; + int groups; int events_reliable; } netlink; struct { @@ -130,6 +143,7 @@ struct ct_general_state { struct local_server local; struct ct_mode *mode; struct ct_filter *us_filter; + struct exp_filter *exp_filter; struct nfct_handle *event; /* event handler */ struct nfct_filter *filter; /* event filter */ @@ -177,6 +191,10 @@ struct ct_general_state { } stats; }; +struct commit_runqueue { + int (*cb)(struct nfct_handle *h, int step); +}; + #define STATE_SYNC(x) state.sync->x struct ct_sync_state { @@ -196,6 +214,7 @@ struct ct_sync_state { struct nfct_handle *h; struct evfd *evfd; int current; + struct commit_runqueue rq[2]; struct { int ok; int fail; diff --git a/include/external.h b/include/external.h index eef0e42..70f0c5c 100644 --- a/include/external.h +++ b/include/external.h @@ -18,6 +18,17 @@ struct external_handler { void (*stats)(int fd); void (*stats_ext)(int fd); } ct; + struct { + void (*new)(struct nf_expect *exp); + void (*upd)(struct nf_expect *exp); + void (*del)(struct nf_expect *exp); + + void (*dump)(int fd, int type); + void (*flush)(void); + int (*commit)(struct nfct_handle *h, int fd); + void (*stats)(int fd); + void (*stats_ext)(int fd); + } exp; }; extern struct external_handler external_cache; diff --git a/include/filter.h b/include/filter.h index f19b18b..3c7c8cc 100644 --- a/include/filter.h +++ b/include/filter.h @@ -52,4 +52,11 @@ void ct_filter_set_logic(struct ct_filter *f, enum ct_filter_logic logic); int ct_filter_conntrack(const struct nf_conntrack *ct, int userspace); +struct exp_filter; +struct nf_expect; + +struct exp_filter *exp_filter_create(void); +int exp_filter_add(struct exp_filter *f, const char *helper_name); +int exp_filter_find(struct exp_filter *f, const struct nf_expect *exp); + #endif diff --git a/include/internal.h b/include/internal.h index f50eb79..2ba9714 100644 --- a/include/internal.h +++ b/include/internal.h @@ -34,6 +34,23 @@ struct internal_handler { void (*stats)(int fd); void (*stats_ext)(int fd); } ct; + struct { + void *data; + + void (*new)(struct nf_expect *exp, int origin_type); + void (*upd)(struct nf_expect *exp, int origin_type); + int (*del)(struct nf_expect *exp, int origin_type); + + void (*dump)(int fd, int type); + void (*populate)(struct nf_expect *exp); + void (*purge)(void); + int (*resync)(enum nf_conntrack_msg_type type, + struct nf_expect *exp, void *data); + void (*flush)(void); + + void (*stats)(int fd); + void (*stats_ext)(int fd); + } exp; }; extern struct internal_handler internal_cache; diff --git a/include/log.h b/include/log.h index f5c5b4f..ae58e79 100644 --- a/include/log.h +++ b/include/log.h @@ -4,10 +4,12 @@ #include struct nf_conntrack; +struct nf_expect; int init_log(void); void dlog(int priority, const char *format, ...); void dlog_ct(FILE *fd, struct nf_conntrack *ct, unsigned int type); +void dlog_exp(FILE *fd, struct nf_expect *exp, unsigned int type); void close_log(void); #endif diff --git a/include/netlink.h b/include/netlink.h index 0df0cbb..3bde30c 100644 --- a/include/netlink.h +++ b/include/netlink.h @@ -30,4 +30,11 @@ static inline int ct_is_related(const struct nf_conntrack *ct) nfct_attr_is_set(ct, ATTR_MASTER_PORT_DST)); } +int nl_create_expect(struct nfct_handle *h, const struct nf_expect *orig, int timeout); +int nl_destroy_expect(struct nfct_handle *h, const struct nf_expect *exp); +int nl_get_expect(struct nfct_handle *h, const struct nf_expect *exp); +int nl_dump_expect_table(struct nfct_handle *h); +int nl_flush_expect_table(struct nfct_handle *h); +int nl_send_expect_resync(struct nfct_handle *h); + #endif diff --git a/include/network.h b/include/network.h index d0531b9..ab95499 100644 --- a/include/network.h +++ b/include/network.h @@ -4,9 +4,10 @@ #include #include -#define CONNTRACKD_PROTOCOL_VERSION 0 +#define CONNTRACKD_PROTOCOL_VERSION 1 struct nf_conntrack; +struct nf_expect; struct nethdr { #if __BYTE_ORDER == __LITTLE_ENDIAN @@ -28,7 +29,10 @@ enum nethdr_type { NET_T_STATE_CT_NEW = 0, NET_T_STATE_CT_UPD, NET_T_STATE_CT_DEL, - NET_T_STATE_MAX = NET_T_STATE_CT_DEL, + NET_T_STATE_EXP_NEW = 3, + NET_T_STATE_EXP_UPD, + NET_T_STATE_EXP_DEL, + NET_T_STATE_MAX = NET_T_STATE_EXP_DEL, NET_T_CTL = 10, }; @@ -92,6 +96,17 @@ enum { __hdr; \ }) +#define BUILD_NETMSG_FROM_EXP(exp, query) \ +({ \ + static char __net[4096]; \ + struct nethdr *__hdr = (struct nethdr *) __net; \ + memset(__hdr, 0, NETHDR_SIZ); \ + nethdr_set(__hdr, query); \ + exp2msg(exp, __hdr); \ + HDR_HOST2NETWORK(__hdr); \ + __hdr; \ +}) + struct mcast_sock_multi; enum { @@ -239,4 +254,25 @@ struct nta_attr_natseqadj { void ct2msg(const struct nf_conntrack *ct, struct nethdr *n); int msg2ct(struct nf_conntrack *ct, struct nethdr *n, size_t remain); +enum nta_exp_attr { + NTA_EXP_MASTER_IPV4 = 0, /* struct nfct_attr_grp_ipv4 */ + NTA_EXP_MASTER_IPV6, /* struct nfct_attr_grp_ipv6 */ + NTA_EXP_MASTER_L4PROTO, /* uint8_t */ + NTA_EXP_MASTER_PORT, /* struct nfct_attr_grp_port */ + NTA_EXP_EXPECT_IPV4 = 4, /* struct nfct_attr_grp_ipv4 */ + NTA_EXP_EXPECT_IPV6, /* struct nfct_attr_grp_ipv6 */ + NTA_EXP_EXPECT_L4PROTO, /* uint8_t */ + NTA_EXP_EXPECT_PORT, /* struct nfct_attr_grp_port */ + NTA_EXP_MASK_IPV4 = 8, /* struct nfct_attr_grp_ipv4 */ + NTA_EXP_MASK_IPV6, /* struct nfct_attr_grp_ipv6 */ + NTA_EXP_MASK_L4PROTO, /* uint8_t */ + NTA_EXP_MASK_PORT, /* struct nfct_attr_grp_port */ + NTA_EXP_TIMEOUT, /* uint32_t */ + NTA_EXP_FLAGS, /* uint32_t */ + NTA_EXP_MAX +}; + +void exp2msg(const struct nf_expect *exp, struct nethdr *n); +int msg2exp(struct nf_expect *exp, struct nethdr *n, size_t remain); + #endif diff --git a/src/Makefile.am b/src/Makefile.am index a0abeee..7d7b2ac 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -12,7 +12,7 @@ conntrack_LDADD = ../extensions/libct_proto_tcp.la ../extensions/libct_proto_udp conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c rbtree.c \ local.c log.c mcast.c udp.c netlink.c vector.c \ filter.c fds.c event.c process.c origin.c date.c \ - cache.c cache-ct.c \ + cache.c cache-ct.c cache-exp.c \ cache_timer.c \ sync-mode.c sync-alarm.c sync-ftfw.c sync-notrack.c \ traffic_stats.c stats-mode.c \ diff --git a/src/build.c b/src/build.c index 9c3687c..3193884 100644 --- a/src/build.c +++ b/src/build.c @@ -224,3 +224,102 @@ void ct2msg(const struct nf_conntrack *ct, struct nethdr *n) if (nfct_attr_is_set_array(ct, nat_type, 6)) ct_build_natseqadj(ct, n); } + +static void +exp_build_l4proto_tcp(const struct nf_conntrack *ct, struct nethdr *n, int a) +{ + ct_build_group(ct, ATTR_GRP_ORIG_PORT, n, a, + sizeof(struct nfct_attr_grp_port)); +} + +static void +exp_build_l4proto_sctp(const struct nf_conntrack *ct, struct nethdr *n, int a) +{ + ct_build_group(ct, ATTR_GRP_ORIG_PORT, n, a, + sizeof(struct nfct_attr_grp_port)); +} + +static void +exp_build_l4proto_dccp(const struct nf_conntrack *ct, struct nethdr *n, int a) +{ + ct_build_group(ct, ATTR_GRP_ORIG_PORT, n, a, + sizeof(struct nfct_attr_grp_port)); +} + +static void +exp_build_l4proto_udp(const struct nf_conntrack *ct, struct nethdr *n, int a) +{ + ct_build_group(ct, ATTR_GRP_ORIG_PORT, n, a, + sizeof(struct nfct_attr_grp_port)); +} + +static struct exp_build_l4proto { + void (*build)(const struct nf_conntrack *, struct nethdr *n, int a); +} exp_l4proto_fcn[IPPROTO_MAX] = { + [IPPROTO_TCP] = { .build = exp_build_l4proto_tcp }, + [IPPROTO_SCTP] = { .build = exp_build_l4proto_sctp }, + [IPPROTO_DCCP] = { .build = exp_build_l4proto_dccp }, + [IPPROTO_UDP] = { .build = exp_build_l4proto_udp }, +}; + +static inline void +exp_build_u32(const struct nf_expect *exp, int a, struct nethdr *n, int b) +{ + uint32_t data = nfexp_get_attr_u32(exp, a); + data = htonl(data); + addattr(n, b, &data, sizeof(uint32_t)); +} + +void exp2msg(const struct nf_expect *exp, struct nethdr *n) +{ + const struct nf_conntrack *ct = nfexp_get_attr(exp, ATTR_EXP_MASTER); + uint8_t l4proto = nfct_get_attr_u8(ct, ATTR_L4PROTO); + + /* master conntrack for this expectation. */ + if (nfct_attr_grp_is_set(ct, ATTR_GRP_ORIG_IPV4)) { + ct_build_group(ct, ATTR_GRP_ORIG_IPV4, n, NTA_EXP_MASTER_IPV4, + sizeof(struct nfct_attr_grp_ipv4)); + } else if (nfct_attr_grp_is_set(ct, ATTR_GRP_ORIG_IPV6)) { + ct_build_group(ct, ATTR_GRP_ORIG_IPV6, n, NTA_EXP_MASTER_IPV6, + sizeof(struct nfct_attr_grp_ipv6)); + } + ct_build_u8(ct, ATTR_L4PROTO, n, NTA_EXP_MASTER_L4PROTO); + + if (exp_l4proto_fcn[l4proto].build) + exp_l4proto_fcn[l4proto].build(ct, n, NTA_EXP_MASTER_PORT); + + /* the expectation itself. */ + ct = nfexp_get_attr(exp, ATTR_EXP_EXPECTED); + + if (nfct_attr_grp_is_set(ct, ATTR_GRP_ORIG_IPV4)) { + ct_build_group(ct, ATTR_GRP_ORIG_IPV4, n, NTA_EXP_EXPECT_IPV4, + sizeof(struct nfct_attr_grp_ipv4)); + } else if (nfct_attr_grp_is_set(ct, ATTR_GRP_ORIG_IPV6)) { + ct_build_group(ct, ATTR_GRP_ORIG_IPV6, n, NTA_EXP_EXPECT_IPV6, + sizeof(struct nfct_attr_grp_ipv6)); + } + ct_build_u8(ct, ATTR_L4PROTO, n, NTA_EXP_EXPECT_L4PROTO); + + if (exp_l4proto_fcn[l4proto].build) + exp_l4proto_fcn[l4proto].build(ct, n, NTA_EXP_EXPECT_PORT); + + /* mask for the expectation. */ + ct = nfexp_get_attr(exp, ATTR_EXP_MASK); + + if (nfct_attr_grp_is_set(ct, ATTR_GRP_ORIG_IPV4)) { + ct_build_group(ct, ATTR_GRP_ORIG_IPV4, n, NTA_EXP_MASK_IPV4, + sizeof(struct nfct_attr_grp_ipv4)); + } else if (nfct_attr_grp_is_set(ct, ATTR_GRP_ORIG_IPV6)) { + ct_build_group(ct, ATTR_GRP_ORIG_IPV6, n, NTA_EXP_MASK_IPV6, + sizeof(struct nfct_attr_grp_ipv6)); + } + ct_build_u8(ct, ATTR_L4PROTO, n, NTA_EXP_MASK_L4PROTO); + + if (exp_l4proto_fcn[l4proto].build) + exp_l4proto_fcn[l4proto].build(ct, n, NTA_EXP_MASK_PORT); + + if (!CONFIG(commit_timeout) && nfexp_attr_is_set(exp, ATTR_EXP_TIMEOUT)) + exp_build_u32(exp, ATTR_EXP_TIMEOUT, n, NTA_EXP_TIMEOUT); + + exp_build_u32(exp, ATTR_EXP_FLAGS, n, NTA_EXP_FLAGS); +} diff --git a/src/cache-ct.c b/src/cache-ct.c index 2c6fd4e..0ad8d2a 100644 --- a/src/cache-ct.c +++ b/src/cache-ct.c @@ -251,7 +251,7 @@ static int cache_ct_commit(struct cache *c, struct nfct_handle *h, int clientfd) /* we already have one commit in progress, skip this. The clientfd * descriptor has to be closed by the caller. */ if (clientfd && STATE_SYNC(commit).clientfd != -1) - return 0; + return -1; switch(STATE_SYNC(commit).state) { case COMMIT_STATE_INACTIVE: @@ -308,9 +308,7 @@ static int cache_ct_commit(struct cache *c, struct nfct_handle *h, int clientfd) STATE_SYNC(commit).current = 0; STATE_SYNC(commit).state = COMMIT_STATE_INACTIVE; - /* Close the client socket now that we're done. */ - close(STATE_SYNC(commit).clientfd); - STATE_SYNC(commit).clientfd = -1; + return 0; } return 1; } diff --git a/src/cache-exp.c b/src/cache-exp.c new file mode 100644 index 0000000..e88877a --- /dev/null +++ b/src/cache-exp.c @@ -0,0 +1,308 @@ +/* + * (C) 2006-2011 by Pablo Neira Ayuso + * (C) 2011 by Vyatta Inc. + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "cache.h" +#include "hash.h" +#include "log.h" +#include "conntrackd.h" +#include "netlink.h" +#include "event.h" +#include "jhash.h" +#include "network.h" + +#include +#include +#include +#include + +static uint32_t +cache_hash4_exp(const struct nf_conntrack *ct, const struct hashtable *table) +{ + uint32_t a[4] = { + [0] = nfct_get_attr_u32(ct, ATTR_IPV4_SRC), + [1] = nfct_get_attr_u32(ct, ATTR_IPV4_DST), + [2] = nfct_get_attr_u8(ct, ATTR_L3PROTO) << 16 | + nfct_get_attr_u8(ct, ATTR_L4PROTO), + [3] = nfct_get_attr_u16(ct, ATTR_PORT_SRC) << 16 | + nfct_get_attr_u16(ct, ATTR_PORT_DST), + }; + + /* + * Instead of returning hash % table->hashsize (implying a divide) + * we return the high 32 bits of the (hash * table->hashsize) that will + * give results between [0 and hashsize-1] and same hash distribution, + * but using a multiply, less expensive than a divide. See: + * http://www.mail-archive.com/netdev@vger.kernel.org/msg56623.html + */ + return ((uint64_t)jhash2(a, 4, 0) * table->hashsize) >> 32; +} + +static uint32_t +cache_hash6_exp(const struct nf_conntrack *ct, const struct hashtable *table) +{ + uint32_t a[10]; + + memcpy(&a[0], nfct_get_attr(ct, ATTR_IPV6_SRC), sizeof(uint32_t)*4); + memcpy(&a[4], nfct_get_attr(ct, ATTR_IPV6_SRC), sizeof(uint32_t)*4); + a[8] = nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO) << 16 | + nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO); + a[9] = nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC) << 16 | + nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST); + + return ((uint64_t)jhash2(a, 10, 0) * table->hashsize) >> 32; +} + +static uint32_t +cache_exp_hash(const void *data, const struct hashtable *table) +{ + int ret = 0; + const struct nf_expect *exp = data; + const struct nf_conntrack *ct = nfexp_get_attr(exp, ATTR_EXP_MASTER); + + switch(nfct_get_attr_u8(ct, ATTR_L3PROTO)) { + case AF_INET: + ret = cache_hash4_exp(ct, table); + break; + case AF_INET6: + ret = cache_hash6_exp(ct, table); + break; + default: + dlog(LOG_ERR, "unknown layer 3 proto in hash"); + break; + } + return ret; +} + +static int cache_exp_cmp(const void *data1, const void *data2) +{ + const struct cache_object *obj = data1; + const struct nf_expect *exp = data2; + + return nfexp_cmp(obj->ptr, exp, 0); +} + +static void *cache_exp_alloc(void) +{ + return nfexp_new(); +} + +static void cache_exp_free(void *ptr) +{ + nfexp_destroy(ptr); +} + +static void cache_exp_copy(void *dst, void *src, unsigned int flags) +{ + /* XXX: add nfexp_copy(...) to libnetfilter_conntrack. */ + memcpy(dst, src, nfexp_maxsize()); +} + +static int cache_exp_dump_step(void *data1, void *n) +{ + char buf[1024]; + int size; + struct __dump_container *container = data1; + struct cache_object *obj = n; + char *data = obj->data; + unsigned i; + + /* + * XXX: Do not dump the entries that are scheduled to expire. + * These entries talk about already destroyed connections + * that we keep for some time just in case that we have to + * resent some lost messages. We do not show them to the + * user as he may think that the firewall replicas are not + * in sync. The branch below is a hack as it is quite + * specific and it breaks conntrackd modularity. Probably + * there's a nicer way to do this but until I come up with it... + */ + if (CONFIG(flags) & CTD_SYNC_FTFW && obj->status == C_OBJ_DEAD) + return 0; + + /* do not show cached timeout, this may confuse users */ + if (nfexp_attr_is_set(obj->ptr, ATTR_EXP_TIMEOUT)) + nfexp_attr_unset(obj->ptr, ATTR_EXP_TIMEOUT); + + memset(buf, 0, sizeof(buf)); + size = nfexp_snprintf(buf, sizeof(buf),obj->ptr, + NFCT_T_UNKNOWN, container->type, 0); + + for (i = 0; i < obj->cache->num_features; i++) { + if (obj->cache->features[i]->dump) { + size += obj->cache->features[i]->dump(obj, data, + buf+size, + container->type); + data += obj->cache->features[i]->size; + } + } + if (container->type != NFCT_O_XML) { + long tm = time(NULL); + size += sprintf(buf+size, " [active since %lds]", + tm - obj->lifetime); + } + size += sprintf(buf+size, "\n"); + if (send(container->fd, buf, size, 0) == -1) { + if (errno != EPIPE) + return -1; + } + + return 0; +} + +static int cache_exp_commit_step(void *data, void *n) +{ + struct cache_object *obj = n; + struct __commit_container *tmp = data; + int ret, retry = 1, timeout; + struct nf_expect *exp = obj->ptr; + + if (CONFIG(commit_timeout)) { + timeout = CONFIG(commit_timeout); + } else { + timeout = time(NULL) - obj->lastupdate; + if (timeout < 0) { + /* XXX: Arbitrarily set the timer to one minute, how + * can this happen? For example, an adjustment due to + * daylight-saving. Probably other situations can + * trigger this. */ + timeout = 60; + } + /* calculate an estimation of the current timeout */ + timeout = nfexp_get_attr_u32(exp, ATTR_EXP_TIMEOUT) - timeout; + if (timeout < 0) { + timeout = 60; + } + } + +retry: + if (nl_create_expect(tmp->h, exp, timeout) == -1) { + if (errno == EEXIST && retry == 1) { + ret = nl_destroy_expect(tmp->h, exp); + if (ret == 0 || (ret == -1 && errno == ENOENT)) { + if (retry) { + retry = 0; + goto retry; + } + } + dlog(LOG_ERR, "commit-destroy: %s", strerror(errno)); + dlog_exp(STATE(log), exp, NFCT_O_PLAIN); + tmp->c->stats.commit_fail++; + } else { + dlog(LOG_ERR, "commit-create: %s", strerror(errno)); + dlog_exp(STATE(log), exp, NFCT_O_PLAIN); + tmp->c->stats.commit_fail++; + } + } else { + tmp->c->stats.commit_ok++; + } + /* keep iterating even if we have found errors */ + return 0; +} + +static int +cache_exp_commit(struct cache *c, struct nfct_handle *h, int clientfd) +{ + unsigned int commit_ok, commit_fail; + struct timeval commit_stop, res; + struct __commit_container tmp = { + .h = h, + .c = c, + }; + + /* we already have one commit in progress, skip this. The clientfd + * descriptor has to be closed by the caller. */ + if (clientfd && STATE_SYNC(commit).clientfd != -1) + return -1; + + switch(STATE_SYNC(commit).state) { + case COMMIT_STATE_INACTIVE: + gettimeofday(&STATE_SYNC(commit).stats.start, NULL); + STATE_SYNC(commit).stats.ok = c->stats.commit_ok; + STATE_SYNC(commit).stats.fail = c->stats.commit_fail; + STATE_SYNC(commit).clientfd = clientfd; + case COMMIT_STATE_MASTER: + STATE_SYNC(commit).current = + hashtable_iterate_limit(c->h, &tmp, + STATE_SYNC(commit).current, + CONFIG(general).commit_steps, + cache_exp_commit_step); + if (STATE_SYNC(commit).current < CONFIG(hashsize)) { + STATE_SYNC(commit).state = COMMIT_STATE_MASTER; + /* give it another step as soon as possible */ + write_evfd(STATE_SYNC(commit).evfd); + return 1; + } + + /* calculate the time that commit has taken */ + gettimeofday(&commit_stop, NULL); + timersub(&commit_stop, &STATE_SYNC(commit).stats.start, &res); + + /* calculate new entries committed */ + commit_ok = c->stats.commit_ok - STATE_SYNC(commit).stats.ok; + commit_fail = + c->stats.commit_fail - STATE_SYNC(commit).stats.fail; + + /* log results */ + dlog(LOG_NOTICE, "Committed %u new expectations", commit_ok); + + if (commit_fail) + dlog(LOG_NOTICE, "%u expectations can't be " + "committed", commit_fail); + + dlog(LOG_NOTICE, "commit has taken %lu.%06lu seconds", + res.tv_sec, res.tv_usec); + + /* prepare the state machine for new commits */ + STATE_SYNC(commit).current = 0; + STATE_SYNC(commit).state = COMMIT_STATE_INACTIVE; + + return 0; + } + return 1; +} + +static struct nethdr * +cache_exp_build_msg(const struct cache_object *obj, int type) +{ + return BUILD_NETMSG_FROM_EXP(obj->ptr, type); +} + +/* template to cache expectations coming from the kernel. */ +struct cache_ops cache_sync_internal_exp_ops = { + .hash = cache_exp_hash, + .cmp = cache_exp_cmp, + .alloc = cache_exp_alloc, + .free = cache_exp_free, + .copy = cache_exp_copy, + .dump_step = cache_exp_dump_step, + .commit = NULL, + .build_msg = cache_exp_build_msg, +}; + +/* template to cache expectations coming from the network. */ +struct cache_ops cache_sync_external_exp_ops = { + .hash = cache_exp_hash, + .cmp = cache_exp_cmp, + .alloc = cache_exp_alloc, + .free = cache_exp_free, + .copy = cache_exp_copy, + .dump_step = cache_exp_dump_step, + .commit = cache_exp_commit, + .build_msg = NULL, +}; diff --git a/src/external_cache.c b/src/external_cache.c index 3f896a0..e290249 100644 --- a/src/external_cache.c +++ b/src/external_cache.c @@ -26,6 +26,7 @@ #include static struct cache *external; +static struct cache *external_exp; static int external_cache_init(void) { @@ -36,12 +37,21 @@ static int external_cache_init(void) dlog(LOG_ERR, "can't allocate memory for the external cache"); return -1; } + external_exp = cache_create("external", CACHE_T_EXP, + STATE_SYNC(sync)->external_cache_flags, + NULL, &cache_sync_external_exp_ops); + if (external_exp == NULL) { + dlog(LOG_ERR, "can't allocate memory for the external cache"); + return -1; + } + return 0; } static void external_cache_close(void) { cache_destroy(external); + cache_destroy(external_exp); } static void external_cache_ct_new(struct nf_conntrack *ct) @@ -109,6 +119,71 @@ static void external_cache_ct_stats_ext(int fd) cache_stats_extended(external, fd); } +static void external_cache_exp_new(struct nf_expect *exp) +{ + struct cache_object *obj; + int id; + + obj = cache_find(external_exp, exp, &id); + if (obj == NULL) { +retry: + obj = cache_object_new(external_exp, exp); + if (obj == NULL) + return; + + if (cache_add(external_exp, obj, id) == -1) { + cache_object_free(obj); + return; + } + } else { + cache_del(external_exp, obj); + cache_object_free(obj); + goto retry; + } +} + +static void external_cache_exp_upd(struct nf_expect *exp) +{ + cache_update_force(external_exp, exp); +} + +static void external_cache_exp_del(struct nf_expect *exp) +{ + struct cache_object *obj; + int id; + + obj = cache_find(external_exp, exp, &id); + if (obj) { + cache_del(external_exp, obj); + cache_object_free(obj); + } +} + +static void external_cache_exp_dump(int fd, int type) +{ + cache_dump(external_exp, fd, type); +} + +static int external_cache_exp_commit(struct nfct_handle *h, int fd) +{ + return cache_commit(external_exp, h, fd); +} + +static void external_cache_exp_flush(void) +{ + cache_flush(external_exp); +} + +static void external_cache_exp_stats(int fd) +{ + cache_stats(external_exp, fd); +} + +static void external_cache_exp_stats_ext(int fd) +{ + cache_stats_extended(external_exp, fd); +} + struct external_handler external_cache = { .init = external_cache_init, .close = external_cache_close, @@ -122,4 +197,14 @@ struct external_handler external_cache = { .stats = external_cache_ct_stats, .stats_ext = external_cache_ct_stats_ext, }, + .exp = { + .new = external_cache_exp_new, + .upd = external_cache_exp_upd, + .del = external_cache_exp_del, + .dump = external_cache_exp_dump, + .commit = external_cache_exp_commit, + .flush = external_cache_exp_flush, + .stats = external_cache_exp_stats, + .stats_ext = external_cache_exp_stats_ext, + }, }; diff --git a/src/external_inject.c b/src/external_inject.c index ba5f3d1..0ad3478 100644 --- a/src/external_inject.c +++ b/src/external_inject.c @@ -42,7 +42,7 @@ struct { static int external_inject_init(void) { /* handler to directly inject conntracks into kernel-space */ - inject = nfct_open(CONNTRACK, 0); + inject = nfct_open(CONFIG(netlink).subsys_id, 0); if (inject == NULL) { dlog(LOG_ERR, "can't open netlink handler: %s", strerror(errno)); @@ -175,6 +175,89 @@ static void external_inject_ct_stats(int fd) send(fd, buf, size, 0); } +struct { + uint32_t add_ok; + uint32_t add_fail; + uint32_t upd_ok; + uint32_t upd_fail; + uint32_t del_ok; + uint32_t del_fail; +} exp_external_inject_stat; + +static void external_inject_exp_new(struct nf_expect *exp) +{ + int ret, retry = 1; + +retry: + if (nl_create_expect(inject, exp, 0) == -1) { + /* if the state entry exists, we delete and try again */ + if (errno == EEXIST && retry == 1) { + ret = nl_destroy_expect(inject, exp); + if (ret == 0 || (ret == -1 && errno == ENOENT)) { + if (retry) { + retry = 0; + goto retry; + } + } + exp_external_inject_stat.add_fail++; + dlog(LOG_ERR, "inject-add1: %s", strerror(errno)); + dlog_exp(STATE(log), exp, NFCT_O_PLAIN); + return; + } + exp_external_inject_stat.add_fail++; + dlog(LOG_ERR, "inject-add2: %s", strerror(errno)); + dlog_exp(STATE(log), exp, NFCT_O_PLAIN); + } else { + exp_external_inject_stat.add_ok++; + } +} + +static void external_inject_exp_del(struct nf_expect *exp) +{ + if (nl_destroy_expect(inject, exp) == -1) { + if (errno != ENOENT) { + exp_external_inject_stat.del_fail++; + dlog(LOG_ERR, "inject-del: %s", strerror(errno)); + dlog_exp(STATE(log), exp, NFCT_O_PLAIN); + } + } else { + exp_external_inject_stat.del_ok++; + } +} + +static void external_inject_exp_dump(int fd, int type) +{ +} + +static int external_inject_exp_commit(struct nfct_handle *h, int fd) +{ + /* close the commit socket. */ + return LOCAL_RET_OK; +} + +static void external_inject_exp_flush(void) +{ +} + +static void external_inject_exp_stats(int fd) +{ + char buf[512]; + int size; + + size = sprintf(buf, "external inject:\n" + "connections created:\t\t%12u\tfailed:\t%12u\n" + "connections updated:\t\t%12u\tfailed:\t%12u\n" + "connections destroyed:\t\t%12u\tfailed:\t%12u\n\n", + exp_external_inject_stat.add_ok, + exp_external_inject_stat.add_fail, + exp_external_inject_stat.upd_ok, + exp_external_inject_stat.upd_fail, + exp_external_inject_stat.del_ok, + exp_external_inject_stat.del_fail); + + send(fd, buf, size, 0); +} + struct external_handler external_inject = { .init = external_inject_init, .close = external_inject_close, @@ -188,4 +271,14 @@ struct external_handler external_inject = { .stats = external_inject_ct_stats, .stats_ext = external_inject_ct_stats, }, + .exp = { + .new = external_inject_exp_new, + .upd = external_inject_exp_new, + .del = external_inject_exp_del, + .dump = external_inject_exp_dump, + .commit = external_inject_exp_commit, + .flush = external_inject_exp_flush, + .stats = external_inject_exp_stats, + .stats_ext = external_inject_exp_stats, + }, }; diff --git a/src/filter.c b/src/filter.c index 746a9bb..e8515d6 100644 --- a/src/filter.c +++ b/src/filter.c @@ -405,3 +405,79 @@ int ct_filter_conntrack(const struct nf_conntrack *ct, int userspace) return 0; } + +struct exp_filter { + struct list_head list; +}; + +struct exp_filter *exp_filter_create(void) +{ + struct exp_filter *f; + + f = calloc(1, sizeof(struct exp_filter)); + if (f == NULL) + return NULL; + + INIT_LIST_HEAD(&f->list); + return f; +} + +struct exp_filter_item { + struct list_head head; + char helper_name[NFCT_HELPER_NAME_MAX]; +}; + +/* this is ugly, but it simplifies read_config_yy.y */ +static struct exp_filter *exp_filter_alloc(void) +{ + if (STATE(exp_filter) == NULL) { + STATE(exp_filter) = exp_filter_create(); + if (STATE(exp_filter) == NULL) { + fprintf(stderr, "Can't init expectation filtering!\n"); + return NULL; + } + } + return STATE(exp_filter);; +} + +int exp_filter_add(struct exp_filter *f, const char *helper_name) +{ + struct exp_filter_item *item; + + f = exp_filter_alloc(); + if (f == NULL) + return -1; + + list_for_each_entry(item, &f->list, head) { + if (strncmp(item->helper_name, helper_name, + NFCT_HELPER_NAME_MAX) == 0) { + return -1; + } + } + item = calloc(1, sizeof(struct exp_filter_item)); + if (item == NULL) + return -1; + + strncpy(item->helper_name, helper_name, NFCT_HELPER_NAME_MAX); + list_add(&item->head, &f->list); + return 0; +} + +int exp_filter_find(struct exp_filter *f, const struct nf_expect *exp) +{ + struct exp_filter_item *item; + + if (f == NULL) + return 0; + + list_for_each_entry(item, &f->list, head) { + const char *name = nfexp_get_attr(exp, ATTR_EXP_HELPER_NAME); + + /* we allow partial matching to support things like sip-PORT. */ + if (strncmp(item->helper_name, name, + strlen(item->helper_name)) == 0) { + return 1; + } + } + return 0; +} diff --git a/src/internal_bypass.c b/src/internal_bypass.c index 98717f3..5c83c21 100644 --- a/src/internal_bypass.c +++ b/src/internal_bypass.c @@ -52,7 +52,7 @@ static void internal_bypass_ct_dump(int fd, int type) u_int32_t family = AF_UNSPEC; int ret; - h = nfct_open(CONNTRACK, 0); + h = nfct_open(CONFIG(netlink).subsys_id, 0); if (h == NULL) { dlog(LOG_ERR, "can't allocate memory for the internal cache"); return; @@ -151,6 +151,138 @@ static int internal_bypass_ct_event_del(struct nf_conntrack *ct, int origin) return 1; } +static int +internal_bypass_exp_dump_cb(enum nf_conntrack_msg_type type, + struct nf_expect *exp, void *data) +{ + char buf[1024]; + int size, *fd = data; + const struct nf_conntrack *master = + nfexp_get_attr(exp, ATTR_EXP_MASTER); + + if (!exp_filter_find(STATE(exp_filter), exp)) + return NFCT_CB_CONTINUE; + + if (ct_filter_conntrack(master, 1)) + return NFCT_CB_CONTINUE; + + size = nfexp_snprintf(buf, 1024, exp, + NFCT_T_UNKNOWN, NFCT_O_DEFAULT, 0); + if (size < 1024) { + buf[size] = '\n'; + size++; + } + send(*fd, buf, size, 0); + + return NFCT_CB_CONTINUE; +} + +static void internal_bypass_exp_dump(int fd, int type) +{ + struct nfct_handle *h; + u_int32_t family = AF_UNSPEC; + int ret; + + h = nfct_open(CONFIG(netlink).subsys_id, 0); + if (h == NULL) { + dlog(LOG_ERR, "can't allocate memory for the internal cache"); + return; + } + nfexp_callback_register(h, NFCT_T_ALL, + internal_bypass_exp_dump_cb, &fd); + ret = nfexp_query(h, NFCT_Q_DUMP, &family); + if (ret == -1) { + dlog(LOG_ERR, "can't dump kernel table"); + } + nfct_close(h); +} + +static void internal_bypass_exp_flush(void) +{ + nl_flush_expect_table(STATE(flush)); +} + +struct { + uint32_t new; + uint32_t upd; + uint32_t del; +} exp_internal_bypass_stats; + +static void internal_bypass_exp_stats(int fd) +{ + char buf[512]; + int size; + + size = sprintf(buf, "internal bypass:\n" + "connections new:\t\t%12u\n" + "connections updated:\t\t%12u\n" + "connections destroyed:\t\t%12u\n\n", + exp_internal_bypass_stats.new, + exp_internal_bypass_stats.upd, + exp_internal_bypass_stats.del); + + send(fd, buf, size, 0); +} + +/* unused, INTERNAL_F_POPULATE is unset. No cache, nothing to populate. */ +static void internal_bypass_exp_populate(struct nf_expect *exp) +{ +} + +/* unused, INTERNAL_F_RESYNC is unset. */ +static void internal_bypass_exp_purge(void) +{ +} + +/* unused, INTERNAL_F_RESYNC is unset. Nothing to resync, we have no cache. */ +static int +internal_bypass_exp_resync(enum nf_conntrack_msg_type type, + struct nf_expect *exp, void *data) +{ + return NFCT_CB_CONTINUE; +} + +static void internal_bypass_exp_event_new(struct nf_expect *exp, int origin) +{ + struct nethdr *net; + + /* this event has been triggered by me, skip */ + if (origin != CTD_ORIGIN_NOT_ME) + return; + + net = BUILD_NETMSG_FROM_EXP(exp, NET_T_STATE_EXP_NEW); + multichannel_send(STATE_SYNC(channel), net); + exp_internal_bypass_stats.new++; +} + +static void internal_bypass_exp_event_upd(struct nf_expect *exp, int origin) +{ + struct nethdr *net; + + /* this event has been triggered by me, skip */ + if (origin != CTD_ORIGIN_NOT_ME) + return; + + net = BUILD_NETMSG_FROM_EXP(exp, NET_T_STATE_EXP_UPD); + multichannel_send(STATE_SYNC(channel), net); + exp_internal_bypass_stats.upd++; +} + +static int internal_bypass_exp_event_del(struct nf_expect *exp, int origin) +{ + struct nethdr *net; + + /* this event has been triggered by me, skip */ + if (origin != CTD_ORIGIN_NOT_ME) + return 1; + + net = BUILD_NETMSG_FROM_EXP(exp, NET_T_STATE_EXP_DEL); + multichannel_send(STATE_SYNC(channel), net); + exp_internal_bypass_stats.del++; + + return 1; +} + struct internal_handler internal_bypass = { .init = internal_bypass_init, .close = internal_bypass_close, @@ -166,4 +298,16 @@ struct internal_handler internal_bypass = { .upd = internal_bypass_ct_event_upd, .del = internal_bypass_ct_event_del, }, + .exp = { + .dump = internal_bypass_exp_dump, + .flush = internal_bypass_exp_flush, + .stats = internal_bypass_exp_stats, + .stats_ext = internal_bypass_exp_stats, + .populate = internal_bypass_exp_populate, + .purge = internal_bypass_exp_purge, + .resync = internal_bypass_exp_resync, + .new = internal_bypass_exp_event_new, + .upd = internal_bypass_exp_event_upd, + .del = internal_bypass_exp_event_del, + }, }; diff --git a/src/internal_cache.c b/src/internal_cache.c index 952327d..ba2d74b 100644 --- a/src/internal_cache.c +++ b/src/internal_cache.c @@ -32,12 +32,25 @@ static int internal_cache_init(void) dlog(LOG_ERR, "can't allocate memory for the internal cache"); return -1; } + + STATE(mode)->internal->exp.data = + cache_create("internal", CACHE_T_EXP, + STATE_SYNC(sync)->internal_cache_flags, + STATE_SYNC(sync)->internal_cache_extra, + &cache_sync_internal_exp_ops); + + if (!STATE(mode)->internal->exp.data) { + dlog(LOG_ERR, "can't allocate memory for the internal cache"); + return -1; + } + return 0; } static void internal_cache_close(void) { cache_destroy(STATE(mode)->internal->ct.data); + cache_destroy(STATE(mode)->internal->exp.data); } static void internal_cache_ct_dump(int fd, int type) @@ -203,6 +216,154 @@ static int internal_cache_ct_event_del(struct nf_conntrack *ct, int origin) return 1; } +static void internal_cache_exp_dump(int fd, int type) +{ + cache_dump(STATE(mode)->internal->exp.data, fd, type); +} + +static void internal_cache_exp_flush(void) +{ + cache_flush(STATE(mode)->internal->exp.data); +} + +static void internal_cache_exp_stats(int fd) +{ + cache_stats(STATE(mode)->internal->exp.data, fd); +} + +static void internal_cache_exp_stats_ext(int fd) +{ + cache_stats_extended(STATE(mode)->internal->exp.data, fd); +} + +static void internal_cache_exp_populate(struct nf_expect *exp) +{ + cache_update_force(STATE(mode)->internal->exp.data, exp); +} + +static int internal_cache_exp_purge_step(void *data1, void *data2) +{ + struct cache_object *obj = data2; + + STATE(get_retval) = 0; + nl_get_expect(STATE(get), obj->ptr); /* modifies STATE(get_reval) */ + if (!STATE(get_retval)) { + if (obj->status != C_OBJ_DEAD) { + cache_object_set_status(obj, C_OBJ_DEAD); + sync_send(obj, NET_T_STATE_EXP_DEL); + cache_object_put(obj); + } + } + + return 0; +} + +static void internal_cache_exp_purge(void) +{ + cache_iterate(STATE(mode)->internal->exp.data, NULL, + internal_cache_exp_purge_step); +} + +static int +internal_cache_exp_resync(enum nf_conntrack_msg_type type, + struct nf_expect *exp, void *data) +{ + struct cache_object *obj; + const struct nf_conntrack *master = + nfexp_get_attr(exp, ATTR_EXP_MASTER); + + if (!exp_filter_find(STATE(exp_filter), exp)) + return NFCT_CB_CONTINUE; + + if (ct_filter_conntrack(master, 1)) + return NFCT_CB_CONTINUE; + + obj = cache_update_force(STATE(mode)->internal->exp.data, exp); + if (obj == NULL) + return NFCT_CB_CONTINUE; + + switch (obj->status) { + case C_OBJ_NEW: + sync_send(obj, NET_T_STATE_EXP_NEW); + break; + case C_OBJ_ALIVE: + sync_send(obj, NET_T_STATE_EXP_UPD); + break; + } + return NFCT_CB_CONTINUE; +} + +static void internal_cache_exp_event_new(struct nf_expect *exp, int origin) +{ + struct cache_object *obj; + int id; + + /* this event has been triggered by a direct inject, skip */ + if (origin == CTD_ORIGIN_INJECT) + return; + + obj = cache_find(STATE(mode)->internal->exp.data, exp, &id); + if (obj == NULL) { +retry: + obj = cache_object_new(STATE(mode)->internal->exp.data, exp); + if (obj == NULL) + return; + if (cache_add(STATE(mode)->internal->exp.data, obj, id) == -1) { + cache_object_free(obj); + return; + } + /* only synchronize events that have been triggered by other + * processes or the kernel, but don't propagate events that + * have been triggered by conntrackd itself, eg. commits. */ + if (origin == CTD_ORIGIN_NOT_ME) + sync_send(obj, NET_T_STATE_EXP_NEW); + } else { + cache_del(STATE(mode)->internal->exp.data, obj); + cache_object_free(obj); + goto retry; + } +} + +static void internal_cache_exp_event_upd(struct nf_expect *exp, int origin) +{ + struct cache_object *obj; + + /* this event has been triggered by a direct inject, skip */ + if (origin == CTD_ORIGIN_INJECT) + return; + + obj = cache_update_force(STATE(mode)->internal->exp.data, exp); + if (obj == NULL) + return; + + if (origin == CTD_ORIGIN_NOT_ME) + sync_send(obj, NET_T_STATE_EXP_UPD); +} + +static int internal_cache_exp_event_del(struct nf_expect *exp, int origin) +{ + struct cache_object *obj; + int id; + + /* this event has been triggered by a direct inject, skip */ + if (origin == CTD_ORIGIN_INJECT) + return 0; + + /* we don't synchronize events for objects that are not in the cache */ + obj = cache_find(STATE(mode)->internal->exp.data, exp, &id); + if (obj == NULL) + return 0; + + if (obj->status != C_OBJ_DEAD) { + cache_object_set_status(obj, C_OBJ_DEAD); + if (origin == CTD_ORIGIN_NOT_ME) { + sync_send(obj, NET_T_STATE_EXP_DEL); + } + cache_object_put(obj); + } + return 1; +} + struct internal_handler internal_cache = { .flags = INTERNAL_F_POPULATE | INTERNAL_F_RESYNC, .init = internal_cache_init, @@ -219,4 +380,16 @@ struct internal_handler internal_cache = { .upd = internal_cache_ct_event_upd, .del = internal_cache_ct_event_del, }, + .exp = { + .dump = internal_cache_exp_dump, + .flush = internal_cache_exp_flush, + .stats = internal_cache_exp_stats, + .stats_ext = internal_cache_exp_stats_ext, + .populate = internal_cache_exp_populate, + .purge = internal_cache_exp_purge, + .resync = internal_cache_exp_resync, + .new = internal_cache_exp_event_new, + .upd = internal_cache_exp_event_upd, + .del = internal_cache_exp_event_del, + }, }; diff --git a/src/log.c b/src/log.c index 9fe5119..d4de111 100644 --- a/src/log.c +++ b/src/log.c @@ -145,6 +145,43 @@ void dlog_ct(FILE *fd, struct nf_conntrack *ct, unsigned int type) } } +void dlog_exp(FILE *fd, struct nf_expect *exp, unsigned int type) +{ + time_t t; + char buf[1024]; + char *tmp; + unsigned int flags = 0; + + buf[0]='\0'; + + switch(type) { + case NFCT_O_PLAIN: + t = time(NULL); + ctime_r(&t, buf); + tmp = buf + strlen(buf); + buf[strlen(buf)-1]='\t'; + break; + default: + return; + } + nfexp_snprintf(buf+strlen(buf), 1024-strlen(buf), exp, 0, type, flags); + + if (fd) { + snprintf(buf+strlen(buf), 1024-strlen(buf), "\n"); + fputs(buf, fd); + } + + if (fd == STATE(log)) { + /* error reporting */ + if (CONFIG(syslog_facility) != -1) + syslog(LOG_ERR, "%s", tmp); + } else if (fd == STATE(stats_log)) { + /* connection logging */ + if (CONFIG(stats).syslog_facility != -1) + syslog(LOG_INFO, "%s", tmp); + } +} + void close_log(void) { if (STATE(log) != NULL) diff --git a/src/main.c b/src/main.c index ebfc8b9..342ed45 100644 --- a/src/main.c +++ b/src/main.c @@ -1,5 +1,6 @@ /* - * (C) 2006-2007 by Pablo Neira Ayuso + * (C) 2006-2011 by Pablo Neira Ayuso + * (C) 2011 by Vyatta Inc. * * 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 @@ -38,14 +39,15 @@ static const char usage_daemon_commands[] = static const char usage_client_commands[] = "Client mode commands:\n" - " -c, commit external cache to conntrack table\n" + " -c [ct|expect], commit external cache to conntrack table\n" " -f [|internal|external], flush internal and external cache\n" - " -F, flush kernel conntrack table\n" - " -i, display content of the internal cache\n" - " -e, display the content of the external cache\n" + " -F [ct|expect], flush kernel conntrack table\n" + " -i [ct|expect], display content of the internal cache\n" + " -e [ct|expect], display the content of the external cache\n" " -k, kill conntrack daemon\n" - " -s [|network|cache|runtime|link|rsqueue|queue], dump statistics\n" - " -R, resync with kernel conntrack table\n" + " -s [|network|cache|runtime|link|rsqueue|queue|ct|expect], " + "dump statistics\n" + " -R [ct|expect], resync with kernel conntrack table\n" " -n, request resync with other node (only FT-FW and NOTRACK modes)\n" " -x, dump cache in XML format (requires -i or -e)\n" " -t, reset the kernel timeout (see PurgeTimeout clause)\n" @@ -89,6 +91,25 @@ set_operation_mode(int *current, int want, char *argv[]) } } +static int +set_action_by_table(int i, int argc, char *argv[], + int ct_action, int exp_action, int dfl_action, int *action) +{ + if (i+1 < argc && argv[i+1][0] != '-') { + if (strncmp(argv[i+1], "ct", strlen(argv[i+1])) == 0) { + *action = ct_action; + i++; + } else if (strncmp(argv[i+1], "expect", + strlen(argv[i+1])) == 0) { + *action = exp_action; + i++; + } + } else + *action = dfl_action; + + return i; +} + int main(int argc, char *argv[]) { int ret, i, action = -1; @@ -115,15 +136,23 @@ int main(int argc, char *argv[]) break; case 'c': set_operation_mode(&type, REQUEST, argv); - action = CT_COMMIT; + i = set_action_by_table(i, argc, argv, + CT_COMMIT, EXP_COMMIT, + ALL_COMMIT, &action); break; case 'i': set_operation_mode(&type, REQUEST, argv); - action = CT_DUMP_INTERNAL; + i = set_action_by_table(i, argc, argv, + CT_DUMP_INTERNAL, + EXP_DUMP_INTERNAL, + CT_DUMP_INTERNAL, &action); break; case 'e': set_operation_mode(&type, REQUEST, argv); - action = CT_DUMP_EXTERNAL; + i = set_action_by_table(i, argc, argv, + CT_DUMP_EXTERNAL, + EXP_DUMP_EXTERNAL, + CT_DUMP_EXTERNAL, &action); break; case 'C': if (++i < argc) { @@ -142,7 +171,10 @@ int main(int argc, char *argv[]) break; case 'F': set_operation_mode(&type, REQUEST, argv); - action = CT_FLUSH_MASTER; + i = set_action_by_table(i, argc, argv, + CT_FLUSH_MASTER, + EXP_FLUSH_MASTER, + ALL_FLUSH_MASTER, &action); break; case 'f': set_operation_mode(&type, REQUEST, argv); @@ -164,12 +196,15 @@ int main(int argc, char *argv[]) } } else { /* default to general flushing */ - action = CT_FLUSH_CACHE; + action = ALL_FLUSH_CACHE; } break; case 'R': set_operation_mode(&type, REQUEST, argv); - action = CT_RESYNC_MASTER; + i = set_action_by_table(i, argc, argv, + CT_RESYNC_MASTER, + EXP_RESYNC_MASTER, + ALL_RESYNC_MASTER, &action); break; case 'B': set_operation_mode(&type, REQUEST, argv); @@ -222,6 +257,14 @@ int main(int argc, char *argv[]) strlen(argv[i+1])) == 0) { action = STATS_QUEUE; i++; + } else if (strncmp(argv[i+1], "ct", + strlen(argv[i+1])) == 0) { + action = STATS; + i++; + } else if (strncmp(argv[i+1], "expect", + strlen(argv[i+1])) == 0) { + action = EXP_STATS; + i++; } else { fprintf(stderr, "ERROR: unknown " "parameter `%s' for " diff --git a/src/netlink.c b/src/netlink.c index 60274f3..fe979e3 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -1,5 +1,6 @@ /* - * (C) 2006 by Pablo Neira Ayuso + * (C) 2006-2011 by Pablo Neira Ayuso + * (C) 2011 by Vyatta Inc. * * 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 @@ -32,7 +33,7 @@ struct nfct_handle *nl_init_event_handler(void) { struct nfct_handle *h; - h = nfct_open(CONNTRACK, NFCT_ALL_CT_GROUPS); + h = nfct_open(CONFIG(netlink).subsys_id, CONFIG(netlink).groups); if (h == NULL) return NULL; @@ -301,3 +302,61 @@ int nl_destroy_conntrack(struct nfct_handle *h, const struct nf_conntrack *ct) { return nfct_query(h, NFCT_Q_DESTROY, ct); } + +int nl_create_expect(struct nfct_handle *h, const struct nf_expect *orig, + int timeout) +{ + int ret; + struct nf_expect *exp; + + exp = nfexp_clone(orig); + if (exp == NULL) + return -1; + + if (timeout > 0) + nfexp_set_attr_u32(exp, ATTR_EXP_TIMEOUT, timeout); + + ret = nfexp_query(h, NFCT_Q_CREATE, exp); + nfexp_destroy(exp); + + return ret; +} + +int nl_destroy_expect(struct nfct_handle *h, const struct nf_expect *exp) +{ + return nfexp_query(h, NFCT_Q_DESTROY, exp); +} + +/* if the handle has no callback, check for existence, otherwise, update */ +int nl_get_expect(struct nfct_handle *h, const struct nf_expect *exp) +{ + int ret = 1; + struct nf_expect *tmp; + + /* XXX: we only need the expectation, not the mask and the master. */ + tmp = nfexp_clone(exp); + if (tmp == NULL) + return -1; + + if (nfexp_query(h, NFCT_Q_GET, tmp) == -1) + ret = (errno == ENOENT) ? 0 : -1; + + nfexp_destroy(tmp); + return ret; +} + +int nl_dump_expect_table(struct nfct_handle *h) +{ + return nfexp_query(h, NFCT_Q_DUMP, &CONFIG(family)); +} + +int nl_flush_expect_table(struct nfct_handle *h) +{ + return nfexp_query(h, NFCT_Q_FLUSH, &CONFIG(family)); +} + +int nl_send_expect_resync(struct nfct_handle *h) +{ + int family = CONFIG(family); + return nfexp_send(h, NFCT_Q_DUMP, &family); +} diff --git a/src/network.c b/src/network.c index cadc466..13db37c 100644 --- a/src/network.c +++ b/src/network.c @@ -126,6 +126,11 @@ static int status2type[CACHE_T_MAX][C_OBJ_MAX] = { [C_OBJ_ALIVE] = NET_T_STATE_CT_UPD, [C_OBJ_DEAD] = NET_T_STATE_CT_DEL, }, + [CACHE_T_EXP] = { + [C_OBJ_NEW] = NET_T_STATE_EXP_NEW, + [C_OBJ_ALIVE] = NET_T_STATE_EXP_UPD, + [C_OBJ_DEAD] = NET_T_STATE_EXP_DEL, + }, }; int object_status_to_network_type(struct cache_object *obj) diff --git a/src/parse.c b/src/parse.c index 0718128..81e9c6b 100644 --- a/src/parse.c +++ b/src/parse.c @@ -248,3 +248,195 @@ int msg2ct(struct nf_conntrack *ct, struct nethdr *net, size_t remain) return 0; } + +static void exp_parse_ct_group(void *ct, int attr, void *data); +static void exp_parse_ct_u8(void *ct, int attr, void *data); +static void exp_parse_u32(void *exp, int attr, void *data); + +static struct exp_parser { + void (*parse)(void *obj, int attr, void *data); + int exp_attr; + int ct_attr; + int size; +} exp_h[NTA_EXP_MAX] = { + [NTA_EXP_MASTER_IPV4] = { + .parse = exp_parse_ct_group, + .exp_attr = ATTR_EXP_MASTER, + .ct_attr = ATTR_GRP_ORIG_IPV4, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_ipv4)), + }, + [NTA_EXP_MASTER_IPV6] = { + .parse = exp_parse_ct_group, + .exp_attr = ATTR_EXP_MASTER, + .ct_attr = ATTR_GRP_ORIG_IPV6, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_ipv6)), + }, + [NTA_EXP_MASTER_L4PROTO] = { + .parse = exp_parse_ct_u8, + .exp_attr = ATTR_EXP_MASTER, + .ct_attr = ATTR_L4PROTO, + .size = NTA_SIZE(sizeof(uint8_t)), + }, + [NTA_EXP_MASTER_PORT] = { + .parse = exp_parse_ct_group, + .exp_attr = ATTR_EXP_MASTER, + .ct_attr = ATTR_GRP_ORIG_PORT, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_port)), + }, + [NTA_EXP_EXPECT_IPV4] = { + .parse = exp_parse_ct_group, + .exp_attr = ATTR_EXP_EXPECTED, + .ct_attr = ATTR_GRP_ORIG_IPV4, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_ipv4)), + }, + [NTA_EXP_EXPECT_IPV6] = { + .parse = exp_parse_ct_group, + .exp_attr = ATTR_EXP_EXPECTED, + .ct_attr = ATTR_GRP_ORIG_IPV6, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_ipv6)), + }, + [NTA_EXP_EXPECT_L4PROTO] = { + .parse = exp_parse_ct_u8, + .exp_attr = ATTR_EXP_EXPECTED, + .ct_attr = ATTR_L4PROTO, + .size = NTA_SIZE(sizeof(uint8_t)), + }, + [NTA_EXP_EXPECT_PORT] = { + .parse = exp_parse_ct_group, + .exp_attr = ATTR_EXP_EXPECTED, + .ct_attr = ATTR_GRP_ORIG_PORT, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_port)), + }, + [NTA_EXP_MASK_IPV4] = { + .parse = exp_parse_ct_group, + .exp_attr = ATTR_EXP_MASK, + .ct_attr = ATTR_GRP_ORIG_IPV4, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_ipv4)), + }, + [NTA_EXP_MASK_IPV6] = { + .parse = exp_parse_ct_group, + .exp_attr = ATTR_EXP_MASK, + .ct_attr = ATTR_GRP_ORIG_IPV6, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_ipv6)), + }, + [NTA_EXP_MASK_L4PROTO] = { + .parse = exp_parse_ct_u8, + .exp_attr = ATTR_EXP_MASK, + .ct_attr = ATTR_L4PROTO, + .size = NTA_SIZE(sizeof(uint8_t)), + }, + [NTA_EXP_MASK_PORT] = { + .parse = exp_parse_ct_group, + .exp_attr = ATTR_EXP_MASK, + .ct_attr = ATTR_GRP_ORIG_PORT, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_port)), + }, + [NTA_EXP_TIMEOUT] = { + .parse = exp_parse_u32, + .exp_attr = ATTR_EXP_TIMEOUT, + .size = NTA_SIZE(sizeof(uint32_t)), + }, + [NTA_EXP_FLAGS] = { + .parse = exp_parse_u32, + .exp_attr = ATTR_EXP_FLAGS, + .size = NTA_SIZE(sizeof(uint32_t)), + }, +}; + +static void exp_parse_ct_group(void *ct, int attr, void *data) +{ + nfct_set_attr_grp(ct, exp_h[attr].ct_attr, data); +} + +static void exp_parse_ct_u8(void *ct, int attr, void *data) +{ + uint8_t *value = (uint8_t *) data; + nfct_set_attr_u8(ct, exp_h[attr].ct_attr, *value); +} + +static void exp_parse_u32(void *exp, int attr, void *data) +{ + uint32_t *value = (uint32_t *) data; + nfexp_set_attr_u32(exp, exp_h[attr].exp_attr, ntohl(*value)); +} + +int msg2exp(struct nf_expect *exp, struct nethdr *net, size_t remain) +{ + int len; + struct netattr *attr; + struct nf_conntrack *master, *expected, *mask; + + if (remain < net->len) + return -1; + + len = net->len - NETHDR_SIZ; + attr = NETHDR_DATA(net); + + master = nfct_new(); + if (master == NULL) + goto err_master; + + expected = nfct_new(); + if (expected == NULL) + goto err_expected; + + mask = nfct_new(); + if (mask == NULL) + goto err_mask; + + while (len > ssizeof(struct netattr)) { + ATTR_NETWORK2HOST(attr); + if (attr->nta_len > len) + goto err; + if (attr->nta_attr > NTA_MAX) + goto err; + if (attr->nta_len != exp_h[attr->nta_attr].size) + goto err; + if (exp_h[attr->nta_attr].parse == NULL) { + attr = NTA_NEXT(attr, len); + continue; + } + switch(exp_h[attr->nta_attr].exp_attr) { + case ATTR_EXP_MASTER: + exp_h[attr->nta_attr].parse(master, attr->nta_attr, + NTA_DATA(attr)); + case ATTR_EXP_EXPECTED: + exp_h[attr->nta_attr].parse(expected, attr->nta_attr, + NTA_DATA(attr)); + case ATTR_EXP_MASK: + exp_h[attr->nta_attr].parse(mask, attr->nta_attr, + NTA_DATA(attr)); + break; + case ATTR_EXP_TIMEOUT: + case ATTR_EXP_FLAGS: + exp_h[attr->nta_attr].parse(exp, attr->nta_attr, + NTA_DATA(attr)); + break; + } + attr = NTA_NEXT(attr, len); + } + + nfexp_set_attr(exp, ATTR_EXP_MASTER, master); + nfexp_set_attr(exp, ATTR_EXP_EXPECTED, expected); + nfexp_set_attr(exp, ATTR_EXP_MASK, mask); + + /* We can release the conntrack objects at this point because the + * setter makes a copy of them. This is not efficient, it would be + * better to save that extra copy but this is how the library works. + * I'm sorry, I cannot change it without breaking backward + * compatibility. Probably it is a good idea to think of adding new + * interfaces in the near future to get it better. */ + nfct_destroy(mask); + nfct_destroy(expected); + nfct_destroy(master); + + return 0; +err: + nfct_destroy(mask); +err_mask: + nfct_destroy(expected); +err_expected: + nfct_destroy(master); +err_master: + return -1; +} diff --git a/src/read_config_lex.l b/src/read_config_lex.l index be6bf8b..01fe4fc 100644 --- a/src/read_config_lex.l +++ b/src/read_config_lex.l @@ -140,6 +140,7 @@ notrack [N|n][O|o][T|t][R|r][A|a][C|c][K|k] "DisableExternalCache" { return T_DISABLE_EXTERNAL_CACHE; } "Options" { return T_OPTIONS; } "TCPWindowTracking" { return T_TCP_WINDOW_TRACKING; } +"ExpectationSync" { return T_EXPECT_SYNC; } "ErrorQueueLength" { return T_ERROR_QUEUE_LENGTH; } {is_on} { return T_ON; } diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 68a83f7..b22784c 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -73,7 +73,7 @@ static void __max_dedicated_links_reached(void); %token T_NETLINK_OVERRUN_RESYNC T_NICE T_IPV4_DEST_ADDR T_IPV6_DEST_ADDR %token T_SCHEDULER T_TYPE T_PRIO T_NETLINK_EVENTS_RELIABLE %token T_DISABLE_INTERNAL_CACHE T_DISABLE_EXTERNAL_CACHE T_ERROR_QUEUE_LENGTH -%token T_OPTIONS T_TCP_WINDOW_TRACKING +%token T_OPTIONS T_TCP_WINDOW_TRACKING T_EXPECT_SYNC %token T_IP T_PATH_VAL %token T_NUMBER @@ -828,6 +828,46 @@ option: T_TCP_WINDOW_TRACKING T_OFF CONFIG(sync).tcp_window_tracking = 0; }; +option: T_EXPECT_SYNC T_ON +{ + CONFIG(flags) |= CTD_EXPECT; + CONFIG(netlink).subsys_id = NFNL_SUBSYS_NONE; + CONFIG(netlink).groups = NF_NETLINK_CONNTRACK_NEW | + NF_NETLINK_CONNTRACK_UPDATE | + NF_NETLINK_CONNTRACK_DESTROY | + NF_NETLINK_CONNTRACK_EXP_NEW | + NF_NETLINK_CONNTRACK_EXP_UPDATE | + NF_NETLINK_CONNTRACK_EXP_DESTROY; +}; + +option: T_EXPECT_SYNC T_OFF +{ + CONFIG(netlink).subsys_id = NFNL_SUBSYS_CTNETLINK; + CONFIG(netlink).groups = NF_NETLINK_CONNTRACK_NEW | + NF_NETLINK_CONNTRACK_UPDATE | + NF_NETLINK_CONNTRACK_DESTROY; +}; + +option: T_EXPECT_SYNC '{' expect_list '}' +{ + CONFIG(flags) |= CTD_EXPECT; + CONFIG(netlink).subsys_id = NFNL_SUBSYS_NONE; + CONFIG(netlink).groups = NF_NETLINK_CONNTRACK_NEW | + NF_NETLINK_CONNTRACK_UPDATE | + NF_NETLINK_CONNTRACK_DESTROY | + NF_NETLINK_CONNTRACK_EXP_NEW | + NF_NETLINK_CONNTRACK_EXP_UPDATE | + NF_NETLINK_CONNTRACK_EXP_DESTROY; +}; + +expect_list: + | expect_list expect_item ; + +expect_item: T_STRING +{ + exp_filter_add(STATE(exp_filter), $1); +} + sync_mode_alarm: T_SYNC_MODE T_ALARM '{' sync_mode_alarm_list '}' { conf.flags |= CTD_SYNC_ALARM; @@ -1598,6 +1638,7 @@ init_config(char *filename) /* Zero may be a valid facility */ CONFIG(syslog_facility) = -1; CONFIG(stats).syslog_facility = -1; + CONFIG(netlink).subsys_id = -1; yyrestart(fp); yyparse(); @@ -1646,5 +1687,12 @@ init_config(char *filename) if (CONFIG(channelc).error_queue_length == 0) CONFIG(channelc).error_queue_length = 128; + if (CONFIG(netlink).subsys_id == -1) { + CONFIG(netlink).subsys_id = NFNL_SUBSYS_CTNETLINK; + CONFIG(netlink).groups = NF_NETLINK_CONNTRACK_NEW | + NF_NETLINK_CONNTRACK_UPDATE | + NF_NETLINK_CONNTRACK_DESTROY; + } + return 0; } diff --git a/src/run.c b/src/run.c index c21db2e..26c1783 100644 --- a/src/run.c +++ b/src/run.c @@ -187,6 +187,62 @@ static void dump_stats_runtime(int fd) send(fd, buf, size, 0); } +static void local_flush_master(void) +{ + STATE(stats).nl_kernel_table_flush++; + dlog(LOG_NOTICE, "flushing kernel conntrack table"); + + /* fork a child process that performs the flush operation, + * meanwhile the parent process handles events. */ + if (fork_process_new(CTD_PROC_FLUSH, CTD_PROC_F_EXCL, + NULL, NULL) == 0) { + nl_flush_conntrack_table(STATE(flush)); + exit(EXIT_SUCCESS); + } +} + +static void local_resync_master(void) +{ + if (STATE(mode)->internal->flags & INTERNAL_F_POPULATE) { + STATE(stats).nl_kernel_table_resync++; + dlog(LOG_NOTICE, "resync with master conntrack table"); + nl_dump_conntrack_table(STATE(dump)); + } else { + dlog(LOG_NOTICE, "resync is unsupported in this mode"); + } +} + +static void local_exp_flush_master(void) +{ + if (!(CONFIG(flags) & CTD_EXPECT)) + return; + + STATE(stats).nl_kernel_table_flush++; + dlog(LOG_NOTICE, "flushing kernel expect table"); + + /* fork a child process that performs the flush operation, + * meanwhile the parent process handles events. */ + if (fork_process_new(CTD_PROC_FLUSH, CTD_PROC_F_EXCL, + NULL, NULL) == 0) { + nl_flush_expect_table(STATE(flush)); + exit(EXIT_SUCCESS); + } +} + +static void local_exp_resync_master(void) +{ + if (!(CONFIG(flags) & CTD_EXPECT)) + return; + + if (STATE(mode)->internal->flags & INTERNAL_F_POPULATE) { + STATE(stats).nl_kernel_table_resync++; + dlog(LOG_NOTICE, "resync with master expect table"); + nl_dump_expect_table(STATE(dump)); + } else { + dlog(LOG_NOTICE, "resync is unsupported in this mode"); + } +} + static int local_handler(int fd, void *data) { int ret = LOCAL_RET_OK; @@ -198,25 +254,24 @@ static int local_handler(int fd, void *data) } switch(type) { case CT_FLUSH_MASTER: - STATE(stats).nl_kernel_table_flush++; - dlog(LOG_NOTICE, "flushing kernel conntrack table"); - - /* fork a child process that performs the flush operation, - * meanwhile the parent process handles events. */ - if (fork_process_new(CTD_PROC_FLUSH, CTD_PROC_F_EXCL, - NULL, NULL) == 0) { - nl_flush_conntrack_table(STATE(flush)); - exit(EXIT_SUCCESS); - } + local_flush_master(); break; case CT_RESYNC_MASTER: - if (STATE(mode)->internal->flags & INTERNAL_F_POPULATE) { - STATE(stats).nl_kernel_table_resync++; - dlog(LOG_NOTICE, "resync with master table"); - nl_dump_conntrack_table(STATE(dump)); - } else { - dlog(LOG_NOTICE, "resync is unsupported in this mode"); - } + local_resync_master(); + break; + case EXP_FLUSH_MASTER: + local_exp_flush_master(); + break; + case EXP_RESYNC_MASTER: + local_exp_resync_master(); + break; + case ALL_FLUSH_MASTER: + local_flush_master(); + local_exp_flush_master(); + break; + case ALL_RESYNC_MASTER: + local_resync_master(); + local_exp_resync_master(); break; case STATS_RUNTIME: dump_stats_runtime(fd); @@ -245,7 +300,11 @@ static void do_polling_alarm(struct alarm_block *a, void *data) if (STATE(mode)->internal->ct.purge) STATE(mode)->internal->ct.purge(); + if (STATE(mode)->internal->exp.purge) + STATE(mode)->internal->exp.purge(); + nl_send_resync(STATE(resync)); + nl_send_expect_resync(STATE(resync)); add_alarm(&STATE(polling_alarm), CONFIG(poll_kernel_secs), 0); } @@ -290,6 +349,49 @@ out: return NFCT_CB_CONTINUE; } +static int exp_event_handler(const struct nlmsghdr *nlh, + enum nf_conntrack_msg_type type, + struct nf_expect *exp, + void *data) +{ + int origin_type; + const struct nf_conntrack *master = + nfexp_get_attr(exp, ATTR_EXP_MASTER); + + STATE(stats).nl_events_received++; + + if (!exp_filter_find(STATE(exp_filter), exp)) { + STATE(stats).nl_events_filtered++; + goto out; + } + if (ct_filter_conntrack(master, 1)) + return NFCT_CB_CONTINUE; + + origin_type = origin_find(nlh); + + switch(type) { + case NFCT_T_NEW: + STATE(mode)->internal->exp.new(exp, origin_type); + break; + case NFCT_T_UPDATE: + STATE(mode)->internal->exp.upd(exp, origin_type); + break; + case NFCT_T_DESTROY: + STATE(mode)->internal->exp.del(exp, origin_type); + break; + default: + STATE(stats).nl_events_unknown_type++; + break; + } + +out: + /* we reset the iteration limiter in the main select loop. */ + if (STATE(event_iterations_limit)-- <= 0) + return NFCT_CB_STOP; + else + return NFCT_CB_CONTINUE; +} + static int dump_handler(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *data) @@ -308,6 +410,29 @@ static int dump_handler(enum nf_conntrack_msg_type type, return NFCT_CB_CONTINUE; } +static int exp_dump_handler(enum nf_conntrack_msg_type type, + struct nf_expect *exp, void *data) +{ + const struct nf_conntrack *master = + nfexp_get_attr(exp, ATTR_EXP_MASTER); + + if (!exp_filter_find(STATE(exp_filter), exp)) + return NFCT_CB_CONTINUE; + + if (ct_filter_conntrack(master, 1)) + return NFCT_CB_CONTINUE; + + switch(type) { + case NFCT_T_UPDATE: + STATE(mode)->internal->exp.populate(exp); + break; + default: + STATE(stats).nl_dump_unknown_type++; + break; + } + return NFCT_CB_CONTINUE; +} + static int get_handler(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *data) @@ -319,6 +444,22 @@ static int get_handler(enum nf_conntrack_msg_type type, return NFCT_CB_CONTINUE; } +static int exp_get_handler(enum nf_conntrack_msg_type type, + struct nf_expect *exp, void *data) +{ + const struct nf_conntrack *master = + nfexp_get_attr(exp, ATTR_EXP_MASTER); + + if (!exp_filter_find(STATE(exp_filter), exp)) + return NFCT_CB_CONTINUE; + + if (ct_filter_conntrack(master, 1)) + return NFCT_CB_CONTINUE; + + STATE(get_retval) = 1; + return NFCT_CB_CONTINUE; +} + int init(void) { @@ -355,7 +496,7 @@ init(void) register_fd(STATE(local).fd, STATE(fds)); /* resynchronize (like 'dump' socket) but it also purges old entries */ - STATE(resync) = nfct_open(CONNTRACK, 0); + STATE(resync) = nfct_open(CONFIG(netlink).subsys_id, 0); if (STATE(resync)== NULL) { dlog(LOG_ERR, "can't open netlink handler: %s", strerror(errno)); @@ -370,7 +511,7 @@ init(void) fcntl(nfct_fd(STATE(resync)), F_SETFL, O_NONBLOCK); if (STATE(mode)->internal->flags & INTERNAL_F_POPULATE) { - STATE(dump) = nfct_open(CONNTRACK, 0); + STATE(dump) = nfct_open(CONFIG(netlink).subsys_id, 0); if (STATE(dump) == NULL) { dlog(LOG_ERR, "can't open netlink handler: %s", strerror(errno)); @@ -380,13 +521,26 @@ init(void) nfct_callback_register(STATE(dump), NFCT_T_ALL, dump_handler, NULL); + if (CONFIG(flags) & CTD_EXPECT) { + nfexp_callback_register(STATE(dump), NFCT_T_ALL, + exp_dump_handler, NULL); + } + if (nl_dump_conntrack_table(STATE(dump)) == -1) { dlog(LOG_ERR, "can't get kernel conntrack table"); return -1; } + + if (CONFIG(flags) & CTD_EXPECT) { + if (nl_dump_expect_table(STATE(dump)) == -1) { + dlog(LOG_ERR, "can't get kernel " + "expect table"); + return -1; + } + } } - STATE(get) = nfct_open(CONNTRACK, 0); + STATE(get) = nfct_open(CONFIG(netlink).subsys_id, 0); if (STATE(get) == NULL) { dlog(LOG_ERR, "can't open netlink handler: %s", strerror(errno)); @@ -395,7 +549,12 @@ init(void) } nfct_callback_register(STATE(get), NFCT_T_ALL, get_handler, NULL); - STATE(flush) = nfct_open(CONNTRACK, 0); + if (CONFIG(flags) & CTD_EXPECT) { + nfexp_callback_register(STATE(get), NFCT_T_ALL, + exp_get_handler, NULL); + } + + STATE(flush) = nfct_open(CONFIG(netlink).subsys_id, 0); if (STATE(flush) == NULL) { dlog(LOG_ERR, "cannot open flusher handler"); return -1; @@ -426,6 +585,11 @@ init(void) } nfct_callback_register2(STATE(event), NFCT_T_ALL, event_handler, NULL); + + if (CONFIG(flags) & CTD_EXPECT) { + nfexp_callback_register2(STATE(event), NFCT_T_ALL, + exp_event_handler, NULL); + } register_fd(nfct_fd(STATE(event)), STATE(fds)); } diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index fa76c0c..1bc2d9f 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -231,6 +231,8 @@ static int ftfw_local(int fd, int type, void *data) dlog(LOG_NOTICE, "sending bulk update"); cache_iterate(STATE(mode)->internal->ct.data, NULL, do_cache_to_tx); + cache_iterate(STATE(mode)->internal->exp.data, + NULL, do_cache_to_tx); break; case STATS_RSQUEUE: ftfw_local_queue(fd); @@ -350,7 +352,10 @@ static int digest_msg(const struct nethdr *net) } else if (IS_RESYNC(net)) { dp("RESYNC ALL\n"); - cache_iterate(STATE(mode)->internal->ct.data, NULL, do_cache_to_tx); + cache_iterate(STATE(mode)->internal->ct.data, NULL, + do_cache_to_tx); + cache_iterate(STATE(mode)->internal->exp.data, NULL, + do_cache_to_tx); return MSG_CTL; } else if (IS_ALIVE(net)) diff --git a/src/sync-mode.c b/src/sync-mode.c index fa522c7..2505631 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -59,10 +59,29 @@ static struct nf_conntrack *msg2ct_alloc(struct nethdr *net, size_t remain) return ct; } +static struct nf_expect *msg2exp_alloc(struct nethdr *net, size_t remain) +{ + struct nf_expect *exp; + + /* TODO: add stats on ENOMEM errors in the future. */ + exp = nfexp_new(); + if (exp == NULL) + return NULL; + + if (msg2exp(exp, net, remain) == -1) { + STATE_SYNC(error).msg_rcv_malformed++; + STATE_SYNC(error).msg_rcv_bad_payload++; + nfexp_destroy(exp); + return NULL; + } + return exp; +} + static void do_channel_handler_step(int i, struct nethdr *net, size_t remain) { - struct nf_conntrack *ct; + struct nf_conntrack *ct = NULL; + struct nf_expect *exp = NULL; if (net->version != CONNTRACKD_PROTOCOL_VERSION) { STATE_SYNC(error).msg_rcv_malformed++; @@ -112,12 +131,33 @@ do_channel_handler_step(int i, struct nethdr *net, size_t remain) return; STATE_SYNC(external)->ct.del(ct); break; + case NET_T_STATE_EXP_NEW: + exp = msg2exp_alloc(net, remain); + if (exp == NULL) + return; + STATE_SYNC(external)->exp.new(exp); + break; + case NET_T_STATE_EXP_UPD: + exp = msg2exp_alloc(net, remain); + if (exp == NULL) + return; + STATE_SYNC(external)->exp.upd(exp); + break; + case NET_T_STATE_EXP_DEL: + exp = msg2exp_alloc(net, remain); + if (exp == NULL) + return; + STATE_SYNC(external)->exp.del(exp); + break; default: STATE_SYNC(error).msg_rcv_malformed++; STATE_SYNC(error).msg_rcv_bad_type++; break; } - nfct_destroy(ct); + if (ct != NULL) + nfct_destroy(ct); + if (exp != NULL) + nfexp_destroy(exp); } static char __net[65536]; /* XXX: maximum MTU for IPv4 */ @@ -351,7 +391,7 @@ static int init_sync(void) STATE(fds)) == -1) return -1; - STATE_SYNC(commit).h = nfct_open(CONNTRACK, 0); + STATE_SYNC(commit).h = nfct_open(CONFIG(netlink).subsys_id, 0); if (STATE_SYNC(commit).h == NULL) { dlog(LOG_ERR, "can't create handler to commit"); return -1; @@ -402,8 +442,30 @@ static void run_sync(fd_set *readfds) interface_handler(); if (FD_ISSET(get_read_evfd(STATE_SYNC(commit).evfd), readfds)) { + int ret; + read_evfd(STATE_SYNC(commit).evfd); - STATE_SYNC(external)->ct.commit(STATE_SYNC(commit).h, 0); + + ret = STATE_SYNC(commit).rq[0].cb(STATE_SYNC(commit).h, 0); + if (ret == 0) { + /* we still have things in the callback queue. */ + if (STATE_SYNC(commit).rq[1].cb) { + int fd = STATE_SYNC(commit).clientfd; + + STATE_SYNC(commit).rq[0].cb = + STATE_SYNC(commit).rq[1].cb; + + STATE_SYNC(commit).rq[1].cb = NULL; + + STATE_SYNC(commit).clientfd = -1; + STATE_SYNC(commit).rq[0].cb( + STATE_SYNC(commit).h, fd); + } else { + /* Close the client socket now, we're done. */ + close(STATE_SYNC(commit).clientfd); + STATE_SYNC(commit).clientfd = -1; + } + } } /* flush pending messages */ @@ -480,6 +542,27 @@ static void dump_stats_sync_extended(int fd) send(fd, buf, size, 0); } +static int local_commit(int fd) +{ + int ret; + + /* delete the reset alarm if any before committing */ + del_alarm(&STATE_SYNC(reset_cache_alarm)); + + ret = STATE_SYNC(commit).rq[0].cb(STATE_SYNC(commit).h, fd); + if (ret == -1) { + dlog(LOG_NOTICE, "commit already in progress, skipping"); + ret = LOCAL_RET_OK; + } else if (ret == 0) { + /* we've finished the commit. */ + ret = LOCAL_RET_OK; + } else { + /* Keep open the client, we want synchronous commit. */ + ret = LOCAL_RET_STOLEN; + } + return ret; +} + /* handler for requests coming via UNIX socket */ static int local_handler_sync(int fd, int type, void *data) { @@ -511,19 +594,10 @@ static int local_handler_sync(int fd, int type, void *data) } break; case CT_COMMIT: - /* delete the reset alarm if any before committing */ - del_alarm(&STATE_SYNC(reset_cache_alarm)); - - dlog(LOG_NOTICE, "committing external cache"); - ret = STATE_SYNC(external)->ct.commit(STATE_SYNC(commit).h, fd); - if (ret == 0) { - dlog(LOG_NOTICE, "commit already in progress, " - "skipping"); - ret = LOCAL_RET_OK; - } else { - /* Keep open the client, we want synchronous commit. */ - ret = LOCAL_RET_STOLEN; - } + dlog(LOG_NOTICE, "committing conntrack cache"); + STATE_SYNC(commit).rq[0].cb = STATE_SYNC(external)->ct.commit; + STATE_SYNC(commit).rq[1].cb = NULL; + ret = local_commit(fd); break; case RESET_TIMERS: if (!alarm_pending(&STATE_SYNC(reset_cache_alarm))) { @@ -575,6 +649,63 @@ static int local_handler_sync(int fd, int type, void *data) case STATS_QUEUE: queue_stats_show(fd); break; + case EXP_STATS: + if (!(CONFIG(flags) & CTD_EXPECT)) + break; + + STATE(mode)->internal->exp.stats(fd); + STATE_SYNC(external)->exp.stats(fd); + dump_traffic_stats(fd); + multichannel_stats(STATE_SYNC(channel), fd); + dump_stats_sync(fd); + break; + case EXP_DUMP_INTERNAL: + if (!(CONFIG(flags) & CTD_EXPECT)) + break; + + if (fork_process_new(CTD_PROC_ANY, 0, NULL, NULL) == 0) { + STATE(mode)->internal->exp.dump(fd, NFCT_O_PLAIN); + exit(EXIT_SUCCESS); + } + break; + case EXP_DUMP_EXTERNAL: + if (!(CONFIG(flags) & CTD_EXPECT)) + break; + + if (fork_process_new(CTD_PROC_ANY, 0, NULL, NULL) == 0) { + STATE_SYNC(external)->exp.dump(fd, NFCT_O_PLAIN); + exit(EXIT_SUCCESS); + } + break; + case EXP_COMMIT: + if (!(CONFIG(flags) & CTD_EXPECT)) + break; + + dlog(LOG_NOTICE, "committing expectation cache"); + STATE_SYNC(commit).rq[0].cb = STATE_SYNC(external)->exp.commit; + STATE_SYNC(commit).rq[1].cb = NULL; + local_commit(fd); + break; + case ALL_FLUSH_CACHE: + dlog(LOG_NOTICE, "flushing caches"); + STATE(mode)->internal->ct.flush(); + STATE_SYNC(external)->ct.flush(); + if (CONFIG(flags) & CTD_EXPECT) { + STATE(mode)->internal->exp.flush(); + STATE_SYNC(external)->exp.flush(); + } + break; + case ALL_COMMIT: + dlog(LOG_NOTICE, "committing all external caches"); + STATE_SYNC(commit).rq[0].cb = STATE_SYNC(external)->ct.commit; + if (CONFIG(flags) & CTD_EXPECT) { + STATE_SYNC(commit).rq[1].cb = + STATE_SYNC(external)->exp.commit; + } else { + STATE_SYNC(commit).rq[1].cb = NULL; + } + local_commit(fd); + break; default: if (STATE_SYNC(sync)->local) ret = STATE_SYNC(sync)->local(fd, type, data); diff --git a/src/sync-notrack.c b/src/sync-notrack.c index 06ad1f0..a7df4e7 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -102,7 +102,7 @@ static void kernel_resync(void) u_int32_t family = AF_UNSPEC; int ret; - h = nfct_open(CONNTRACK, 0); + h = nfct_open(CONFIG(netlink).subsys_id, 0); if (h == NULL) { dlog(LOG_ERR, "can't allocate memory for the internal cache"); return; @@ -131,6 +131,8 @@ static int notrack_local(int fd, int type, void *data) } else { cache_iterate(STATE(mode)->internal->ct.data, NULL, do_cache_to_tx); + cache_iterate(STATE(mode)->internal->exp.data, + NULL, do_cache_to_tx); } break; default: @@ -152,6 +154,8 @@ static int digest_msg(const struct nethdr *net) } else { cache_iterate(STATE(mode)->internal->ct.data, NULL, do_cache_to_tx); + cache_iterate(STATE(mode)->internal->exp.data, + NULL, do_cache_to_tx); } return MSG_CTL; } -- cgit v1.2.3