From 84f08393a85d3994fc26e434cdeabb24e66da5fb Mon Sep 17 00:00:00 2001 From: Justin Pettit Date: Fri, 13 Feb 2009 10:36:44 -0800 Subject: [PATCH] Support multiple NetFlow collectors. Add support for sending NetFlow messages to up to eight different collectors. With these changes, secchan now reads configuration files using the same syntax as vswitchd. This address Redmine feature #901. --- lib/automake.mk | 2 + {vswitchd => lib}/cfg.c | 0 {vswitchd => lib}/cfg.h | 0 secchan/executer.c | 1 + secchan/fail-open.c | 1 + secchan/flow-end.c | 100 ++++++++++++++++++++++++++++++--------- secchan/flow-end.h | 5 +- secchan/in-band.c | 3 +- secchan/port-watcher.c | 1 + secchan/ratelimit.c | 3 +- secchan/secchan.8.in | 31 ++++++++---- secchan/secchan.c | 60 ++++++++++++++++++----- secchan/secchan.h | 9 ++-- secchan/snat.c | 1 + secchan/status.c | 3 +- secchan/stp-secchan.c | 1 + vswitchd/automake.mk | 2 - vswitchd/bridge.c | 40 ++++++++-------- vswitchd/vswitchd.c | 4 ++ vswitchd/vswitchd.conf.5 | 12 ++--- 20 files changed, 198 insertions(+), 81 deletions(-) rename {vswitchd => lib}/cfg.c (100%) rename {vswitchd => lib}/cfg.h (100%) diff --git a/lib/automake.mk b/lib/automake.mk index d1cccd9e..f629a1f1 100644 --- a/lib/automake.mk +++ b/lib/automake.mk @@ -5,6 +5,8 @@ lib_libopenflow_a_SOURCES = \ lib/backtrace.h \ lib/bitmap.c \ lib/bitmap.h \ + lib/cfg.c \ + lib/cfg.h \ lib/command-line.c \ lib/command-line.h \ lib/compiler.h \ diff --git a/vswitchd/cfg.c b/lib/cfg.c similarity index 100% rename from vswitchd/cfg.c rename to lib/cfg.c diff --git a/vswitchd/cfg.h b/lib/cfg.h similarity index 100% rename from vswitchd/cfg.h rename to lib/cfg.h diff --git a/secchan/executer.c b/secchan/executer.c index 964a8b94..fb26ecd3 100644 --- a/secchan/executer.c +++ b/secchan/executer.c @@ -478,6 +478,7 @@ static struct hook_class executer_hook_class = { executer_periodic_cb, /* periodic_cb */ executer_wait_cb, /* wait_cb */ executer_closing_cb, /* closing_cb */ + NULL, /* reconfigure_cb */ }; void diff --git a/secchan/fail-open.c b/secchan/fail-open.c index eb28bc38..27295277 100644 --- a/secchan/fail-open.c +++ b/secchan/fail-open.c @@ -137,6 +137,7 @@ static struct hook_class fail_open_hook_class = { fail_open_periodic_cb, /* periodic_cb */ fail_open_wait_cb, /* wait_cb */ NULL, /* closing_cb */ + NULL, /* reconfigure_cb */ }; void diff --git a/secchan/flow-end.c b/secchan/flow-end.c index 82b0186f..dd8a9c08 100644 --- a/secchan/flow-end.c +++ b/secchan/flow-end.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford +/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford * Junior University * * We are making the OpenFlow specification and associated documentation @@ -32,7 +32,6 @@ */ #include -#include "flow-end.h" #include #include #include @@ -40,27 +39,36 @@ #include #include #include + #include "openflow/nicira-ext.h" #include "openflow/openflow.h" -#include "secchan.h" +#include "cfg.h" +#include "flow-end.h" +#include "netflow.h" #include "ofpbuf.h" -#include "vconn.h" #include "rconn.h" +#include "secchan.h" #include "socket-util.h" +#include "svec.h" +#include "vconn.h" #include "xtoxll.h" -#include "netflow.h" #define THIS_MODULE VLM_flow_end #include "vlog.h" + +#define MAX_COLLECTORS 8 + struct flow_end_data { + const struct settings *s; + struct rconn *remote_rconn; struct rconn *local_rconn; - bool send_ofp_exp; /* Send OpenFlow 'flow expired' messages? */ + bool send_ofp_exp; /* Send OpenFlow 'flow expired' messages? */ - int netflow_fd; /* Socket for NetFlow collector. */ - uint32_t netflow_cnt; /* Flow sequence number for NetFlow. */ + int netflow_fds[MAX_COLLECTORS]; /* Sockets for NetFlow collectors. */ + uint32_t netflow_cnt; /* Flow sequence number for NetFlow. */ }; static int @@ -126,6 +134,7 @@ send_netflow_msg(const struct nx_flow_end *nfe, struct flow_end_data *fe) uint8_t buf[sizeof(*nf_hdr) + sizeof(*nf_rec)]; uint8_t *p = buf; struct timeval now; + int i; /* We only send NetFlow messages for fully specified IP flows; any * entry with a wildcard is ignored. */ @@ -182,7 +191,12 @@ send_netflow_msg(const struct nx_flow_end *nfe, struct flow_end_data *fe) nf_rec->src_mask = 0; nf_rec->dst_mask = 0; - send(fe->netflow_fd, buf, sizeof(buf), 0); + for (i=0; inetflow_fds[i] == -1) { + break; + } + send(fe->netflow_fds[i], buf, sizeof(buf), 0); + } fe->netflow_cnt++; } @@ -222,7 +236,7 @@ send_nx_flow_end_config(const struct flow_end_data *fe) nfec = make_openflow(sizeof(*nfec), OFPT_VENDOR, &b); nfec->header.vendor = htonl(NX_VENDOR_ID); nfec->header.subtype = htonl(NXT_FLOW_END_CONFIG); - if ((fe->send_ofp_exp == false) && (fe->netflow_fd < 0)) { + if ((fe->send_ofp_exp == false) && (fe->netflow_fds[0] < 0)) { nfec->enable = 0; } else { nfec->enable = 1; @@ -250,7 +264,7 @@ flow_end_local_packet_cb(struct relay *r, void *flow_end_) return false; } - if (fe->netflow_fd >= 0) { + if (fe->netflow_fds[0] >= 0) { send_netflow_msg(nfe, fe); } @@ -289,37 +303,77 @@ flow_end_remote_packet_cb(struct relay *r, void *flow_end_) return false; } +static void +flow_end_reconfigure_cb(void *flow_end_) +{ + int i, nf_idx=0; + struct flow_end_data *fe = flow_end_; + struct svec collectors; + + /* Configure NetFlow collectors. */ + for (i=0; inetflow_fds[i] >= 0) { + close(fe->netflow_fds[i]); + fe->netflow_fds[i] = -1; + } + } + + svec_init(&collectors); + cfg_get_all_keys(&collectors, "netflow.%s.host", fe->s->br_name); + svec_sort(&collectors); + if (!svec_is_unique(&collectors)) { + VLOG_WARN("%s specified twice as netflow collector", + svec_get_duplicate(&collectors)); + svec_unique(&collectors); + } + + for (i=0; i= MAX_COLLECTORS) { + VLOG_WARN("too many netflow collectors specified, ignoring %s\n", + collectors.names[i]); + continue; + } + + fe->netflow_fds[nf_idx] = udp_open(collectors.names[i]); + if (fe->netflow_fds[nf_idx] < 0) { + VLOG_WARN("couldn't open connection to collector, ignoring %s\n", + collectors.names[i]); + } else { + nf_idx++; + } + } + + if (nf_idx > 0) { + send_nx_flow_end_config(fe); + } +} + static struct hook_class flow_end_hook_class = { flow_end_local_packet_cb, /* local_packet_cb */ flow_end_remote_packet_cb, /* remote_packet_cb */ NULL, /* periodic_cb */ NULL, /* wait_cb */ NULL, /* closing_cb */ + flow_end_reconfigure_cb, /* reconfigure_cb */ }; void -flow_end_start(struct secchan *secchan, char *netflow_dst, +flow_end_start(struct secchan *secchan, const struct settings *settings, struct rconn *local, struct rconn *remote) { + int i; struct flow_end_data *fe; fe = xcalloc(1, sizeof *fe); + fe->s = settings; fe->remote_rconn = remote; fe->local_rconn = local; - if (netflow_dst) { - fe->netflow_fd = udp_open(netflow_dst); - if (fe->netflow_fd < 0) { - ofp_fatal(0, "NetFlow setup failed"); - } - fe->send_ofp_exp = true; - } else { - fe->netflow_fd = -1; - fe->send_ofp_exp = false; + for (i=0; inetflow_fds[i] = -1; } + fe->send_ofp_exp = false; add_hook(secchan, &flow_end_hook_class, fe); - - send_nx_flow_end_config(fe); } diff --git a/secchan/flow-end.h b/secchan/flow-end.h index 3fb1f8f8..4ffad59a 100644 --- a/secchan/flow-end.h +++ b/secchan/flow-end.h @@ -34,9 +34,12 @@ #ifndef FLOW_END_H #define FLOW_END_H 1 + struct secchan; +struct settings; struct rconn; -void flow_end_start(struct secchan *, char *, struct rconn *, struct rconn *); +void flow_end_start(struct secchan *, const struct settings *, + struct rconn *, struct rconn *); #endif /* flow-end.h */ diff --git a/secchan/in-band.c b/secchan/in-band.c index 46109daf..0ff29d1e 100644 --- a/secchan/in-band.c +++ b/secchan/in-band.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford +/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford * Junior University * * We are making the OpenFlow specification and associated documentation @@ -310,6 +310,7 @@ static struct hook_class in_band_hook_class = { in_band_periodic_cb, /* periodic_cb */ in_band_wait_cb, /* wait_cb */ NULL, /* closing_cb */ + NULL, /* reconfigure_cb */ }; void diff --git a/secchan/port-watcher.c b/secchan/port-watcher.c index 1d8d69d4..feebd897 100644 --- a/secchan/port-watcher.c +++ b/secchan/port-watcher.c @@ -594,6 +594,7 @@ static struct hook_class port_watcher_hook_class = { port_watcher_periodic_cb, /* periodic_cb */ port_watcher_wait_cb, /* wait_cb */ NULL, /* closing_cb */ + NULL, /* reconfigure_cb */ }; void diff --git a/secchan/ratelimit.c b/secchan/ratelimit.c index 7a1e4951..f03a2866 100644 --- a/secchan/ratelimit.c +++ b/secchan/ratelimit.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford +/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford * Junior University * * We are making the OpenFlow specification and associated documentation @@ -240,6 +240,7 @@ static struct hook_class rate_limit_hook_class = { rate_limit_periodic_cb, /* periodic_cb */ rate_limit_wait_cb, /* wait_cb */ NULL, /* closing_cb */ + NULL, /* reconfigure_cb */ }; void diff --git a/secchan/secchan.8.in b/secchan/secchan.8.in index 18d1ef3e..8921a42a 100644 --- a/secchan/secchan.8.in +++ b/secchan/secchan.8.in @@ -1,6 +1,6 @@ .ds PN secchan -.TH secchan 8 "October 2008" "OpenFlow" "OpenFlow Manual" +.TH secchan 8 "February 2009" "OpenFlow" "OpenFlow Manual" .SH NAME secchan \- secure channel connecting an OpenFlow datapath to a controller @@ -195,6 +195,25 @@ the local port network device, and start the DHCP client afterward. .RE .SH OPTIONS +.SS "Configuration Options" +.TP +\fB-F \fIfile\fR|\fIdir\fR, \fB--config=\fIfile\fR|\fIdir\fR +The \fB-F\fR or \fB--config\fR option specifies a configuration file +or directory. If a regular file is named, then \fBsecchan\fR reads +that file. If a directory is named, then \fBsecchan\fR reads all the +files in that directory whose names consist entirely of English +letters, digits, and the special characters \fB._-\fR and do not begin +with \fB.\fR. +.IP +For a description of the configuration syntax, see \fBvswitchd.conf\fR(5). +Currently, only the NetFlow section applies to \fBsecchan\fR. + +.TP +\fB--br-name=\fIname\fR +When processing the configuration files specified with the \fB--config\fR +option, use \fIname\fR as the bridge identifier to look for applicable +lines. + .SS "Controller Discovery Options" .TP \fB--accept-vconn=\fIregex\fR @@ -235,7 +254,7 @@ When controller discovery is not performed, this option has no effect. .SS "Networking Options" .TP -\fB-F\fR, \fB--fail=\fR[\fBopen\fR|\fBclosed\fR] +\fB--fail=\fR[\fBopen\fR|\fBclosed\fR] The controller is, ordinarily, responsible for setting up all flows on the OpenFlow switch. Thus, if the connection to the controller fails, no new network connections can be set up. If the connection to the @@ -366,11 +385,6 @@ at the switch. The default is \fB--no-stp\fR in this distribution, because bugs in the STP implementation are still being worked out. The default will change to \fB--stp\fR at some point in the future. -.TP -\fB--netflow=\fIhost\fB:\fIport\fR -When flows end on the switch, send NetFlow v5 messages to -\fIhost\fR on UDP \fIport\fR. - .SS "Rate-Limiting Options" These options configure how the switch applies a ``token bucket'' to @@ -481,4 +495,5 @@ require the controller to send the CA certificate, but .BR controller (8), .BR ofp-pki (8), .BR udatapath (8), -.BR vlogconf (8) +.BR vlogconf (8), +.BR vswitchd.conf (5), diff --git a/secchan/secchan.c b/secchan/secchan.c index c17d02ca..a7fd4638 100644 --- a/secchan/secchan.c +++ b/secchan/secchan.c @@ -41,6 +41,7 @@ #include #include +#include "cfg.h" #include "command-line.h" #include "compiler.h" #include "daemon.h" @@ -59,6 +60,7 @@ #include "poll-loop.h" #include "ratelimit.h" #include "rconn.h" +#include "signals.h" #ifdef SUPPORT_SNAT #include "snat.h" #endif @@ -86,6 +88,7 @@ struct secchan { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 60); +static void reconfigure(struct secchan *); static void parse_options(int argc, char *argv[], struct settings *); static void usage(void) NO_RETURN; @@ -115,6 +118,7 @@ main(int argc, char *argv[]) struct pvconn *listeners[MAX_MGMT]; size_t n_listeners; + struct signal *sighup; char *local_rconn_name; struct rconn *async_rconn, *local_rconn, *remote_rconn; struct relay *controller_relay; @@ -130,6 +134,7 @@ main(int argc, char *argv[]) vlog_init(); parse_options(argc, argv, &s); signal(SIGPIPE, SIG_IGN); + sighup = signal_register(SIGHUP); secchan.hooks = NULL; secchan.n_hooks = 0; @@ -214,7 +219,7 @@ main(int argc, char *argv[]) #ifdef SUPPORT_SNAT snat_start(&secchan, pw); #endif - flow_end_start(&secchan, s.netflow_dst, local_rconn, remote_rconn); + flow_end_start(&secchan, &s, local_rconn, remote_rconn); if (s.enable_stp) { stp_start(&secchan, pw, local_rconn, remote_rconn); } @@ -232,10 +237,16 @@ main(int argc, char *argv[]) executer_start(&secchan, &s); } + reconfigure(&secchan); + while (s.discovery || rconn_is_alive(remote_rconn)) { struct relay *r, *n; size_t i; + if (signal_poll(sighup)) { + reconfigure(&secchan); + } + /* Do work. */ LIST_FOR_EACH_SAFE (r, n, struct relay, node, &relays) { relay_run(r, &secchan); @@ -294,12 +305,26 @@ main(int argc, char *argv[]) if (discovery) { discovery_wait(discovery); } + signal_wait(sighup); poll_block(); } return 0; } +static void +reconfigure(struct secchan *secchan) +{ + int i; + + cfg_read(); + for (i = 0; i < secchan->n_hooks; i++) { + if (secchan->hooks[i].class->reconfigure_cb) { + secchan->hooks[i].class->reconfigure_cb(secchan->hooks[i].aux); + } + } +} + static struct pvconn * open_passive_vconn(const char *name) { @@ -578,6 +603,8 @@ parse_options(int argc, char *argv[], struct settings *s) enum { OPT_ACCEPT_VCONN = UCHAR_MAX + 1, OPT_NO_RESOLV_CONF, + OPT_BR_NAME, + OPT_FAIL_MODE, OPT_INACTIVITY_PROBE, OPT_MAX_IDLE, OPT_MAX_BACKOFF, @@ -590,14 +617,15 @@ parse_options(int argc, char *argv[], struct settings *s) OPT_IN_BAND, OPT_COMMAND_ACL, OPT_COMMAND_DIR, - OPT_NETFLOW, VLOG_OPTION_ENUMS, LEAK_CHECKER_OPTION_ENUMS }; static struct option long_options[] = { {"accept-vconn", required_argument, 0, OPT_ACCEPT_VCONN}, {"no-resolv-conf", no_argument, 0, OPT_NO_RESOLV_CONF}, - {"fail", required_argument, 0, 'F'}, + {"config", required_argument, 0, 'F'}, + {"br-name", required_argument, 0, OPT_BR_NAME}, + {"fail", required_argument, 0, OPT_FAIL_MODE}, {"inactivity-probe", required_argument, 0, OPT_INACTIVITY_PROBE}, {"max-idle", required_argument, 0, OPT_MAX_IDLE}, {"max-backoff", required_argument, 0, OPT_MAX_BACKOFF}, @@ -611,7 +639,6 @@ parse_options(int argc, char *argv[], struct settings *s) {"in-band", no_argument, 0, OPT_IN_BAND}, {"command-acl", required_argument, 0, OPT_COMMAND_ACL}, {"command-dir", required_argument, 0, OPT_COMMAND_DIR}, - {"netflow", required_argument, 0, OPT_NETFLOW}, {"verbose", optional_argument, 0, 'v'}, {"help", no_argument, 0, 'h'}, {"version", no_argument, 0, 'V'}, @@ -642,8 +669,8 @@ parse_options(int argc, char *argv[], struct settings *s) s->in_band = true; s->command_acl = ""; s->command_dir = xasprintf("%s/commands", ofp_pkgdatadir); - s->netflow_dst = NULL; for (;;) { + int error; int c; c = getopt_long(argc, argv, short_options, long_options, NULL); @@ -656,11 +683,15 @@ parse_options(int argc, char *argv[], struct settings *s) accept_re = optarg[0] == '^' ? optarg : xasprintf("^%s", optarg); break; + case OPT_BR_NAME: + s->br_name = optarg; + break; + case OPT_NO_RESOLV_CONF: s->update_resolv_conf = false; break; - case 'F': + case OPT_FAIL_MODE: if (!strcmp(optarg, "open")) { s->fail_mode = FAIL_OPEN; } else if (!strcmp(optarg, "closed")) { @@ -743,11 +774,12 @@ parse_options(int argc, char *argv[], struct settings *s) s->command_dir = optarg; break; - case OPT_NETFLOW: - if (s->netflow_dst) { - ofp_fatal(0, "--netflow may only be specified once"); + case 'F': + error = cfg_add_file(optarg); + if (error) { + ofp_fatal(error, "failed to add configuration file or " + "directory \"%s\"", optarg); } - s->netflow_dst = optarg; break; case 'l': @@ -852,11 +884,14 @@ usage(void) "omitted, then secchan performs controller discovery.\n", program_name, program_name); vconn_usage(true, true, true); - printf("\nController discovery options:\n" + printf("\nConfiguration options:\n" + " -F, --config=FILE|DIR reads configuration from FILE or DIR\n" + " --br-name=NAME bridge name to use for configuration\n" + "\nController discovery options:\n" " --accept-vconn=REGEX accept matching discovered controllers\n" " --no-resolv-conf do not update /etc/resolv.conf\n" "\nNetworking options:\n" - " -F, --fail=open|closed when controller connection fails:\n" + " --fail=open|closed when controller connection fails:\n" " closed: drop all packets\n" " open (default): act as learning switch\n" " --inactivity-probe=SECS time between inactivity probes\n" @@ -870,7 +905,6 @@ usage(void) " --out-of-band controller connection is out-of-band\n" " --stp enable 802.1D Spanning Tree Protocol\n" " --no-stp disable 802.1D Spanning Tree Protocol\n" - " --netflow=HOST:PORT send NetFlow v5 messages when flows end\n" "\nRate-limiting of \"packet-in\" messages to the controller:\n" " --rate-limit[=PACKETS] max rate, in packets/s (default: 1000)\n" " --burst-limit=BURST limit on packet credit for idle time\n" diff --git a/secchan/secchan.h b/secchan/secchan.h index b5948976..09439a0c 100644 --- a/secchan/secchan.h +++ b/secchan/secchan.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford +/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford * Junior University * * We are making the OpenFlow specification and associated documentation @@ -53,6 +53,9 @@ enum fail_mode { /* Settings that may be configured by the user. */ struct settings { + /* Configuration. */ + const char *br_name; /* Bridge name to use for configuration lookup */ + /* Overall mode of operation. */ bool discovery; /* Discover the controller automatically? */ bool in_band; /* Connect to controller in-band? */ @@ -85,9 +88,6 @@ struct settings { /* Remote command execution. */ char *command_acl; /* Command white/blacklist, as shell globs. */ char *command_dir; /* Directory that contains commands. */ - - /* NetFlow logging. */ - char *netflow_dst; /* Host and port to send NetFlow traffic. */ }; struct half { @@ -123,6 +123,7 @@ struct hook_class { void (*periodic_cb)(void *aux); void (*wait_cb)(void *aux); void (*closing_cb)(struct relay *, void *aux); + void (*reconfigure_cb)(void *aux); }; void add_hook(struct secchan *, const struct hook_class *, void *); diff --git a/secchan/snat.c b/secchan/snat.c index b27372cb..310a9069 100644 --- a/secchan/snat.c +++ b/secchan/snat.c @@ -271,6 +271,7 @@ static struct hook_class snat_hook_class = { NULL, /* periodic_cb */ NULL, /* wait_cb */ NULL, /* closing_cb */ + NULL, /* reconfigure_cb */ }; void diff --git a/secchan/status.c b/secchan/status.c index cf228123..c3e95aff 100644 --- a/secchan/status.c +++ b/secchan/status.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford +/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford * Junior University * * We are making the OpenFlow specification and associated documentation @@ -171,6 +171,7 @@ static struct hook_class switch_status_hook_class = { NULL, /* periodic_cb */ NULL, /* wait_cb */ NULL, /* closing_cb */ + NULL, /* reconfigure_cb */ }; void diff --git a/secchan/stp-secchan.c b/secchan/stp-secchan.c index 152595e9..3e8a7d77 100644 --- a/secchan/stp-secchan.c +++ b/secchan/stp-secchan.c @@ -269,6 +269,7 @@ static struct hook_class stp_hook_class = { stp_periodic_cb, /* periodic_cb */ stp_wait_cb, /* wait_cb */ NULL, /* closing_cb */ + NULL, /* reconfigure_cb */ }; void diff --git a/vswitchd/automake.mk b/vswitchd/automake.mk index cc87027e..e6c68b8c 100644 --- a/vswitchd/automake.mk +++ b/vswitchd/automake.mk @@ -8,8 +8,6 @@ vswitchd_vswitchd_SOURCES = \ vswitchd/brcompat.h \ vswitchd/bridge.c \ vswitchd/bridge.h \ - vswitchd/cfg.c \ - vswitchd/cfg.h \ vswitchd/flowtrack.c \ vswitchd/flowtrack.h \ vswitchd/stats.c \ diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c index f4f351c0..d4289981 100644 --- a/vswitchd/bridge.c +++ b/vswitchd/bridge.c @@ -68,6 +68,8 @@ #define THIS_MODULE VLM_bridge #include "vlog.h" +extern struct svec config_files; + struct iface { struct port *port; /* Containing port. */ size_t port_ifidx; /* Index within containing port. */ @@ -149,10 +151,6 @@ struct bridge { bool sent_config_request; /* Successfully sent config request? */ bool sent_features_request; /* Successfully sent features request? */ - /* Support for NetFlow. */ - char *netflow_host; /* NULL if no NetFlow logging; otherwise a - * "host:port" string. */ - /* Support for remote controllers. */ char *controller; /* NULL if there is no remote controller; * "discover" to do controller discovery; @@ -509,6 +507,14 @@ log_secchan_died(enum vlog_level level, struct bridge *br, bool expected) free(status); } +static void +hup_secchan(struct bridge *br) +{ + if (br->sc_state == SC_RUNNING) { + process_kill(br->secchan, SIGHUP); + } +} + static void kill_secchan(struct bridge *br) { @@ -566,6 +572,7 @@ console_logging_enabled(void) static void start_secchan(struct bridge *br) { + int i; struct svec argv; int sockets[2]; struct stat s; @@ -610,6 +617,11 @@ start_secchan(struct bridge *br) /* Assemble command-line arguments. */ svec_init(&argv); svec_add(&argv, "secchan"); + svec_add_nocopy(&argv, xasprintf("--br-name=%s", br->name)); + for (i=0; iname, "%c|%p|%m")); @@ -622,9 +634,6 @@ start_secchan(struct bridge *br) svec_add_nocopy(&argv, xasprintf("--log-file=%s.secchan-%s", vlog_get_log_file(), br->name)); } - if (br->netflow_host) { - svec_add_nocopy(&argv, xasprintf("--netflow=%s", br->netflow_host)); - } if (!br->controller) { svec_add(&argv, "--out-of-band"); svec_add(&argv, "--max-backoff=1"); @@ -697,7 +706,6 @@ bridge_destroy(struct bridge *br) } process_destroy(br->secchan); rconn_destroy(br->rconn); - free(br->netflow_host); free(br->controller); svec_destroy(&br->secchan_opts); ft_destroy(br->ft); @@ -833,10 +841,8 @@ bridge_reconfigure_one(struct bridge *br) { struct svec old_ports, new_ports, ifaces; const char *controller; - const char *netflow_host; size_t i, j; char *ctl; - char *nf; /* Collect old and new ports. */ svec_init(&old_ports); @@ -914,17 +920,6 @@ bridge_reconfigure_one(struct bridge *br) free(br->controller); br->controller = ctl; - /* Configure NetFlow. */ - netflow_host = cfg_get_string(0, "netflow.%s.host", br->name); - nf = netflow_host ? xstrdup(netflow_host) : NULL; - if ((nf == NULL) != (br->netflow_host == NULL) - || (nf && br->netflow_host && strcmp(nf, br->netflow_host))) { - br->sc_retries = 0; - kill_secchan(br); - } - free(br->netflow_host); - br->netflow_host = nf; - /* Allow arbitrary secchan options if a remote controller is configured. */ svec_clear(&br->secchan_opts); if (ctl) { @@ -945,6 +940,9 @@ bridge_reconfigure_one(struct bridge *br) } mirror_reconfigure(br); + + /* Force secchan to reconfigure itself. */ + hup_secchan(br); } static void diff --git a/vswitchd/vswitchd.c b/vswitchd/vswitchd.c index c7e5c862..c83a22bf 100644 --- a/vswitchd/vswitchd.c +++ b/vswitchd/vswitchd.c @@ -45,6 +45,7 @@ #include "poll-loop.h" #include "process.h" #include "signals.h" +#include "svec.h" #include "timeval.h" #include "util.h" #include "vconn-ssl.h" @@ -60,6 +61,7 @@ static void usage(void) NO_RETURN; static void reconfigure(void); static bool brc_enabled = false; +struct svec config_files; int main(int argc, char *argv[]) @@ -71,6 +73,7 @@ main(int argc, char *argv[]) register_fault_handlers(); time_init(); vlog_init(); + svec_init(&config_files); parse_options(argc, argv); signal(SIGPIPE, SIG_IGN); sighup = signal_register(SIGHUP); @@ -156,6 +159,7 @@ parse_options(int argc, char *argv[]) case 'F': configured = true; + svec_add(&config_files, optarg); error = cfg_add_file(optarg); if (error) { ofp_fatal(error, "failed to add configuration file or " diff --git a/vswitchd/vswitchd.conf.5 b/vswitchd/vswitchd.conf.5 index 3d1bccad..d5a8c9ca 100644 --- a/vswitchd/vswitchd.conf.5 +++ b/vswitchd/vswitchd.conf.5 @@ -4,10 +4,10 @@ . ns . TP \$1 .. -.TH vswitchd.conf 5 "December 2008" "OpenFlow" "OpenFlow Manual" +.TH vswitchd.conf 5 "February 2009" "OpenFlow" "OpenFlow Manual" . .SH NAME -vswitchd.conf \- configuration file for \fBvswitchd.conf\fR +vswitchd.conf \- configuration file for \fBvswitchd\fR . .SH DESCRIPTION \fBvswitchd\fR(8), the virtual switch daemon, is configured using one @@ -337,10 +337,10 @@ set to 64: .SS "NetFlow v5 Flow Logging" NetFlow provides a number of details about terminating flows, such as the principals involved and duration. A bridge may be configured to send -NetFlow v5 records to a collector when flows end. To enable, define the -key \fBnetflow.\fIbridge\fB.host\fR to a NetFlow collector in the form -\fIhost\fB:\fIport\fR. Records from \fIbridge\fR will be sent to -\fIhost\fR on UDP \fIport\fR. +NetFlow v5 records to up to eight collectors when flows end. To enable, +define the key \fBnetflow.\fIbridge\fB.host\fR for each NetFlow collector +in the form \fIhost\fB:\fIport\fR. Records from \fIbridge\fR will be sent +to each \fIhost\fR on UDP \fIport\fR. .PP The following syntax sends NetFlow records for \fBmybr\fR to the NetFlow collector \fBnflow.example.com\fR on UDP port \fB9995\fR: -- 2.30.2