diff options
author | Pablo Neira Ayuso <pablo@netfilter.org> | 2009-01-17 18:03:52 +0100 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2009-01-17 18:03:52 +0100 |
commit | 7ae054f8aae252ee9c57e26327675e466fc1d15d (patch) | |
tree | 8014a333b430477e336afd4621f49097c8d17435 | |
parent | d581381870486687586dea4ebf4b7065ae408cd0 (diff) | |
download | conntrack-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.conf | 19 | ||||
-rw-r--r-- | doc/sync/ftfw/conntrackd.conf | 19 | ||||
-rw-r--r-- | doc/sync/notrack/conntrackd.conf | 19 | ||||
-rw-r--r-- | include/conntrackd.h | 10 | ||||
-rw-r--r-- | include/mcast.h | 28 | ||||
-rw-r--r-- | include/netlink.h | 1 | ||||
-rw-r--r-- | include/network.h | 6 | ||||
-rw-r--r-- | src/main.c | 6 | ||||
-rw-r--r-- | src/mcast.c | 231 | ||||
-rw-r--r-- | src/netlink.c | 16 | ||||
-rw-r--r-- | src/network.c | 9 | ||||
-rw-r--r-- | src/read_config_lex.l | 1 | ||||
-rw-r--r-- | src/read_config_yy.y | 105 | ||||
-rw-r--r-- | src/sync-mode.c | 109 |
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) @@ -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); |