summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2009-01-17 18:03:52 +0100
committerPablo Neira Ayuso <pablo@netfilter.org>2009-01-17 18:03:52 +0100
commit7ae054f8aae252ee9c57e26327675e466fc1d15d (patch)
tree8014a333b430477e336afd4621f49097c8d17435
parentd581381870486687586dea4ebf4b7065ae408cd0 (diff)
downloadconntrack-tools-7ae054f8aae252ee9c57e26327675e466fc1d15d.tar.gz
conntrack-tools-7ae054f8aae252ee9c57e26327675e466fc1d15d.zip
src: support for redundant dedicated links
This patch adds support for redundant dedicated links. You can add a pool of dedicated links that can be used if the current active fails. Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
-rw-r--r--doc/sync/alarm/conntrackd.conf19
-rw-r--r--doc/sync/ftfw/conntrackd.conf19
-rw-r--r--doc/sync/notrack/conntrackd.conf19
-rw-r--r--include/conntrackd.h10
-rw-r--r--include/mcast.h28
-rw-r--r--include/netlink.h1
-rw-r--r--include/network.h6
-rw-r--r--src/main.c6
-rw-r--r--src/mcast.c231
-rw-r--r--src/netlink.c16
-rw-r--r--src/network.c9
-rw-r--r--src/read_config_lex.l1
-rw-r--r--src/read_config_yy.y105
-rw-r--r--src/sync-mode.c109
14 files changed, 495 insertions, 84 deletions
diff --git a/doc/sync/alarm/conntrackd.conf b/doc/sync/alarm/conntrackd.conf
index f16f439..528ff8f 100644
--- a/doc/sync/alarm/conntrackd.conf
+++ b/doc/sync/alarm/conntrackd.conf
@@ -104,6 +104,25 @@ Sync {
#
Checksum on
}
+ #
+ # You can specify more than one dedicated link. Thus, if one dedicated
+ # link fails, conntrackd can fail-over to another. Note that adding
+ # more than one dedicated link does not mean that state-updates will
+ # be sent to all of them. There is only one active dedicated link at
+ # a given moment. The `Default' keyword indicates that this interface
+ # will be selected as the initial dedicated link. You can have
+ # up to 4 redundant dedicated links. Note: Use different multicast
+ # groups for every redundant link.
+ #
+ # Multicast Default {
+ # IPv4_address 225.0.0.51
+ # Group 3781
+ # IPv4_interface 192.168.100.101
+ # Interface eth3
+ # # McastSndSocketBuffer 1249280
+ # # McastRcvSocketBuffer 1249280
+ # Checksum on
+ # }
}
#
diff --git a/doc/sync/ftfw/conntrackd.conf b/doc/sync/ftfw/conntrackd.conf
index d85fc28..2e60f2c 100644
--- a/doc/sync/ftfw/conntrackd.conf
+++ b/doc/sync/ftfw/conntrackd.conf
@@ -112,6 +112,25 @@ Sync {
#
Checksum on
}
+ #
+ # You can specify more than one dedicated link. Thus, if one dedicated
+ # link fails, conntrackd can fail-over to another. Note that adding
+ # more than one dedicated link does not mean that state-updates will
+ # be sent to all of them. There is only one active dedicated link at
+ # a given moment. The `Default' keyword indicates that this interface
+ # will be selected as the initial dedicated link. You can have
+ # up to 4 redundant dedicated links. Note: Use different multicast
+ # groups for every redundant link.
+ #
+ # Multicast Default {
+ # IPv4_address 225.0.0.51
+ # Group 3781
+ # IPv4_interface 192.168.100.101
+ # Interface eth3
+ # # McastSndSocketBuffer 1249280
+ # # McastRcvSocketBuffer 1249280
+ # Checksum on
+ # }
}
#
diff --git a/doc/sync/notrack/conntrackd.conf b/doc/sync/notrack/conntrackd.conf
index 4d03234..7f8c8a3 100644
--- a/doc/sync/notrack/conntrackd.conf
+++ b/doc/sync/notrack/conntrackd.conf
@@ -94,6 +94,25 @@ Sync {
#
Checksum on
}
+ #
+ # You can specify more than one dedicated link. Thus, if one dedicated
+ # link fails, conntrackd can fail-over to another. Note that adding
+ # more than one dedicated link does not mean that state-updates will
+ # be sent to all of them. There is only one active dedicated link at
+ # a given moment. The `Default' keyword indicates that this interface
+ # will be selected as the initial dedicated link. You can have
+ # up to 4 redundant dedicated links. Note: Use different multicast
+ # groups for every redundant link.
+ #
+ # Multicast Default {
+ # IPv4_address 225.0.0.51
+ # Group 3781
+ # IPv4_interface 192.168.100.101
+ # Interface eth3
+ # # McastSndSocketBuffer 1249280
+ # # McastRcvSocketBuffer 1249280
+ # Checksum on
+ # }
}
#
diff --git a/include/conntrackd.h b/include/conntrackd.h
index 3637e2c..ab5d825 100644
--- a/include/conntrackd.h
+++ b/include/conntrackd.h
@@ -29,6 +29,7 @@
#define STATS_NETWORK 28 /* extended network stats */
#define STATS_CACHE 29 /* extended cache stats */
#define STATS_RUNTIME 30 /* extended runtime stats */
+#define STATS_MULTICAST 31 /* multicast network stats */
#define DEFAULT_CONFIGFILE "/etc/conntrackd/conntrackd.conf"
#define DEFAULT_LOCKFILE "/var/lock/conntrackd.lock"
@@ -66,7 +67,9 @@ struct ct_conf {
int syslog_facility;
char lockfile[FILENAME_MAXLEN];
int hashsize; /* hashtable size */
- struct mcast_conf mcast; /* multicast settings */
+ int mcast_links;
+ int mcast_default_link;
+ struct mcast_conf mcast[MCAST_LINKS_MAX];
struct local_conf local; /* unix socket facilities */
int limit;
int refresh;
@@ -148,8 +151,9 @@ struct ct_sync_state {
struct cache *internal; /* internal events cache (netlink) */
struct cache *external; /* external events cache (mcast) */
- struct mcast_sock *mcast_server; /* multicast socket: incoming */
- struct mcast_sock *mcast_client; /* multicast socket: outgoing */
+ struct mcast_sock_multi *mcast_server; /* multicast incoming */
+ struct mcast_sock_multi *mcast_client; /* multicast outgoing */
+ struct nlif_handle *mcast_iface;
struct queue *tx_queue;
struct sync_mode *sync; /* sync mode */
diff --git a/include/mcast.h b/include/mcast.h
index 7c4b1d6..623f390 100644
--- a/include/mcast.h
+++ b/include/mcast.h
@@ -19,6 +19,7 @@ struct mcast_conf {
unsigned int interface_index6;
} ifa;
int mtu;
+ int interface_idx;
int sndbuf;
int rcvbuf;
char iface[IFNAMSIZ];
@@ -37,19 +38,42 @@ struct mcast_sock {
struct sockaddr_in6 ipv6;
} addr;
socklen_t sockaddr_len;
+ int interface_idx;
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);
-struct mcast_stats *mcast_get_stats(struct mcast_sock *m);
-void mcast_dump_stats(int fd, struct mcast_sock *s, struct mcast_sock *r);
+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);
+
+struct nlif_handle;
+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/netlink.h b/include/netlink.h
index 5feb3e9..4bc5ee4 100644
--- a/include/netlink.h
+++ b/include/netlink.h
@@ -10,6 +10,7 @@ struct nfct_handle *nl_init_event_handler(void);
struct nfct_handle *nl_init_dump_handler(void);
struct nfct_handle *nl_init_request_handler(void);
struct nfct_handle *nl_init_overrun_handler(void);
+struct nlif_handle *nl_init_interface_handler(void);
int nl_overrun_request_resync(struct nfct_handle *h);
void nl_resize_socket_buffer(struct nfct_handle *h);
diff --git a/include/network.h b/include/network.h
index f02d920..740e762 100644
--- a/include/network.h
+++ b/include/network.h
@@ -76,7 +76,7 @@ enum {
__hdr; \
})
-struct mcast_sock;
+struct mcast_sock_multi;
enum {
SEQ_UNKNOWN,
@@ -94,8 +94,8 @@ struct mcast_conf;
int mcast_buffered_init(int mtu);
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);
+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)
diff --git a/src/main.c b/src/main.c
index 929b5c9..061a73e 100644
--- a/src/main.c
+++ b/src/main.c
@@ -43,7 +43,7 @@ static const char usage_client_commands[] =
" -i, display content of the internal cache\n"
" -e, display the content of the external cache\n"
" -k, kill conntrack daemon\n"
- " -s [|network|cache|runtime], dump statistics\n"
+ " -s [|network|cache|runtime|multicast], dump statistics\n"
" -R, 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"
@@ -169,6 +169,10 @@ int main(int argc, char *argv[])
strlen(argv[i+1])) == 0) {
action = STATS_RUNTIME;
i++;
+ } else if (strncmp(argv[i+1], "multicast",
+ strlen(argv[i+1])) == 0) {
+ action = STATS_MULTICAST;
+ i++;
} else {
fprintf(stderr, "ERROR: unknown "
"parameter `%s' for "
diff --git a/src/mcast.c b/src/mcast.c
index 2bb8743..70205d8 100644
--- a/src/mcast.c
+++ b/src/mcast.c
@@ -1,5 +1,5 @@
/*
- * (C) 2006 by Pablo Neira Ayuso <pablo@netfilter.org>
+ * (C) 2006-2009 by Pablo Neira Ayuso <pablo@netfilter.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -45,6 +45,8 @@ struct mcast_sock *mcast_server_create(struct mcast_conf *conf)
return NULL;
memset(m, 0, sizeof(struct mcast_sock));
+ m->interface_idx = conf->interface_idx;
+
switch(conf->ipproto) {
case AF_INET:
mreq.ipv4.imr_multiaddr.s_addr = conf->in.inet_addr.s_addr;
@@ -147,12 +149,52 @@ 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; i<conf_len; i++) {
+ m->multi[i] = mcast_server_create(&conf[i]);
+ if (m->multi[i] == NULL) {
+ for (j=0; j<i; j++) {
+ mcast_server_destroy(m->multi[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; i<m->num_links; i++)
+ mcast_server_destroy(m->multi[i]);
+ free(m);
+}
+
static int
__mcast_client_create_ipv4(struct mcast_sock *m, struct mcast_conf *conf)
{
@@ -222,6 +264,8 @@ struct mcast_sock *mcast_client_create(struct mcast_conf *conf)
return NULL;
memset(m, 0, sizeof(struct mcast_sock));
+ m->interface_idx = conf->interface_idx;
+
if ((m->fd = socket(conf->ipproto, SOCK_DGRAM, 0)) == -1) {
debug("mcast_sock_client_create:socket");
free(m);
@@ -275,12 +319,52 @@ 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; i<conf_len; i++) {
+ m->multi[i] = mcast_client_create(&conf[i]);
+ if (m->multi[i] == NULL) {
+ for (j=0; j<i; j++) {
+ mcast_client_destroy(m->multi[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; i<m->num_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;
@@ -326,29 +410,140 @@ ssize_t mcast_recv(struct mcast_sock *m, void *data, int size)
return ret;
}
-struct mcast_stats *mcast_get_stats(struct mcast_sock *m)
+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->stats;
+ return m->current_link->interface_idx;
}
-void mcast_dump_stats(int fd, struct mcast_sock *s, struct mcast_sock *r)
+int mcast_get_ifidx(struct mcast_sock_multi *m, int i)
{
- char buf[512];
+ return m->multi[i]->interface_idx;
+}
+
+static int
+mcast_snprintf_stats(char *buf, size_t buflen, char *ifname,
+ struct mcast_stats *s, struct mcast_stats *r)
+{
+ size_t size;
+
+ size = snprintf(buf, buflen, "multicast traffic (active device=%s):\n"
+ "%20llu Bytes sent "
+ "%20llu Bytes recv\n"
+ "%20llu Pckts sent "
+ "%20llu Pckts recv\n"
+ "%20llu Error send "
+ "%20llu Error recv\n\n",
+ ifname,
+ (unsigned long long)s->bytes,
+ (unsigned long long)r->bytes,
+ (unsigned long long)s->messages,
+ (unsigned long long)r->messages,
+ (unsigned long long)s->error,
+ (unsigned long long)r->error);
+ return size;
+}
+
+static 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)
+{
+ size_t size;
+
+ size = snprintf(buf, buflen,
+ "multicast traffic device=%s status=%s role=%s:\n"
+ "%20llu Bytes sent "
+ "%20llu Bytes recv\n"
+ "%20llu Pckts sent "
+ "%20llu Pckts recv\n"
+ "%20llu Error send "
+ "%20llu Error recv\n\n",
+ ifname, status, active ? "ACTIVE" : "BACKUP",
+ (unsigned long long)s->bytes,
+ (unsigned long long)r->bytes,
+ (unsigned long long)s->messages,
+ (unsigned long long)r->messages,
+ (unsigned long long)s->error,
+ (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;
- size = sprintf(buf, "multicast traffic:\n"
- "%20llu Bytes sent "
- "%20llu Bytes recv\n"
- "%20llu Pckts sent "
- "%20llu Pckts recv\n"
- "%20llu Error send "
- "%20llu Error recv\n\n",
- (unsigned long long)s->stats.bytes,
- (unsigned long long)r->stats.bytes,
- (unsigned long long)s->stats.messages,
- (unsigned long long)r->stats.messages,
- (unsigned long long)s->stats.error,
- (unsigned long long)r->stats.error);
+ /* it is the same for the receiver, no need to do it twice */
+ if_indextoname(s->current_link->interface_idx, ifname);
+
+ for (i=0; i<s->num_links && i<r->num_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; i<s->num_links && i<r->num_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/netlink.c b/src/netlink.c
index 92fbf00..2266201 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -114,6 +114,22 @@ struct nfct_handle *nl_init_request_handler(void)
return h;
}
+struct nlif_handle *nl_init_interface_handler(void)
+{
+ struct nlif_handle *h;
+ h = nlif_open();
+ if (h == NULL)
+ return NULL;
+
+ if (nlif_query(h) == -1) {
+ free(h);
+ return NULL;
+ }
+ fcntl(nlif_fd(h), F_SETFL, O_NONBLOCK);
+
+ return h;
+}
+
static int warned = 0;
void nl_resize_socket_buffer(struct nfct_handle *h)
diff --git a/src/network.c b/src/network.c
index 7a106b1..f71aef0 100644
--- a/src/network.c
+++ b/src/network.c
@@ -95,7 +95,8 @@ void mcast_buffered_destroy(void)
}
/* return 0 if it is not sent, otherwise return 1 */
-int mcast_buffered_send_netmsg(struct mcast_sock *m, const struct nethdr *net)
+int
+mcast_buffered_send_netmsg(struct mcast_sock_multi *m, const struct nethdr *net)
{
int ret = 0, len = ntohs(net->len);
@@ -104,7 +105,7 @@ retry:
memcpy(tx_buf + tx_buflen, net, len);
tx_buflen += len;
} else {
- mcast_send(m, tx_buf, tx_buflen);
+ mcast_send(mcast_get_current_link(m), tx_buf, tx_buflen);
ret = 1;
tx_buflen = 0;
goto retry;
@@ -113,14 +114,14 @@ retry:
return ret;
}
-ssize_t mcast_buffered_pending_netmsg(struct mcast_sock *m)
+ssize_t mcast_buffered_pending_netmsg(struct mcast_sock_multi *m)
{
ssize_t ret;
if (tx_buflen == 0)
return 0;
- ret = mcast_send(m, tx_buf, tx_buflen);
+ ret = mcast_send(mcast_get_current_link(m), tx_buf, tx_buflen);
tx_buflen = 0;
return ret;
diff --git a/src/read_config_lex.l b/src/read_config_lex.l
index f8b0ba1..e9e5d43 100644
--- a/src/read_config_lex.l
+++ b/src/read_config_lex.l
@@ -118,6 +118,7 @@ notrack [N|n][O|o][T|t][R|r][A|a][C|c][K|k]
"Userspace" { return T_USERSPACE; }
"Kernelspace" { return T_KERNELSPACE; }
"EventIterationLimit" { return T_EVENT_ITER_LIMIT; }
+"Default" { return T_DEFAULT; }
{is_on} { return T_ON; }
{is_off} { return T_OFF; }
diff --git a/src/read_config_yy.y b/src/read_config_yy.y
index 274bfc3..de6cef3 100644
--- a/src/read_config_yy.y
+++ b/src/read_config_yy.y
@@ -38,6 +38,7 @@ struct ct_conf conf;
static void __kernel_filter_start(void);
static void __kernel_filter_add_state(int value);
+static void __max_mcast_dedicated_links_reached(void);
%}
%union {
@@ -59,7 +60,7 @@ static void __kernel_filter_add_state(int value);
%token T_SYSLOG T_WRITE_THROUGH T_STAT_BUFFER_SIZE T_DESTROY_TIMEOUT
%token T_MCAST_RCVBUFF T_MCAST_SNDBUFF T_NOTRACK
%token T_FILTER T_ADDRESS T_PROTOCOL T_STATE T_ACCEPT T_IGNORE
-%token T_FROM T_USERSPACE T_KERNELSPACE T_EVENT_ITER_LIMIT
+%token T_FROM T_USERSPACE T_KERNELSPACE T_EVENT_ITER_LIMIT T_DEFAULT
%token <string> T_IP T_PATH_VAL
%token <val> T_NUMBER
@@ -174,14 +175,22 @@ checksum: T_CHECKSUM T_ON
{
fprintf(stderr, "WARNING: The use of `Checksum' outside the "
"`Multicast' clause is ambiguous.\n");
- conf.mcast.checksum = 0;
+ /*
+ * 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;
};
checksum: T_CHECKSUM T_OFF
{
fprintf(stderr, "WARNING: The use of `Checksum' outside the "
"`Multicast' clause is ambiguous.\n");
- conf.mcast.checksum = 1;
+ /*
+ * 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;
};
ignore_traffic : T_IGNORE_TRAFFIC '{' ignore_traffic_options '}'
@@ -243,32 +252,45 @@ ignore_traffic_option : T_IPV6_ADDR T_IP
};
-multicast_line : T_MULTICAST '{' multicast_options '}';
+multicast_line : T_MULTICAST '{' multicast_options '}'
+{
+ conf.mcast_links++;
+};
+
+multicast_line : T_MULTICAST T_DEFAULT '{' multicast_options '}'
+{
+ conf.mcast_default_link = conf.mcast_links;
+ conf.mcast_links++;
+};
multicast_options :
| multicast_options multicast_option;
multicast_option : T_IPV4_ADDR T_IP
{
- if (!inet_aton($2, &conf.mcast.in)) {
+ __max_mcast_dedicated_links_reached();
+
+ if (!inet_aton($2, &conf.mcast[conf.mcast_links].in)) {
fprintf(stderr, "%s is not a valid IPv4 address\n", $2);
break;
}
- if (conf.mcast.ipproto == AF_INET6) {
+ if (conf.mcast[conf.mcast_links].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.ipproto = AF_INET;
+ conf.mcast[conf.mcast_links].ipproto = AF_INET;
};
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.in) <= 0) {
+ if (inet_pton(AF_INET6, $2, &conf.mcast[conf.mcast_links].in) <= 0) {
fprintf(stderr, "%s is not a valid IPv6 address\n", $2);
break;
}
@@ -277,16 +299,17 @@ multicast_option : T_IPV6_ADDR T_IP
break;
#endif
- if (conf.mcast.ipproto == AF_INET) {
+ if (conf.mcast[conf.mcast_links].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.ipproto = AF_INET6;
+ conf.mcast[conf.mcast_links].ipproto = AF_INET6;
- if (conf.mcast.iface[0] && !conf.mcast.ifa.interface_index6) {
+ if (conf.mcast[conf.mcast_links].iface[0] &&
+ !conf.mcast[conf.mcast_links].ifa.interface_index6) {
unsigned int idx;
idx = if_nametoindex($2);
@@ -295,26 +318,28 @@ multicast_option : T_IPV6_ADDR T_IP
break;
}
- conf.mcast.ifa.interface_index6 = idx;
- conf.mcast.ipproto = AF_INET6;
+ conf.mcast[conf.mcast_links].ifa.interface_index6 = idx;
+ conf.mcast[conf.mcast_links].ipproto = AF_INET6;
}
};
multicast_option : T_IPV4_IFACE T_IP
{
- if (!inet_aton($2, &conf.mcast.ifa)) {
+ __max_mcast_dedicated_links_reached();
+
+ if (!inet_aton($2, &conf.mcast[conf.mcast_links].ifa)) {
fprintf(stderr, "%s is not a valid IPv4 address\n", $2);
break;
}
- if (conf.mcast.ipproto == AF_INET6) {
+ if (conf.mcast[conf.mcast_links].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.ipproto = AF_INET;
+ conf.mcast[conf.mcast_links].ipproto = AF_INET;
};
multicast_option : T_IPV6_IFACE T_IP
@@ -324,19 +349,22 @@ multicast_option : T_IPV6_IFACE T_IP
multicast_option : T_IFACE T_STRING
{
- strncpy(conf.mcast.iface, $2, IFNAMSIZ);
+ unsigned int idx;
- if (conf.mcast.ipproto == AF_INET6) {
- unsigned int idx;
+ __max_mcast_dedicated_links_reached();
- idx = if_nametoindex($2);
- if (!idx) {
- fprintf(stderr, "%s is an invalid interface.\n", $2);
- break;
- }
+ strncpy(conf.mcast[conf.mcast_links].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.mcast.ifa.interface_index6 = idx;
- conf.mcast.ipproto = AF_INET6;
+ 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;
}
};
@@ -348,27 +376,32 @@ multicast_option : T_BACKLOG T_NUMBER
multicast_option : T_GROUP T_NUMBER
{
- conf.mcast.port = $2;
+ __max_mcast_dedicated_links_reached();
+ conf.mcast[conf.mcast_links].port = $2;
};
multicast_option: T_MCAST_SNDBUFF T_NUMBER
{
- conf.mcast.sndbuf = $2;
+ __max_mcast_dedicated_links_reached();
+ conf.mcast[conf.mcast_links].sndbuf = $2;
};
multicast_option: T_MCAST_RCVBUFF T_NUMBER
{
- conf.mcast.rcvbuf = $2;
+ __max_mcast_dedicated_links_reached();
+ conf.mcast[conf.mcast_links].rcvbuf = $2;
};
multicast_option: T_CHECKSUM T_ON
{
- conf.mcast.checksum = 0;
+ __max_mcast_dedicated_links_reached();
+ conf.mcast[conf.mcast_links].checksum = 0;
};
multicast_option: T_CHECKSUM T_OFF
{
- conf.mcast.checksum = 1;
+ __max_mcast_dedicated_links_reached();
+ conf.mcast[conf.mcast_links].checksum = 1;
};
hashsize : T_HASHSIZE T_NUMBER
@@ -1050,6 +1083,16 @@ static void __kernel_filter_add_state(int value)
&filter_proto);
}
+static void __max_mcast_dedicated_links_reached(void)
+{
+ if (conf.mcast_links >= MCAST_LINKS_MAX) {
+ fprintf(stderr, "ERROR: too many dedicated links in "
+ "the configuration file (Maximum: %d).\n",
+ MCAST_LINKS_MAX);
+ exit(EXIT_FAILURE);
+ }
+}
+
int
init_config(char *filename)
{
diff --git a/src/sync-mode.c b/src/sync-mode.c
index 00e2f7b..0dbd12d 100644
--- a/src/sync-mode.c
+++ b/src/sync-mode.c
@@ -33,8 +33,10 @@
#include <time.h>
#include <string.h>
#include <stdlib.h>
+#include <net/if.h>
-static void do_mcast_handler_step(struct nethdr *net, size_t remain)
+static void
+do_mcast_handler_step(int if_idx, struct nethdr *net, size_t remain)
{
char __ct[nfct_maxsize()];
struct nf_conntrack *ct = (struct nf_conntrack *)(void*) __ct;
@@ -47,6 +49,9 @@ static void do_mcast_handler_step(struct nethdr *net, size_t remain)
return;
}
+ if (if_idx != mcast_get_current_ifidx(STATE_SYNC(mcast_client)))
+ mcast_set_current_link(STATE_SYNC(mcast_client), if_idx);
+
switch (STATE_SYNC(sync)->recv(net)) {
case MSG_DATA:
break;
@@ -111,13 +116,13 @@ retry:
}
/* handler for multicast messages received */
-static void mcast_handler(void)
+static void mcast_handler(struct mcast_sock *m, int if_idx)
{
ssize_t numbytes;
ssize_t remain;
char __net[65536], *ptr = __net; /* XXX: maximum MTU for IPv4 */
- numbytes = mcast_recv(STATE_SYNC(mcast_server), __net, sizeof(__net));
+ numbytes = mcast_recv(m, __net, sizeof(__net));
if (numbytes <= 0)
return;
@@ -160,12 +165,46 @@ static void mcast_handler(void)
HDR_NETWORK2HOST(net);
- do_mcast_handler_step(net, remain);
+ do_mcast_handler_step(if_idx, net, remain);
ptr += net->len;
remain -= net->len;
}
}
+/* select a new interface candidate in a round robin basis */
+static void mcast_iface_candidate(void)
+{
+ int i, idx;
+ unsigned int flags;
+ char buf[IFNAMSIZ];
+
+ for (i=0; i<STATE_SYNC(mcast_client)->num_links; i++) {
+ idx = mcast_get_ifidx(STATE_SYNC(mcast_client), i);
+ if (idx == mcast_get_current_ifidx(STATE_SYNC(mcast_client)))
+ continue;
+ nlif_get_ifflags(STATE_SYNC(mcast_iface), idx, &flags);
+ if (flags & (IFF_RUNNING | IFF_UP)) {
+ mcast_set_current_link(STATE_SYNC(mcast_client), i);
+ dlog(LOG_NOTICE, "device `%s' becomes multicast "
+ "dedicated link",
+ if_indextoname(idx, buf));
+ return;
+ }
+ }
+ dlog(LOG_ERR, "no dedicated links available!");
+}
+
+static void mcast_iface_handler(void)
+{
+ int idx = mcast_get_current_ifidx(STATE_SYNC(mcast_client));
+ unsigned int flags;
+
+ nlif_catch(STATE_SYNC(mcast_iface));
+ nlif_get_ifflags(STATE_SYNC(mcast_iface), idx, &flags);
+ if (!(flags & IFF_RUNNING) || !(flags & IFF_UP))
+ mcast_iface_candidate();
+}
+
static int init_sync(void)
{
state.sync = malloc(sizeof(struct ct_sync_state));
@@ -216,30 +255,35 @@ static int init_sync(void)
}
/* multicast server to receive events from the wire */
- STATE_SYNC(mcast_server) = mcast_server_create(&CONFIG(mcast));
+ 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!");
return -1;
}
- dlog(LOG_NOTICE, "multicast server socket receiver queue "
- "has been set to %d bytes", CONFIG(mcast).rcvbuf);
-
/* multicast client to send events on the wire */
- STATE_SYNC(mcast_client) = mcast_client_create(&CONFIG(mcast));
+ 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(STATE_SYNC(mcast_server));
+ 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));
- dlog(LOG_NOTICE, "multicast client socket sender queue "
- "has been set to %d bytes", CONFIG(mcast).sndbuf);
-
- if (mcast_buffered_init(CONFIG(mcast).mtu) == -1) {
+ if (mcast_buffered_init(STATE_SYNC(mcast_client)->max_mtu) == -1) {
dlog(LOG_ERR, "can't init tx buffer!");
- mcast_server_destroy(STATE_SYNC(mcast_server));
- mcast_client_destroy(STATE_SYNC(mcast_client));
+ mcast_server_destroy_multi(STATE_SYNC(mcast_server));
+ mcast_client_destroy_multi(STATE_SYNC(mcast_client));
+ return -1;
+ }
+
+ STATE_SYNC(mcast_iface) = nl_init_interface_handler();
+ if (!STATE_SYNC(mcast_iface)) {
+ dlog(LOG_ERR, "can't open interface watcher");
return -1;
}
@@ -257,7 +301,14 @@ static int init_sync(void)
static int register_fds_sync(struct fds *fds)
{
- if (register_fd(STATE_SYNC(mcast_server->fd), fds) == -1)
+ int i;
+
+ for (i=0; i<STATE_SYNC(mcast_server)->num_links; i++) {
+ int fd = mcast_get_fd(STATE_SYNC(mcast_server)->multi[i]);
+ if (register_fd(fd, fds) == -1)
+ return -1;
+ }
+ if (register_fd(nlif_fd(STATE_SYNC(mcast_iface)), fds) == -1)
return -1;
if (register_fd(queue_get_eventfd(STATE_SYNC(tx_queue)), fds) == -1)
@@ -268,13 +319,20 @@ static int register_fds_sync(struct fds *fds)
static void run_sync(fd_set *readfds)
{
- /* multicast packet has been received */
- if (FD_ISSET(STATE_SYNC(mcast_server->fd), readfds))
- mcast_handler();
+ int i;
+
+ for (i=0; i<STATE_SYNC(mcast_server)->num_links; i++) {
+ int fd = mcast_get_fd(STATE_SYNC(mcast_server)->multi[i]);
+ if (FD_ISSET(fd, readfds))
+ mcast_handler(STATE_SYNC(mcast_server)->multi[i], i);
+ }
if (FD_ISSET(queue_get_eventfd(STATE_SYNC(tx_queue)), readfds))
STATE_SYNC(sync)->xmit();
+ if (FD_ISSET(nlif_fd(STATE_SYNC(mcast_iface)), readfds))
+ mcast_iface_handler();
+
/* flush pending messages */
mcast_buffered_pending_netmsg(STATE_SYNC(mcast_client));
}
@@ -284,8 +342,10 @@ static void kill_sync(void)
cache_destroy(STATE_SYNC(internal));
cache_destroy(STATE_SYNC(external));
- mcast_server_destroy(STATE_SYNC(mcast_server));
- mcast_client_destroy(STATE_SYNC(mcast_client));
+ mcast_server_destroy_multi(STATE_SYNC(mcast_server));
+ mcast_client_destroy_multi(STATE_SYNC(mcast_client));
+
+ nlif_close(STATE_SYNC(mcast_iface));
mcast_buffered_destroy();
queue_destroy(STATE_SYNC(tx_queue));
@@ -418,6 +478,11 @@ static int local_handler_sync(int fd, int type, void *data)
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(mcast_iface));
+ break;
default:
if (STATE_SYNC(sync)->local)
ret = STATE_SYNC(sync)->local(fd, type, data);