From 7ae054f8aae252ee9c57e26327675e466fc1d15d Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 17 Jan 2009 18:03:52 +0100 Subject: 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 --- src/main.c | 6 +- src/mcast.c | 231 ++++++++++++++++++++++++++++++++++++++++++++++---- src/netlink.c | 16 ++++ src/network.c | 9 +- src/read_config_lex.l | 1 + src/read_config_yy.y | 105 ++++++++++++++++------- src/sync-mode.c | 109 +++++++++++++++++++----- 7 files changed, 401 insertions(+), 76 deletions(-) (limited to 'src') 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 + * (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 @@ -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; 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) { @@ -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; 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; @@ -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; 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/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 T_IP T_PATH_VAL %token 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 #include #include +#include -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; inum_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; inum_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; inum_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); -- cgit v1.2.3