#include <config.h>
#include "discovery.h"
+#include <errno.h>
#include <inttypes.h>
#include <regex.h>
#include <stdlib.h>
#include "openflow/openflow.h"
#include "packets.h"
#include "status.h"
+#include "vconn-ssl.h"
#define THIS_MODULE VLM_discovery
#include "vlog.h"
struct discovery {
- const char *accept_controller_re;
+ char *re;
bool update_resolv_conf;
- regex_t accept_controller_regex;
+ regex_t *regex;
struct dhclient *dhcp;
int n_changes;
+ struct status_category *ss_cat;
};
static void modify_dhcp_request(struct dhcp_msg *, void *aux);
{
struct discovery *d = d_;
- status_reply_put(sr, "accept-remote=%s", d->accept_controller_re);
+ status_reply_put(sr, "accept-remote=%s", d->re);
status_reply_put(sr, "n-changes=%d", d->n_changes);
if (d->dhcp) {
status_reply_put(sr, "state=%s", dhclient_get_state(d->dhcp));
}
}
-struct discovery *
-discovery_create(const char *accept_controller_re, bool update_resolv_conf,
- struct dpif *dpif, struct switch_status *ss)
+int
+discovery_create(const char *re, bool update_resolv_conf,
+ struct dpif *dpif, struct switch_status *ss,
+ struct discovery **discoveryp)
{
struct discovery *d;
struct odp_port port;
d = xcalloc(1, sizeof *d);
/* Controller regular expression. */
- d->accept_controller_re = accept_controller_re;
- error = regcomp(&d->accept_controller_regex, accept_controller_re,
- REG_NOSUB | REG_EXTENDED);
+ error = discovery_set_accept_controller_re(d, re);
if (error) {
- size_t length = regerror(error, &d->accept_controller_regex, NULL, 0);
- char *buffer = xmalloc(length);
- regerror(error, &d->accept_controller_regex, buffer, length);
- ofp_fatal(0, "%s: %s", accept_controller_re, buffer);
+ goto error_free;
}
d->update_resolv_conf = update_resolv_conf;
/* Initialize DHCP client. */
error = dpif_port_query_by_number(dpif, ODPP_LOCAL, &port);
if (error) {
- ofp_fatal(error, "failed to query datapath local port");
+ VLOG_ERR("failed to query datapath local port: %s", strerror(error));
+ goto error_regfree;
}
error = dhclient_create(port.devname, modify_dhcp_request,
validate_dhcp_offer, d, &d->dhcp);
if (error) {
- ofp_fatal(error, "failed to initialize DHCP client");
+ VLOG_ERR("failed to initialize DHCP client: %s", strerror(error));
+ goto error_regfree;
}
dhclient_set_max_timeout(d->dhcp, 3);
dhclient_init(d->dhcp, 0);
- switch_status_register_category(ss, "discovery", discovery_status_cb, d);
+ d->ss_cat = switch_status_register(ss, "discovery",
+ discovery_status_cb, d);
+
+ *discoveryp = d;
+ return 0;
- return d;
+error_regfree:
+ regfree(d->regex);
+ free(d->regex);
+error_free:
+ free(d);
+ *discoveryp = 0;
+ return error;
}
void
discovery_destroy(struct discovery *d)
{
if (d) {
- /* We don't own d->accept_controller_re. */
- regfree(&d->accept_controller_regex);
+ free(d->re);
+ regfree(d->regex);
+ free(d->regex);
dhclient_destroy(d->dhcp);
+ switch_status_unregister(d->ss_cat);
free(d);
}
}
+void
+discovery_set_update_resolv_conf(struct discovery *d,
+ bool update_resolv_conf)
+{
+ d->update_resolv_conf = update_resolv_conf;
+}
+
+int
+discovery_set_accept_controller_re(struct discovery *d, const char *re_)
+{
+ regex_t *regex;
+ int error;
+ char *re;
+
+ re = (!re_ ? xstrdup(vconn_ssl_is_configured() ? "^ssl:.*" : ".*")
+ : re_[0] == '^' ? xstrdup(re_) : xasprintf("^%s", re_));
+ regex = xmalloc(sizeof *regex);
+ error = regcomp(regex, re, REG_NOSUB | REG_EXTENDED);
+ if (error) {
+ size_t length = regerror(error, regex, NULL, 0);
+ char *buffer = xmalloc(length);
+ regerror(error, regex, buffer, length);
+ VLOG_WARN("%s: %s", re, buffer);
+ free(regex);
+ free(re);
+ return EINVAL;
+ } else {
+ if (d->regex) {
+ regfree(d->regex);
+ free(d->regex);
+ }
+ free(d->re);
+
+ d->regex = regex;
+ d->re = re;
+ return 0;
+ }
+}
+
void
discovery_question_connectivity(struct discovery *d)
{
VLOG_WARN_RL(&rl, "rejecting DHCP offer missing controller vconn");
return false;
}
- accept = !regexec(&d->accept_controller_regex, vconn_name, 0, NULL,
- 0);
+ accept = !regexec(d->regex, vconn_name, 0, NULL, 0);
if (!accept) {
VLOG_WARN_RL(&rl, "rejecting controller vconn that fails to match %s",
- d->accept_controller_re);
+ d->re);
}
free(vconn_name);
return accept;
#include <stdbool.h>
struct dpif;
+struct discovery;
struct settings;
struct switch_status;
-struct discovery *discovery_create(const char *accept_controller_re,
- bool update_resolv_conf,
- struct dpif *, struct switch_status *);
+int discovery_create(const char *accept_controller_re, bool update_resolv_conf,
+ struct dpif *, struct switch_status *,
+ struct discovery **);
void discovery_destroy(struct discovery *);
+void discovery_set_update_resolv_conf(struct discovery *,
+ bool update_resolv_conf);
+int discovery_set_accept_controller_re(struct discovery *, const char *re);
void discovery_question_connectivity(struct discovery *);
bool discovery_run(struct discovery *, char **controller_name);
void discovery_wait(struct discovery *);
struct executer {
/* Settings. */
- const char *command_acl; /* Command white/blacklist, as shell globs. */
- const char *command_dir; /* Directory that contains commands. */
+ char *command_acl; /* Command white/blacklist, as shell globs. */
+ char *command_dir; /* Directory that contains commands. */
/* Children. */
struct child children[MAX_CHILDREN];
write(signal_fds[1], "", 1);
}
-struct executer *
-executer_create(const char *command_acl, const char *command_dir)
+int
+executer_create(const char *command_acl, const char *command_dir,
+ struct executer **executerp)
{
struct executer *e;
struct sigaction sa;
+ *executerp = NULL;
if (null_fd == -1) {
/* Create pipe for notifying us that SIGCHLD was invoked. */
if (pipe(signal_fds)) {
- ofp_fatal(errno, "pipe failed");
+ VLOG_ERR("pipe failed: %s", strerror(errno));
+ return errno;
}
set_nonblocking(signal_fds[0]);
set_nonblocking(signal_fds[1]);
/* Open /dev/null. */
null_fd = open("/dev/null", O_RDWR);
if (null_fd < 0) {
- ofp_fatal(errno, "could not open /dev/null");
+ int error = errno;
+ VLOG_ERR("could not open /dev/null: %s", strerror(error));
+ close(signal_fds[0]);
+ close(signal_fds[1]);
+ return error;
}
}
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_NOCLDSTOP | SA_RESTART;
if (sigaction(SIGCHLD, &sa, NULL)) {
- ofp_fatal(errno, "sigaction(SIGCHLD) failed");
+ VLOG_ERR("sigaction(SIGCHLD) failed: %s", strerror(errno));
+ return errno;
}
e = xcalloc(1, sizeof *e);
- e->command_acl = command_acl;
- e->command_dir = command_dir;
+ e->command_acl = xstrdup(command_acl);
+ e->command_dir = xstrdup(command_dir);
e->n_children = 0;
- return e;
+ *executerp = e;
+ return 0;
}
void
if (e) {
size_t i;
- /* We don't own e->command_acl or e->command_dir. */
+ free(e->command_acl);
+ free(e->command_dir);
for (i = 0; i < e->n_children; i++) {
struct child *child = &e->children[i];
free(e);
}
}
+
+void
+executer_set_acl(struct executer *e, const char *acl, const char *dir)
+{
+ free(e->command_acl);
+ e->command_acl = xstrdup(acl);
+ free(e->command_dir);
+ e->command_dir = xstrdup(dir);
+}
#ifndef EXECUTER_H
#define EXECUTER_H 1
+struct executer;
struct nicira_header;
struct rconn;
-struct executer *executer_create(const char *command_acl,
- const char *command_dir);
+int executer_create(const char *acl, const char *dir, struct executer **);
+void executer_set_acl(struct executer *, const char *acl, const char *dir);
void executer_destroy(struct executer *);
void executer_run(struct executer *);
void executer_wait(struct executer *);
int trigger_duration;
int last_disconn_secs;
struct mac_learning *mac_learning;
+ struct status_category *ss_cat;
};
/* Causes 'r' to enter or leave fail-open mode, if appropriate. */
-
void
fail_open_run(struct fail_open *fo)
{
fo->trigger_duration = trigger_duration;
fo->last_disconn_secs = 0;
fo->mac_learning = NULL;
- switch_status_register_category(switch_status, "fail-open",
- fail_open_status_cb, fo);
+ fo->ss_cat = switch_status_register(switch_status, "fail-open",
+ fail_open_status_cb, fo);
return fo;
}
+void
+fail_open_set_trigger_duration(struct fail_open *fo, int trigger_duration)
+{
+ fo->trigger_duration = trigger_duration;
+}
+
void
fail_open_destroy(struct fail_open *fo)
{
if (fo) {
/* We don't own fo->controller. */
mac_learning_destroy(fo->mac_learning);
+ switch_status_unregister(fo->ss_cat);
free(fo);
}
}
struct fail_open *fail_open_create(int trigger_duration,
struct switch_status *,
struct rconn *controller);
+void fail_open_set_trigger_duration(struct fail_open *, int trigger_duration);
void fail_open_destroy(struct fail_open *);
void fail_open_wait(struct fail_open *);
void fail_open_run(struct fail_open *);
struct mac_learning *mac_learning;
struct netdev *netdev;
struct rconn *controller;
+ struct status_category *ss_cat;
};
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 60);
mac_learning_wait(in_band->mac_learning);
}
-struct in_band *
+int
in_band_create(struct dpif *dpif, struct switch_status *ss,
- struct rconn *controller)
+ struct rconn *controller, struct in_band **in_bandp)
{
struct in_band *in_band;
struct netdev *netdev;
struct odp_port port;
int error;
+ *in_bandp = NULL;
error = dpif_port_query_by_number(dpif, ODPP_LOCAL, &port);
if (error) {
- ofp_fatal(error, "failed to query datapath local port");
+ VLOG_ERR("failed to query datapath local port: %s", strerror(error));
+ return error;
}
error = netdev_open(port.devname, NETDEV_ETH_TYPE_NONE, &netdev);
if (error) {
- ofp_fatal(error, "failed to open %s network device", port.devname);
+ VLOG_ERR("failed to open %s network device: %s",
+ port.devname, strerror(error));
+ return error;
}
in_band = xcalloc(1, sizeof *in_band);
in_band->mac_learning = mac_learning_create();
in_band->netdev = netdev;
in_band->controller = controller;
- switch_status_register_category(ss, "in-band", in_band_status_cb, in_band);
+ in_band->ss_cat = switch_status_register(ss, "in-band",
+ in_band_status_cb, in_band);
- return in_band;
+ *in_bandp = in_band;
+ return 0;
}
-
void
in_band_destroy(struct in_band *in_band)
{
if (in_band) {
mac_learning_destroy(in_band->mac_learning);
netdev_close(in_band->netdev);
+ switch_status_unregister(in_band->ss_cat);
/* We don't own the rconn. */
}
}
#include "flow.h"
struct dpif;
+struct in_band;
struct ofproto;
struct rconn;
struct secchan;
struct settings;
struct switch_status;
-struct in_band *in_band_create(struct dpif *, struct switch_status *,
- struct rconn *controller);
+int in_band_create(struct dpif *, struct switch_status *,
+ struct rconn *controller, struct in_band **);
void in_band_destroy(struct in_band *);
void in_band_run(struct in_band *);
void in_band_wait(struct in_band *);
#include "rconn.h"
#include "signals.h"
#include "status.h"
+#include "svec.h"
#include "timeval.h"
#include "util.h"
#include "vconn-ssl.h"
#include "vlog.h"
#define THIS_MODULE VLM_secchan
-static void reconfigure(struct ofproto *);
+/* Behavior when the connection to the controller fails. */
+enum fail_mode {
+ FAIL_OPEN, /* Act as learning switch. */
+ FAIL_CLOSED /* Drop all packets. */
+};
+
+/* Settings that may be configured by the user. */
+struct ofsettings {
+ /* 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? */
+
+ /* Datapath. */
+ uint64_t datapath_id; /* Datapath ID. */
+ const char *dp_name; /* Name of local datapath. */
+
+ /* Description strings. */
+ const char *mfr_desc; /* Manufacturer. */
+ const char *hw_desc; /* Hardware. */
+ const char *sw_desc; /* Software version. */
+ const char *serial_desc; /* Serial number. */
+
+ /* Related vconns and network devices. */
+ const char *controller_name; /* Controller (if not discovery mode). */
+ struct svec listeners; /* Listen for management connections. */
+
+ /* Failure behavior. */
+ enum fail_mode fail_mode; /* Act as learning switch if no controller? */
+ int max_idle; /* Idle time for flows in fail-open mode. */
+ int probe_interval; /* # seconds idle before sending echo request. */
+ int max_backoff; /* Max # seconds between connection attempts. */
+
+ /* Packet-in rate-limiting. */
+ int rate_limit; /* Tokens added to bucket per second. */
+ int burst_limit; /* Maximum number token bucket size. */
+
+ /* Discovery behavior. */
+ const char *accept_controller_re; /* Controller vconns to accept. */
+ bool update_resolv_conf; /* Update /etc/resolv.conf? */
+
+ /* Spanning tree protocol. */
+ bool enable_stp;
+
+ /* Remote command execution. */
+ char *command_acl; /* Command white/blacklist, as shell globs. */
+ char *command_dir; /* Directory that contains commands. */
+};
+
+static void reconfigure(struct ofproto *, const char *br_name);
static void parse_options(int argc, char *argv[], struct ofsettings *);
static void usage(void) NO_RETURN;
struct signal *sighup;
struct ofproto *ofproto;
struct ofsettings s;
- int retval;
+ int error;
set_program_name(argv[0]);
register_fault_handlers();
daemonize();
/* Start listening for vlogconf requests. */
- retval = vlog_server_listen(NULL, NULL);
- if (retval) {
- ofp_fatal(retval, "Could not listen for vlog connections");
+ error = vlog_server_listen(NULL, NULL);
+ if (error) {
+ ofp_fatal(error, "Could not listen for vlog connections");
}
VLOG_INFO("OpenFlow reference implementation version %s", VERSION BUILDNR);
VLOG_INFO("OpenFlow protocol version 0x%02x", OFP_VERSION);
/* Start OpenFlow processing. */
- ofproto = ofproto_create(&s);
+ error = ofproto_create(s.dp_name, &ofproto);
+ if (error) {
+ ofp_fatal(error, "could not initialize openflow switch");
+ }
+ error = ofproto_set_in_band(ofproto, s.in_band);
+ if (error) {
+ ofp_fatal(error, "failed to configure in-band control");
+ }
+ error = ofproto_set_discovery(ofproto, s.discovery, s.accept_controller_re,
+ s.update_resolv_conf);
+ if (error) {
+ ofp_fatal(error, "failed to configure controller discovery");
+ }
+ if (s.datapath_id) {
+ ofproto_set_datapath_id(ofproto, s.datapath_id);
+ }
+ ofproto_set_desc(ofproto, s.mfr_desc, s.hw_desc, s.sw_desc, s.serial_desc);
+ error = ofproto_set_listeners(ofproto, &s.listeners);
+ if (error) {
+ ofp_fatal(error, "failed to configure management connections");
+ }
+ ofproto_set_failure(ofproto, s.fail_mode == FAIL_OPEN);
+ ofproto_set_probe_interval(ofproto, s.probe_interval);
+ ofproto_set_max_backoff(ofproto, s.max_backoff);
+ ofproto_set_rate_limit(ofproto, s.rate_limit, s.burst_limit);
+ error = ofproto_set_stp(ofproto, s.enable_stp);
+ if (error) {
+ ofp_fatal(error, "failed to configure STP");
+ }
+ error = ofproto_set_remote_execution(ofproto, s.command_acl,
+ s.command_dir);
+ if (error) {
+ ofp_fatal(error, "failed to configure remote command execution");
+ }
+ if (!s.discovery) {
+ error = ofproto_set_controller(ofproto, s.controller_name);
+ if (error) {
+ ofp_fatal(error, "failed to configure controller");
+ }
+ }
- reconfigure(ofproto);
+ reconfigure(ofproto, s.br_name);
while (ofproto_is_alive(ofproto)) {
if (signal_poll(sighup)) {
- reconfigure(ofproto);
+ reconfigure(ofproto, s.br_name);
}
/* Do work. */
}
static void
-reconfigure(struct ofproto *ofproto)
+reconfigure(struct ofproto *ofproto, const char *br_name)
{
cfg_read();
- ofproto_reconfigure(ofproto);
+ if (br_name) {
+ struct svec collectors;
+
+ svec_init(&collectors);
+ cfg_get_all_keys(&collectors, "netflow.%s.host", br_name);
+ ofproto_set_netflow(ofproto, &collectors);
+ svec_destroy(&collectors);
+ }
}
\f
/* User interface. */
/* Set defaults that we can figure out before parsing options. */
s->br_name = NULL;
s->datapath_id = 0;
- s->mfr_desc = "Nicira Networks, Inc.";
- s->hw_desc = "Reference Implementation";
- s->sw_desc = VERSION BUILDNR;
- s->serial_desc = "None";
- s->n_listeners = 0;
+ s->mfr_desc = NULL;
+ s->hw_desc = NULL;
+ s->sw_desc = NULL;
+ s->serial_desc = NULL;
+ svec_init(&s->listeners);
s->fail_mode = FAIL_OPEN;
- s->max_idle = 15;
- s->probe_interval = 15;
- s->max_backoff = 15;
+ s->max_idle = 0;
+ s->probe_interval = 0;
+ s->max_backoff = 0;
s->update_resolv_conf = true;
s->rate_limit = 0;
s->burst_limit = 0;
break;
case OPT_ACCEPT_VCONN:
- s->accept_controller_re = (optarg[0] == '^' ? optarg
- : xasprintf("^%s", optarg));
+ s->accept_controller_re = optarg;
break;
case OPT_BR_NAME:
break;
case 'l':
- if (s->n_listeners >= MAX_MGMT) {
- ofp_fatal(0,
- "-l or --listen may be specified at most %d times",
- MAX_MGMT);
- }
- s->listener_names[s->n_listeners++] = optarg;
+ svec_add(&s->listeners, optarg);
break;
case 'h':
};
BUILD_ASSERT_DECL(sizeof(struct netflow_v5_record) == 48);
-#define MAX_COLLECTORS 8
-
struct netflow {
- const char *br_name; /* Bridge name, for reading config file. */
long long int boot_time; /* Time when netflow_create() was called. */
- int netflow_fds[MAX_COLLECTORS]; /* Sockets for NetFlow collectors. */
+ int *fds; /* Sockets for NetFlow collectors. */
+ size_t n_fds; /* Number of Netflow collectors. */
uint32_t netflow_cnt; /* Flow sequence number for NetFlow. */
};
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
static int
-udp_open(char *dst)
+open_collector(char *dst)
{
char *save_ptr;
const char *host_name;
nf_rec.src_mask = 0;
nf_rec.dst_mask = 0;
- for (i=0; i<MAX_COLLECTORS; i++) {
+ for (i = 0; i < nf->n_fds; i++) {
struct msghdr msghdr;
struct iovec iov[2];
- if (nf->netflow_fds[i] == -1) {
- break;
- }
-
iov[0].iov_base = &nf_hdr;
iov[0].iov_len = sizeof nf_hdr;
iov[1].iov_base = &nf_rec;
msghdr.msg_control = NULL;
msghdr.msg_controllen = 0;
msghdr.msg_flags = 0;
- if (sendmsg(nf->netflow_fds[i], &msghdr, 0) < 0) {
+ if (sendmsg(nf->fds[i], &msghdr, 0) < 0) {
VLOG_WARN_RL(&rl, "netflow message send failed: %s",
strerror(errno));
}
nf->netflow_cnt++;
}
-void
-netflow_reconfigure(struct netflow *nf)
+static void
+clear_collectors(struct netflow *nf)
{
- struct svec collectors;
- int i, nf_idx=0;
+ size_t i;
- /* Configure NetFlow collectors. */
- for (i=0; i<MAX_COLLECTORS; i++) {
- if (nf->netflow_fds[i] >= 0) {
- close(nf->netflow_fds[i]);
- nf->netflow_fds[i] = -1;
- }
+ for (i = 0; i < nf->n_fds; i++) {
+ close(nf->fds[i]);
}
+ free(nf->fds);
+ nf->fds = NULL;
+ nf->n_fds = 0;
+}
- svec_init(&collectors);
- cfg_get_all_keys(&collectors, "netflow.%s.host", nf->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<collectors.n; i++) {
- if (nf_idx >= MAX_COLLECTORS) {
- VLOG_WARN("too many netflow collectors specified, ignoring %s\n",
- collectors.names[i]);
- continue;
- }
-
- nf->netflow_fds[nf_idx] = udp_open(collectors.names[i]);
- if (nf->netflow_fds[nf_idx] < 0) {
- VLOG_WARN("couldn't open connection to collector, ignoring %s\n",
- collectors.names[i]);
+int
+netflow_set_collectors(struct netflow *nf, const struct svec *collectors_)
+{
+ struct svec collectors;
+ int error = 0;
+ size_t i;
+
+ clear_collectors(nf);
+
+ svec_clone(&collectors, collectors_);
+ svec_sort_unique(&collectors);
+
+ nf->fds = xmalloc(sizeof *nf->fds * collectors.n);
+ for (i = 0; i < collectors.n; i++) {
+ const char *name = collectors.names[i];
+ char *tmpname = xstrdup(name);
+ int fd = open_collector(tmpname);
+ free(tmpname);
+ if (fd >= 0) {
+ nf->fds[nf->n_fds++] = fd;
} else {
- nf_idx++;
+ VLOG_WARN("couldn't open connection to collector (%s), "
+ "ignoring %s\n", strerror(-fd), name);
+ if (!error) {
+ error = -fd;
+ }
}
}
+
+ svec_destroy(&collectors);
+ return error;
}
struct netflow *
-netflow_create(const char *br_name)
+netflow_create(void)
{
- struct netflow *nf;
- int i;
-
- nf = xmalloc(sizeof *nf);
- nf->br_name = br_name;
+ struct netflow *nf = xmalloc(sizeof *nf);
nf->boot_time = time_msec();
- for (i = 0; i < MAX_COLLECTORS; i++) {
- nf->netflow_fds[i] = -1;
- }
+ nf->fds = NULL;
+ nf->n_fds = 0;
nf->netflow_cnt = 0;
return nf;
}
netflow_destroy(struct netflow *nf)
{
if (nf) {
- int i;
-
- /* We don't own nf->br_name. */
- for (i = 0; i < MAX_COLLECTORS; i++) {
- int fd = nf->netflow_fds[i];
- if (fd >= 0) {
- close(fd);
- }
- }
+ clear_collectors(nf);
free(nf);
}
}
#include "flow.h"
struct odp_flow_stats;
+struct svec;
-struct netflow *netflow_create(const char *br_name);
+struct netflow *netflow_create(void);
void netflow_destroy(struct netflow *);
-void netflow_reconfigure(struct netflow *);
+int netflow_set_collectors(struct netflow *, const struct svec *collectors);
void netflow_expire(struct netflow *, const flow_t *,
const struct odp_flow_stats *,
long long int created);
#include "svec.h"
#include "timeval.h"
#include "vconn.h"
+#include "vconn-ssl.h"
#include "xtoxll.h"
#define THIS_MODULE VLM_ofproto
struct ofproto {
/* Settings. */
uint64_t datapath_id; /* Datapath ID. */
- const char *mfr_desc; /* Manufacturer. */
- const char *hw_desc; /* Hardware. */
- const char *sw_desc; /* Software version. */
- const char *serial_desc; /* Serial number. */
+ uint64_t fallback_dpid; /* Datapath ID if no better choice found. */
+ char *manufacturer; /* Manufacturer. */
+ char *hardware; /* Hardware. */
+ char *software; /* Software version. */
+ char *serial; /* Serial number. */
/* Datapath. */
struct dpif dpif;
/* Configuration. */
struct switch_status *switch_status;
+ struct status_category *ss_cat;
struct in_band *in_band;
struct discovery *discovery;
struct fail_open *fail_open;
/* OpenFlow connections. */
struct list all_conns;
struct ofconn *controller;
- struct pvconn *listeners[MAX_MGMT];
+ struct pvconn **listeners;
size_t n_listeners;
};
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
-static uint64_t pick_datapath_id(struct dpif *);
+static uint64_t pick_datapath_id(struct dpif *, uint64_t fallback_dpid);
+static uint64_t pick_fallback_dpid(void);
static void send_packet_in_miss(struct ofpbuf *, void *ofproto);
static void send_packet_in_action(struct ofpbuf *, void *ofproto);
static void update_used(struct ofproto *);
static void refresh_port_group(struct ofproto *, unsigned int group);
static void update_port(struct ofproto *, const char *devname);
-static void init_ports(struct ofproto *);
+static int init_ports(struct ofproto *);
static void reinit_ports(struct ofproto *);
static uint16_t odp_port_to_ofp_port(uint16_t odp_port);
static uint16_t ofp_port_to_odp_port(uint16_t ofp_port);
-struct ofproto *
-ofproto_create(const struct ofsettings *settings)
+int
+ofproto_create(const char *datapath, struct ofproto **ofprotop)
{
struct dpifmon *dpifmon;
- struct rconn *controller;
struct ofproto *p;
struct dpif dpif;
int error;
- size_t i;
+
+ *ofprotop = NULL;
/* Connect to datapath and start listening for messages. */
- error = dpif_open(settings->dp_name, &dpif);
+ error = dpif_open(datapath, &dpif);
if (error) {
- ofp_fatal(error, "Failed to open datapath %s", settings->dp_name);
+ VLOG_ERR("failed to open datapath %s: %s", datapath, strerror(error));
+ return error;
}
error = dpif_set_listen_mask(&dpif, ODPL_MISS | ODPL_ACTION);
if (error) {
- ofp_fatal(error, "failed to listen on dpif %d", dpif.minor);
+ VLOG_ERR("failed to listen on datapath %s: %s",
+ datapath, strerror(error));
+ dpif_close(&dpif);
+ return error;
}
/* Start monitoring datapath ports for status changes. */
error = dpifmon_create(&dpif, &dpifmon);
if (error) {
- ofp_fatal(error, "failed to starting monitoring dpif %d", dpif.minor);
- }
-
- /* Create controller connection. */
- controller = rconn_create(settings->probe_interval, settings->max_backoff);
- if (settings->controller_name) {
- error = rconn_connect(controller, settings->controller_name);
- if (error == EAFNOSUPPORT) {
- ofp_fatal(0, "No support for %s vconn", settings->controller_name);
- }
+ VLOG_ERR("failed to starting monitoring datapath %s: %s",
+ datapath, strerror(error));
+ dpif_close(&dpif);
+ return error;
}
/* Initialize settings. */
p = xcalloc(1, sizeof *p);
- p->datapath_id = settings->datapath_id;
- if (!p->datapath_id) {
- p->datapath_id = pick_datapath_id(&dpif);
- }
+ p->fallback_dpid = pick_fallback_dpid();
+ p->datapath_id = pick_datapath_id(&dpif, p->fallback_dpid);
VLOG_INFO("using datapath ID %012"PRIx64, p->datapath_id);
- p->mfr_desc = settings->mfr_desc;
- p->hw_desc = settings->hw_desc;
- p->sw_desc = settings->sw_desc;
- p->serial_desc = settings->serial_desc;
+ p->manufacturer = xstrdup("Nicira Networks, Inc.");
+ p->hardware = xstrdup("Reference Implementation");
+ p->software = xstrdup(VERSION BUILDNR);
+ p->serial = xstrdup("None");
- /* Initialize datapath information. */
+ /* Initialize datapath. */
p->dpif = dpif;
p->dpifmon = dpifmon;
port_array_init(&p->ports);
shash_init(&p->port_by_name);
/* Initialize submodules. */
- p->switch_status = switch_status_create(settings);
- switch_status_register_category(p->switch_status, "remote",
- rconn_status_cb, controller);
- if (settings->in_band) {
- p->in_band = in_band_create(&dpif, p->switch_status, controller);
- }
- if (settings->discovery) {
- p->discovery = discovery_create(settings->accept_controller_re,
- settings->update_resolv_conf, &p->dpif,
- p->switch_status);
- }
- if (settings->fail_mode == FAIL_OPEN) {
- p->fail_open = fail_open_create(settings->probe_interval * 3,
- p->switch_status, controller);
- }
- if (settings->rate_limit) {
- p->miss_sched = pinsched_create(settings->rate_limit,
- settings->burst_limit,
- p->switch_status);
- p->action_sched = pinsched_create(settings->rate_limit,
- settings->burst_limit, NULL);
- }
- if (settings->command_acl[0]) {
- p->executer = executer_create(settings->command_acl,
- settings->command_dir);
- }
- if (settings->br_name) {
- p->netflow = netflow_create(settings->br_name);
- }
+ p->switch_status = switch_status_create(p);
+ p->in_band = NULL;
+ p->discovery = NULL;
+ p->fail_open = NULL;
+ p->miss_sched = p->action_sched = NULL;
+ p->executer = NULL;
+ p->netflow = NULL;
/* Initialize flow table. */
classifier_init(&p->cls);
/* Initialize OpenFlow connections. */
list_init(&p->all_conns);
- p->controller = ofconn_create(p, controller);
+ p->controller = ofconn_create(p, rconn_create(15, 15));
p->controller->pktbuf = pktbuf_create();
p->controller->miss_send_len = OFP_DEFAULT_MISS_SEND_LEN;
+ p->listeners = NULL;
p->n_listeners = 0;
- for (i = 0; i < settings->n_listeners; i++) {
- const char *name = settings->listener_names[i];
+
+ /* Register switch status category. */
+ p->ss_cat = switch_status_register(p->switch_status, "remote",
+ rconn_status_cb, p->controller->rconn);
+
+ /* Almost done... */
+ error = init_ports(p);
+ if (error) {
+ ofproto_destroy(p);
+ return error;
+ }
+
+ *ofprotop = p;
+ return 0;
+}
+
+void
+ofproto_set_datapath_id(struct ofproto *p, uint64_t datapath_id)
+{
+ uint64_t old_dpid = p->datapath_id;
+ p->datapath_id = (datapath_id
+ ? datapath_id
+ : pick_datapath_id(&p->dpif, p->fallback_dpid));
+ if (p->datapath_id != old_dpid) {
+ VLOG_INFO("datapath ID changed to %012"PRIx64, p->datapath_id);
+ rconn_reconnect(p->controller->rconn);
+ }
+}
+
+void
+ofproto_set_probe_interval(struct ofproto *p, int probe_interval)
+{
+ if (probe_interval) {
+ rconn_set_probe_interval(p->controller->rconn, probe_interval);
+ if (p->fail_open) {
+ fail_open_set_trigger_duration(p->fail_open, probe_interval * 3);
+ }
+ }
+}
+
+void
+ofproto_set_max_backoff(struct ofproto *p, int max_backoff)
+{
+ if (max_backoff) {
+ rconn_set_max_backoff(p->controller->rconn, max_backoff);
+ }
+}
+
+void
+ofproto_set_desc(struct ofproto *p,
+ const char *manufacturer, const char *hardware,
+ const char *software, const char *serial)
+{
+ if (manufacturer) {
+ free(p->manufacturer);
+ p->manufacturer = xstrdup(manufacturer);
+ }
+ if (hardware) {
+ free(p->hardware);
+ p->hardware = xstrdup(hardware);
+ }
+ if (software) {
+ free(p->software);
+ p->software = xstrdup(software);
+ }
+ if (serial) {
+ free(p->serial);
+ p->serial = xstrdup(serial);
+ }
+}
+
+int
+ofproto_set_in_band(struct ofproto *p, bool in_band)
+{
+ if (in_band != (p->in_band != NULL)) {
+ if (in_band) {
+ return in_band_create(&p->dpif, p->switch_status,
+ p->controller->rconn, &p->in_band);
+ } else {
+ ofproto_set_discovery(p, false, NULL, true);
+ in_band_destroy(p->in_band);
+ p->in_band = NULL;
+ }
+ rconn_reconnect(p->controller->rconn);
+ }
+ return 0;
+}
+
+int
+ofproto_set_discovery(struct ofproto *p, bool discovery,
+ const char *re, bool update_resolv_conf)
+{
+ if (discovery != (p->discovery != NULL)) {
+ if (discovery) {
+ int error = ofproto_set_in_band(p, true);
+ if (error) {
+ return error;
+ }
+ error = discovery_create(re, update_resolv_conf,
+ &p->dpif, p->switch_status,
+ &p->discovery);
+ if (error) {
+ return error;
+ }
+ } else {
+ discovery_destroy(p->discovery);
+ p->discovery = NULL;
+ }
+ rconn_disconnect(p->controller->rconn);
+ } else if (discovery) {
+ discovery_set_update_resolv_conf(p->discovery, update_resolv_conf);
+ return discovery_set_accept_controller_re(p->discovery, re);
+ }
+ return 0;
+}
+
+int
+ofproto_set_controller(struct ofproto *ofproto, const char *controller)
+{
+ if (ofproto->discovery) {
+ return EINVAL;
+ }
+ rconn_connect(ofproto->controller->rconn, controller);
+ return 0;
+}
+
+int
+ofproto_set_listeners(struct ofproto *ofproto, const struct svec *listeners)
+{
+ int retval = 0;
+ size_t i;
+
+ for (i = 0; i < ofproto->n_listeners; i++) {
+ pvconn_close(ofproto->listeners[i]);
+ }
+ free(ofproto->listeners);
+ ofproto->n_listeners = 0;
+
+ ofproto->listeners = xmalloc(listeners->n * sizeof *ofproto->listeners);
+ for (i = 0; i < listeners->n; i++) {
+ const char *name = listeners->names[i];
struct pvconn *pvconn;
+ int error;
error = pvconn_open(name, &pvconn);
- if (error && error != EAGAIN) {
- ofp_fatal(error, "opening %s", name);
+ if (!error) {
+ ofproto->listeners[ofproto->n_listeners++] = pvconn;
+ } else {
+ VLOG_ERR("failed to listen on %s: %s", name, strerror(error));
+ if (!retval) {
+ retval = error;
+ }
}
- p->listeners[p->n_listeners++] = pvconn;
}
+ return retval;
+}
- /* Retrieve initial port status. */
- init_ports(p);
+int
+ofproto_set_netflow(struct ofproto *ofproto, const struct svec *collectors)
+{
+ if (collectors && collectors->n) {
+ if (!ofproto->netflow) {
+ ofproto->netflow = netflow_create();
+ }
+ return netflow_set_collectors(ofproto->netflow, collectors);
+ } else {
+ netflow_destroy(ofproto->netflow);
+ ofproto->netflow = NULL;
+ return 0;
+ }
+}
- return p;
+void
+ofproto_set_failure(struct ofproto *ofproto, bool fail_open)
+{
+ if (fail_open) {
+ struct rconn *rconn = ofproto->controller->rconn;
+ int trigger_duration = rconn_get_probe_interval(rconn) * 3;
+ if (!ofproto->fail_open) {
+ ofproto->fail_open = fail_open_create(trigger_duration,
+ ofproto->switch_status,
+ rconn);
+ } else {
+ fail_open_set_trigger_duration(ofproto->fail_open,
+ trigger_duration);
+ }
+ } else {
+ fail_open_destroy(ofproto->fail_open);
+ ofproto->fail_open = NULL;
+ }
+}
+
+void
+ofproto_set_rate_limit(struct ofproto *ofproto,
+ int rate_limit, int burst_limit)
+{
+ if (rate_limit) {
+ if (!ofproto->miss_sched) {
+ ofproto->miss_sched = pinsched_create(rate_limit, burst_limit,
+ ofproto->switch_status);
+ ofproto->action_sched = pinsched_create(rate_limit, burst_limit,
+ NULL);
+ } else {
+ pinsched_set_limits(ofproto->miss_sched, rate_limit, burst_limit);
+ pinsched_set_limits(ofproto->action_sched,
+ rate_limit, burst_limit);
+ }
+ } else {
+ pinsched_destroy(ofproto->miss_sched);
+ ofproto->miss_sched = NULL;
+ pinsched_destroy(ofproto->action_sched);
+ ofproto->action_sched = NULL;
+ }
+}
+
+int
+ofproto_set_stp(struct ofproto *ofproto UNUSED, bool enable_stp)
+{
+ /* XXX */
+ if (enable_stp) {
+ VLOG_WARN("STP is not yet implemented");
+ return EINVAL;
+ } else {
+ return 0;
+ }
+}
+
+int
+ofproto_set_remote_execution(struct ofproto *ofproto, const char *command_acl,
+ const char *command_dir)
+{
+ if (command_acl) {
+ if (!ofproto->executer) {
+ return executer_create(command_acl, command_dir,
+ &ofproto->executer);
+ } else {
+ executer_set_acl(ofproto->executer, command_acl, command_dir);
+ }
+ } else {
+ executer_destroy(ofproto->executer);
+ ofproto->executer = NULL;
+ }
+ return 0;
+}
+
+uint64_t
+ofproto_get_datapath_id(const struct ofproto *ofproto)
+{
+ return ofproto->datapath_id;
+}
+
+int
+ofproto_get_probe_interval(const struct ofproto *ofproto)
+{
+ return rconn_get_probe_interval(ofproto->controller->rconn);
+}
+
+int
+ofproto_get_max_backoff(const struct ofproto *ofproto)
+{
+ return rconn_get_max_backoff(ofproto->controller->rconn);
+}
+
+bool
+ofproto_get_in_band(const struct ofproto *ofproto)
+{
+ return ofproto->in_band != NULL;
+}
+
+bool
+ofproto_get_discovery(const struct ofproto *ofproto)
+{
+ return ofproto->discovery != NULL;
+}
+
+const char *
+ofproto_get_controller(const struct ofproto *ofproto)
+{
+ return rconn_get_name(ofproto->controller->rconn);
+}
+
+void
+ofproto_get_listeners(const struct ofproto *ofproto, struct svec *listeners)
+{
+ size_t i;
+
+ for (i = 0; i < ofproto->n_listeners; i++) {
+ svec_add(listeners, pvconn_get_name(ofproto->listeners[i]));
+ }
}
void
executer_destroy(p->executer);
netflow_destroy(p->netflow);
+ switch_status_unregister(p->ss_cat);
+
for (i = 0; i < p->n_listeners; i++) {
pvconn_close(p->listeners[i]);
}
+ free(p->listeners);
free(p);
}
-void
-ofproto_reconfigure(struct ofproto *p)
-{
- if (p->netflow) {
- netflow_reconfigure(p->netflow);
- }
-}
-
void
ofproto_run(struct ofproto *p)
{
refresh_port_groups(p);
}
-static void
+static int
init_ports(struct ofproto *p)
{
struct odp_port *ports;
error = dpif_port_list(&p->dpif, &ports, &n_ports);
if (error) {
- ofp_fatal(error, "failed to list datapath ports");
+ return error;
}
for (i = 0; i < n_ports; i++) {
}
free(ports);
refresh_port_groups(p);
+ return 0;
}
\f
static struct ofconn *
msg = start_stats_reply(request, sizeof *ods);
ods = append_stats_reply(sizeof *ods, ofconn, &msg);
- strncpy(ods->mfr_desc, p->mfr_desc, sizeof ods->mfr_desc);
- strncpy(ods->hw_desc, p->hw_desc, sizeof ods->hw_desc);
- strncpy(ods->sw_desc, p->sw_desc, sizeof ods->sw_desc);
- strncpy(ods->serial_num, p->serial_desc, sizeof ods->serial_num);
+ strncpy(ods->mfr_desc, p->manufacturer, sizeof ods->mfr_desc);
+ strncpy(ods->hw_desc, p->hardware, sizeof ods->hw_desc);
+ strncpy(ods->sw_desc, p->software, sizeof ods->sw_desc);
+ strncpy(ods->serial_num, p->serial, sizeof ods->serial_num);
queue_tx(msg, ofconn);
return 0;
}
static uint64_t
-pick_datapath_id(struct dpif *dpif)
+pick_datapath_id(struct dpif *dpif, uint64_t fallback_dpid)
{
struct odp_port port;
uint8_t ea[ETH_ADDR_LEN];
VLOG_WARN("datapath local port query failed (%s)", strerror(error));
}
+ return fallback_dpid;
+}
+
+static uint64_t
+pick_fallback_dpid(void)
+{
+ uint8_t ea[ETH_ADDR_LEN];
eth_addr_random(ea);
ea[0] = 0x00; /* Set Nicira OUI. */
ea[1] = 0x23;
ea[2] = 0x20;
return eth_addr_to_uint64(ea);
}
-
#include <stdbool.h>
#include <stddef.h>
+#include <stdint.h>
#include "flow.h"
-/* Behavior when the connection to the controller fails. */
-enum fail_mode {
- FAIL_OPEN, /* Act as learning switch. */
- FAIL_CLOSED /* Drop all packets. */
-};
+struct ofproto;
+struct svec;
-/* Maximum number of management connection listeners. */
-#define MAX_MGMT 8
-
-/* Settings that may be configured by the user. */
-struct ofsettings {
- /* 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? */
-
- /* Datapath. */
- uint64_t datapath_id; /* Datapath ID. */
- const char *dp_name; /* Name of local datapath. */
-
- /* Description strings. */
- const char *mfr_desc; /* Manufacturer. */
- const char *hw_desc; /* Hardware. */
- const char *sw_desc; /* Software version. */
- const char *serial_desc; /* Serial number. */
-
- /* Related vconns and network devices. */
- const char *controller_name; /* Controller (if not discovery mode). */
- const char *listener_names[MAX_MGMT]; /* Listen for mgmt connections. */
- size_t n_listeners; /* Number of mgmt connection listeners. */
-
- /* Failure behavior. */
- enum fail_mode fail_mode; /* Act as learning switch if no controller? */
- int max_idle; /* Idle time for flows in fail-open mode. */
- int probe_interval; /* # seconds idle before sending echo request. */
- int max_backoff; /* Max # seconds between connection attempts. */
-
- /* Packet-in rate-limiting. */
- int rate_limit; /* Tokens added to bucket per second. */
- int burst_limit; /* Maximum number token bucket size. */
-
- /* Discovery behavior. */
- const char *accept_controller_re; /* Controller vconns to accept. */
- bool update_resolv_conf; /* Update /etc/resolv.conf? */
-
- /* Spanning tree protocol. */
- bool enable_stp;
-
- /* Remote command execution. */
- char *command_acl; /* Command white/blacklist, as shell globs. */
- char *command_dir; /* Directory that contains commands. */
-};
-
-struct ofproto *ofproto_create(const struct ofsettings *);
+int ofproto_create(const char *datapath, struct ofproto **ofprotop);
void ofproto_destroy(struct ofproto *);
-void ofproto_reconfigure(struct ofproto *);
void ofproto_run(struct ofproto *);
void ofproto_wait(struct ofproto *);
-bool ofproto_is_alive(const struct ofproto *p);
-
-int ofproto_send_packet(struct ofproto *p, const flow_t *,
+bool ofproto_is_alive(const struct ofproto *);
+
+/* Configuration. */
+void ofproto_set_datapath_id(struct ofproto *, uint64_t datapath_id);
+void ofproto_set_probe_interval(struct ofproto *, int probe_interval);
+void ofproto_set_max_backoff(struct ofproto *, int max_backoff);
+void ofproto_set_desc(struct ofproto *,
+ const char *manufacturer, const char *hardware,
+ const char *software, const char *serial);
+int ofproto_set_in_band(struct ofproto *, bool in_band);
+int ofproto_set_discovery(struct ofproto *, bool discovery,
+ const char *accept_controller_re,
+ bool update_resolv_conf);
+int ofproto_set_controller(struct ofproto *, const char *controller);
+int ofproto_set_listeners(struct ofproto *, const struct svec *listeners);
+int ofproto_set_netflow(struct ofproto *, const struct svec *collectors);
+void ofproto_set_failure(struct ofproto *, bool fail_open);
+void ofproto_set_rate_limit(struct ofproto *, int rate_limit, int burst_limit);
+int ofproto_set_stp(struct ofproto *, bool enable_stp);
+int ofproto_set_remote_execution(struct ofproto *, const char *command_acl,
+ const char *command_dir);
+
+/* Configuration querying. */
+uint64_t ofproto_get_datapath_id(const struct ofproto *);
+int ofproto_get_probe_interval(const struct ofproto *);
+int ofproto_get_max_backoff(const struct ofproto *);
+bool ofproto_get_in_band(const struct ofproto *);
+bool ofproto_get_discovery(const struct ofproto *);
+const char *ofproto_get_controller(const struct ofproto *);
+void ofproto_get_listeners(const struct ofproto *, struct svec *);
+
+/* Functions for use by ofproto implementation modules, not by clients. */
+int ofproto_send_packet(struct ofproto *, const flow_t *,
const union ofp_action *, size_t n_actions,
const struct ofpbuf *);
void ofproto_setup_exact_flow(struct ofproto *, const flow_t *,
unsigned long long n_limited; /* # queued for rate limiting. */
unsigned long long n_queue_dropped; /* # dropped due to queue overflow. */
unsigned long long n_tx_dropped; /* # dropped due to tx overflow. */
+
+ /* Switch status. */
+ struct status_category *ss_cat;
};
static struct ofpbuf *
ps->n_tx_dropped = 0;
if (ss) {
- switch_status_register_category(ss, "rate-limit",
- pinsched_status_cb, ps);
+ ps->ss_cat = switch_status_register(ss, "rate-limit",
+ pinsched_status_cb, ps);
}
return ps;
free(queue);
}
port_array_destroy(&ps->queues);
+ switch_status_unregister(ps->ss_cat);
free(ps);
}
}
+
+void
+pinsched_set_limits(struct pinsched *ps, int rate_limit, int burst_limit)
+{
+ ps->rate_limit = rate_limit;
+ ps->burst_limit = burst_limit;
+ while (ps->n_queued > burst_limit) {
+ drop_packet(ps);
+ }
+}
typedef void pinsched_tx_cb(struct ofpbuf *, void *aux);
struct pinsched *pinsched_create(int rate_limit, int burst_limit,
struct switch_status *);
+void pinsched_set_limits(struct pinsched *, int rate_limit, int burst_limit);
void pinsched_destroy(struct pinsched *);
void pinsched_send(struct pinsched *, uint16_t port_no, struct ofpbuf *,
pinsched_tx_cb *, void *aux);
#include <stdlib.h>
#include <unistd.h>
#include "dynamic-string.h"
+#include "list.h"
#include "ofpbuf.h"
#include "ofproto.h"
#include "openflow/nicira-ext.h"
#include "rconn.h"
+#include "svec.h"
#include "timeval.h"
#include "vconn.h"
#define THIS_MODULE VLM_status
#include "vlog.h"
-struct switch_status_category {
+struct status_category {
+ struct list node;
char *name;
void (*cb)(struct status_reply *, void *aux);
void *aux;
struct switch_status {
time_t booted;
- struct switch_status_category *categories;
- size_t n_categories, allocated_categories;
+ struct status_category *config_cat;
+ struct status_category *switch_cat;
+ struct list categories;
};
struct status_reply {
- struct switch_status_category *category;
+ struct status_category *category;
struct ds request;
struct ds output;
};
switch_status_handle_request(struct switch_status *ss, struct rconn *rconn,
struct nicira_header *request)
{
- struct switch_status_category *c;
+ struct status_category *c;
struct nicira_header *reply;
struct status_reply sr;
struct ofpbuf *b;
sr.request.string = (void *) (request + 1);
sr.request.length = ntohs(request->header.length) - sizeof *request;
ds_init(&sr.output);
- for (c = ss->categories; c < &ss->categories[ss->n_categories]; c++) {
+ LIST_FOR_EACH (c, struct status_category, node, &ss->categories) {
if (!memcmp(c->name, sr.request.string,
MIN(strlen(c->name), sr.request.length))) {
sr.category = c;
}
static void
-config_status_cb(struct status_reply *sr, void *s_)
+config_status_cb(struct status_reply *sr, void *ofproto_)
{
- const struct ofsettings *s = s_;
+ const struct ofproto *ofproto = ofproto_;
+ struct svec listeners;
+ int probe_interval, max_backoff;
size_t i;
- for (i = 0; i < s->n_listeners; i++) {
- status_reply_put(sr, "management%zu=%s", i, s->listener_names[i]);
+ svec_init(&listeners);
+ ofproto_get_listeners(ofproto, &listeners);
+ for (i = 0; i < listeners.n; i++) {
+ status_reply_put(sr, "management%zu=%s", i, listeners.names[i]);
}
- if (s->probe_interval) {
- status_reply_put(sr, "probe-interval=%d", s->probe_interval);
+ svec_destroy(&listeners);
+
+ probe_interval = ofproto_get_probe_interval(ofproto);
+ if (probe_interval) {
+ status_reply_put(sr, "probe-interval=%d", probe_interval);
}
- if (s->max_backoff) {
- status_reply_put(sr, "max-backoff=%d", s->max_backoff);
+
+ max_backoff = ofproto_get_max_backoff(ofproto);
+ if (max_backoff) {
+ status_reply_put(sr, "max-backoff=%d", max_backoff);
}
}
}
struct switch_status *
-switch_status_create(const struct ofsettings *settings)
+switch_status_create(const struct ofproto *ofproto)
{
struct switch_status *ss = xcalloc(1, sizeof *ss);
ss->booted = time_now();
- switch_status_register_category(ss, "config",
- config_status_cb, (void *) settings);
- switch_status_register_category(ss, "switch", switch_status_cb, ss);
+ list_init(&ss->categories);
+ ss->config_cat = switch_status_register(ss, "config", config_status_cb,
+ (void *) ofproto);
+ ss->switch_cat = switch_status_register(ss, "switch", switch_status_cb,
+ ss);
return ss;
}
switch_status_destroy(struct switch_status *ss)
{
if (ss) {
- free(ss->categories);
+ /* Orphan any remaining categories, so that unregistering them later
+ * won't write to bad memory. */
+ struct status_category *c;
+ LIST_FOR_EACH (c, struct status_category, node, &ss->categories) {
+ list_init(&c->node);
+ }
+ switch_status_unregister(ss->config_cat);
+ switch_status_unregister(ss->switch_cat);
free(ss);
}
}
-void
-switch_status_register_category(struct switch_status *ss,
- const char *category,
- void (*cb)(struct status_reply *, void *aux),
- void *aux)
+struct status_category *
+switch_status_register(struct switch_status *ss,
+ const char *category,
+ status_cb_func *cb, void *aux)
{
- struct switch_status_category *c;
- if (ss->n_categories >= ss->allocated_categories) {
- ss->categories = x2nrealloc(ss->categories, &ss->allocated_categories,
- sizeof *ss->categories);
- }
- c = &ss->categories[ss->n_categories++];
+ struct status_category *c = xmalloc(sizeof *c);
c->cb = cb;
c->aux = aux;
c->name = xstrdup(category);
+ list_push_back(&ss->categories, &c->node);
+ return c;
+}
+
+void
+switch_status_unregister(struct status_category *c)
+{
+ if (c) {
+ if (!list_is_empty(&c->node)) {
+ list_remove(&c->node);
+ }
+ free(c->name);
+ free(c);
+ }
}
void
struct nicira_header;
struct rconn;
struct secchan;
-struct ofsettings;
+struct ofproto;
struct status_reply;
-struct switch_status *switch_status_create(const struct ofsettings *);
+struct switch_status *switch_status_create(const struct ofproto *);
void switch_status_destroy(struct switch_status *);
int switch_status_handle_request(struct switch_status *, struct rconn *,
struct nicira_header *);
-void switch_status_register_category(struct switch_status *,
- const char *category,
- void (*cb)(struct status_reply *,
- void *aux),
- void *aux);
+typedef void status_cb_func(struct status_reply *, void *aux);
+struct status_category *switch_status_register(struct switch_status *,
+ const char *category,
+ status_cb_func *, void *aux);
+void switch_status_unregister(struct status_category *);
void status_reply_put(struct status_reply *, const char *, ...)
PRINTF_FORMAT(2, 3);