* derivatives without specific, written prior permission.
*/
+#include <config.h>
+
#include <errno.h>
#include <getopt.h>
+#include <limits.h>
+#include <signal.h>
#include <stdlib.h>
#include <string.h>
-#include "buffer.h"
#include "command-line.h"
#include "compiler.h"
+#include "daemon.h"
#include "fault.h"
#include "learning-switch.h"
+#include "ofpbuf.h"
+#include "openflow.h"
#include "poll-loop.h"
#include "rconn.h"
+#include "timeval.h"
#include "util.h"
#include "vconn-ssl.h"
#include "vconn.h"
/* Set up flows? (If not, every packet is processed at the controller.) */
static bool setup_flows = true;
+/* --max-idle: Maximum idle time, in seconds, before flows expire. */
+static int max_idle = 60;
+
static int do_switching(struct switch_ *);
static void new_switch(struct switch_ *, struct vconn *, const char *name);
static void parse_options(int argc, char *argv[]);
main(int argc, char *argv[])
{
struct switch_ switches[MAX_SWITCHES];
- struct vconn *listeners[MAX_LISTENERS];
+ struct pvconn *listeners[MAX_LISTENERS];
int n_switches, n_listeners;
int retval;
int i;
set_program_name(argv[0]);
register_fault_handlers();
+ time_init();
vlog_init();
parse_options(argc, argv);
+ signal(SIGPIPE, SIG_IGN);
if (argc - optind < 1) {
- fatal(0, "at least one vconn argument required; use --help for usage");
+ ofp_fatal(0, "at least one vconn argument required; "
+ "use --help for usage");
}
retval = vlog_server_listen(NULL, NULL);
if (retval) {
- fatal(retval, "Could not listen for vlog connections");
+ ofp_fatal(retval, "Could not listen for vlog connections");
}
n_switches = n_listeners = 0;
struct vconn *vconn;
int retval;
- retval = vconn_open(name, &vconn);
- if (retval) {
- VLOG_ERR("%s: connect: %s", name, strerror(retval));
- continue;
- }
-
- if (vconn_is_passive(vconn)) {
- if (n_listeners >= MAX_LISTENERS) {
- fatal(0, "max %d passive connections", n_listeners);
- }
- listeners[n_listeners++] = vconn;
- } else {
+ retval = vconn_open(name, OFP_VERSION, &vconn);
+ if (!retval) {
if (n_switches >= MAX_SWITCHES) {
- fatal(0, "max %d switch connections", n_switches);
+ ofp_fatal(0, "max %d switch connections", n_switches);
}
new_switch(&switches[n_switches++], vconn, name);
+ continue;
+ } else if (retval == EAFNOSUPPORT) {
+ struct pvconn *pvconn;
+ retval = pvconn_open(name, &pvconn);
+ if (!retval) {
+ if (n_listeners >= MAX_LISTENERS) {
+ ofp_fatal(0, "max %d passive connections", n_listeners);
+ }
+ listeners[n_listeners++] = pvconn;
+ }
+ }
+ if (retval) {
+ VLOG_ERR("%s: connect: %s", name, strerror(retval));
}
}
if (n_switches == 0 && n_listeners == 0) {
- fatal(0, "no active or passive switch connections");
+ ofp_fatal(0, "no active or passive switch connections");
}
+ die_if_already_running();
+ daemonize();
+
while (n_switches > 0 || n_listeners > 0) {
int iteration;
int i;
struct vconn *new_vconn;
int retval;
- retval = vconn_accept(listeners[i], &new_vconn);
+ retval = pvconn_accept(listeners[i], OFP_VERSION, &new_vconn);
if (!retval || retval == EAGAIN) {
if (!retval) {
new_switch(&switches[n_switches++], new_vconn, "tcp");
}
i++;
} else {
- vconn_close(listeners[i]);
+ pvconn_close(listeners[i]);
listeners[i] = listeners[--n_listeners];
}
}
/* Wait for something to happen. */
if (n_switches < MAX_SWITCHES) {
for (i = 0; i < n_listeners; i++) {
- vconn_accept_wait(listeners[i]);
+ pvconn_wait(listeners[i]);
}
}
for (i = 0; i < n_switches; i++) {
static void
new_switch(struct switch_ *sw, struct vconn *vconn, const char *name)
{
- sw->rconn = rconn_new_from_vconn(name, 128, vconn);
- sw->lswitch = lswitch_create(sw->rconn, learn_macs, setup_flows);
+ sw->rconn = rconn_new_from_vconn(name, vconn);
+ sw->lswitch = lswitch_create(sw->rconn, learn_macs,
+ setup_flows ? max_idle : -1);
}
static int
do_switching(struct switch_ *sw)
{
unsigned int packets_sent;
- struct buffer *msg;
+ struct ofpbuf *msg;
packets_sent = rconn_packets_sent(sw->rconn);
msg = rconn_recv(sw->rconn);
if (msg) {
lswitch_process_packet(sw->lswitch, sw->rconn, msg);
- buffer_delete(msg);
+ ofpbuf_delete(msg);
}
rconn_run(sw->rconn);
static void
parse_options(int argc, char *argv[])
{
+ enum {
+ OPT_MAX_IDLE = UCHAR_MAX + 1,
+ OPT_PEER_CA_CERT
+ };
static struct option long_options[] = {
+ {"detach", no_argument, 0, 'D'},
+ {"pidfile", optional_argument, 0, 'P'},
+ {"force", no_argument, 0, 'f'},
{"hub", no_argument, 0, 'H'},
{"noflow", no_argument, 0, 'n'},
+ {"max-idle", required_argument, 0, OPT_MAX_IDLE},
{"verbose", optional_argument, 0, 'v'},
{"help", no_argument, 0, 'h'},
{"version", no_argument, 0, 'V'},
+#ifdef HAVE_OPENSSL
VCONN_SSL_LONG_OPTIONS
+ {"peer-ca-cert", required_argument, 0, OPT_PEER_CA_CERT},
+#endif
{0, 0, 0, 0},
};
char *short_options = long_options_to_short_options(long_options);
}
switch (c) {
+ case 'D':
+ set_detach();
+ break;
+
+ case 'P':
+ set_pidfile(optarg);
+ break;
+
+ case 'f':
+ ignore_existing_pidfile();
+ break;
+
case 'H':
learn_macs = false;
break;
setup_flows = false;
break;
+ case OPT_MAX_IDLE:
+ if (!strcmp(optarg, "permanent")) {
+ max_idle = OFP_FLOW_PERMANENT;
+ } else {
+ max_idle = atoi(optarg);
+ if (max_idle < 1 || max_idle > 65535) {
+ ofp_fatal(0, "--max-idle argument must be between 1 and "
+ "65535 or the word 'permanent'");
+ }
+ }
+ break;
+
case 'h':
usage();
vlog_set_verbosity(optarg);
break;
+#ifdef HAVE_OPENSSL
VCONN_SSL_OPTION_HANDLERS
+ case OPT_PEER_CA_CERT:
+ vconn_ssl_set_peer_ca_cert_file(optarg);
+ break;
+#endif
+
case '?':
exit(EXIT_FAILURE);
"usage: %s [OPTIONS] METHOD\n"
"where METHOD is any OpenFlow connection method.\n",
program_name, program_name);
- vconn_usage(true, true);
+ vconn_usage(true, true, false);
printf("\nOther options:\n"
+ " -D, --detach run in background as daemon\n"
+ " -P, --pidfile[=FILE] create pidfile (default: %s/controller.pid)\n"
+ " -f, --force with -P, start even if already running\n"
" -H, --hub act as hub instead of learning switch\n"
" -n, --noflow pass traffic, but don't add flows\n"
+ " --max-idle=SECS max idle time for new flows\n"
+ " -v, --verbose=MODULE[:FACILITY[:LEVEL]] set logging levels\n"
" -v, --verbose set maximum verbosity level\n"
" -h, --help display this help message\n"
- " -V, --version display version information\n");
+ " -V, --version display version information\n",
+ RUNDIR);
exit(EXIT_SUCCESS);
}