#include <time.h>
#include <unistd.h>
-#include "buffer.h"
#include "command-line.h"
#include "compiler.h"
#include "daemon.h"
-#include "dhcp.h"
#include "dhcp-client.h"
+#include "dhcp.h"
#include "dynamic-string.h"
#include "fault.h"
#include "flow.h"
#include "mac-learning.h"
#include "netdev.h"
#include "nicira-ext.h"
+#include "ofpbuf.h"
#include "openflow.h"
#include "packets.h"
#include "poll-loop.h"
regex_t accept_controller_regex; /* Controller vconns to accept. */
const char *accept_controller_re; /* String version of regex. */
bool update_resolv_conf; /* Update /etc/resolv.conf? */
+
+ /* Spanning tree protocol. */
+ bool enable_stp;
};
struct half {
struct rconn *rconn;
- struct buffer *rxbuf;
+ struct ofpbuf *rxbuf;
int n_txq; /* No. of packets queued for tx on 'rconn'. */
};
static void parse_options(int argc, char *argv[], struct settings *);
static void usage(void) NO_RETURN;
-static struct vconn *open_passive_vconn(const char *name);
-static struct vconn *accept_vconn(struct vconn *vconn);
+static struct pvconn *open_passive_vconn(const char *name);
+static struct vconn *accept_vconn(struct pvconn *pvconn);
static struct relay *relay_create(struct rconn *local, struct rconn *remote,
bool is_mgmt_conn);
-static struct relay *relay_accept(const struct settings *, struct vconn *);
+static struct relay *relay_accept(const struct settings *, struct pvconn *);
static void relay_run(struct relay *, const struct hook[], size_t n_hooks);
static void relay_wait(struct relay *);
static void relay_destroy(struct relay *);
static struct ofp_packet_in *get_ofp_packet_in(struct relay *);
static bool get_ofp_packet_eth_header(struct relay *, struct ofp_packet_in **,
struct eth_header **);
-static void get_ofp_packet_payload(struct ofp_packet_in *, struct buffer *);
+static void get_ofp_packet_payload(struct ofp_packet_in *, struct ofpbuf *);
struct switch_status;
struct status_reply;
struct hook hooks[8];
size_t n_hooks = 0;
- struct vconn *monitor;
+ struct pvconn *monitor;
- struct vconn *listeners[MAX_MGMT];
+ struct pvconn *listeners[MAX_MGMT];
size_t n_listeners;
struct rconn *local_rconn, *remote_rconn;
/* Start listening for vlogconf requests. */
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");
}
die_if_already_running();
if (s.controller_name) {
retval = rconn_connect(remote_rconn, s.controller_name);
if (retval == EAFNOSUPPORT) {
- fatal(0, "No support for %s vconn", s.controller_name);
+ ofp_fatal(0, "No support for %s vconn", s.controller_name);
}
}
switch_status_register_category(switch_status, "remote",
/* Set up hooks. */
hooks[n_hooks++] = port_watcher_create(local_rconn, remote_rconn, &pw);
- hooks[n_hooks++] = stp_hook_create(&s, pw, local_rconn, remote_rconn);
+ if (s.enable_stp) {
+ hooks[n_hooks++] = stp_hook_create(&s, pw, local_rconn, remote_rconn);
+ }
if (s.in_band) {
hooks[n_hooks++] = in_band_hook_create(&s, switch_status,
remote_rconn);
relay_wait(r);
}
for (i = 0; i < n_listeners; i++) {
- vconn_accept_wait(listeners[i]);
+ pvconn_wait(listeners[i]);
}
if (monitor) {
- vconn_accept_wait(monitor);
+ pvconn_wait(monitor);
}
for (i = 0; i < n_hooks; i++) {
if (hooks[i].wait_cb) {
return 0;
}
-static struct vconn *
-open_passive_vconn(const char *name)
+static struct pvconn *
+open_passive_vconn(const char *name)
{
- struct vconn *vconn;
+ struct pvconn *pvconn;
int retval;
- retval = vconn_open(name, &vconn);
+ retval = pvconn_open(name, &pvconn);
if (retval && retval != EAGAIN) {
- fatal(retval, "opening %s", name);
- }
- if (!vconn_is_passive(vconn)) {
- fatal(0, "%s is not a passive vconn", name);
+ ofp_fatal(retval, "opening %s", name);
}
- return vconn;
+ return pvconn;
}
static struct vconn *
-accept_vconn(struct vconn *vconn)
+accept_vconn(struct pvconn *pvconn)
{
struct vconn *new;
int retval;
- retval = vconn_accept(vconn, &new);
+ retval = pvconn_accept(pvconn, OFP_VERSION, &new);
if (retval && retval != EAGAIN) {
VLOG_WARN_RL(&vrl, "accept failed (%s)", strerror(retval));
}
static struct ofp_packet_in *
get_ofp_packet_in(struct relay *r)
{
- struct buffer *msg = r->halves[HALF_LOCAL].rxbuf;
+ struct ofpbuf *msg = r->halves[HALF_LOCAL].rxbuf;
struct ofp_header *oh = msg->data;
if (oh->type == OFPT_PACKET_IN) {
if (msg->size >= offsetof (struct ofp_packet_in, data)) {
/* OpenFlow message relaying. */
static struct relay *
-relay_accept(const struct settings *s, struct vconn *listen_vconn)
+relay_accept(const struct settings *s, struct pvconn *pvconn)
{
struct vconn *new_remote, *new_local;
char *nl_name_without_subscription;
struct rconn *r1, *r2;
int retval;
- new_remote = accept_vconn(listen_vconn);
+ new_remote = accept_vconn(pvconn);
if (!new_remote) {
return NULL;
}
* obtaining a subscription for ofp_packet_in or ofp_flow_expired
* messages.*/
nl_name_without_subscription = xasprintf("%s:0", s->nl_name);
- retval = vconn_open(nl_name_without_subscription, &new_local);
+ retval = vconn_open(nl_name_without_subscription, OFP_VERSION, &new_local);
if (retval) {
VLOG_ERR_RL(&vrl, "could not connect to %s (%s)",
nl_name_without_subscription, strerror(retval));
const struct hook *h;
for (h = hooks; h < &hooks[n_hooks]; h++) {
if (h->packet_cb[i] && h->packet_cb[i](r, h->aux)) {
- buffer_delete(this->rxbuf);
+ ofpbuf_delete(this->rxbuf);
this->rxbuf = NULL;
progress = true;
break;
if (!retval) {
progress = true;
} else {
- buffer_delete(this->rxbuf);
+ ofpbuf_delete(this->rxbuf);
}
this->rxbuf = NULL;
}
for (i = 0; i < 2; i++) {
struct half *this = &r->halves[i];
rconn_destroy(this->rconn);
- buffer_delete(this->rxbuf);
+ ofpbuf_delete(this->rxbuf);
}
free(r);
}
\f
/* Port status watcher. */
-typedef void port_watcher_cb_func(uint16_t port_no,
+typedef void edit_port_cb_func(struct ofp_phy_port *port, void *aux);
+typedef void port_changed_cb_func(uint16_t port_no,
const struct ofp_phy_port *old,
const struct ofp_phy_port *new,
void *aux);
struct port_watcher_cb {
- port_watcher_cb_func *function;
+ edit_port_cb_func *edit_port;
+ port_changed_cb_func *port_changed;
void *aux;
};
}
static void
-call_pw_callbacks(struct port_watcher *pw, int port_no,
- const struct ofp_phy_port *old,
- const struct ofp_phy_port *new)
+call_port_changed_callbacks(struct port_watcher *pw, int port_no,
+ const struct ofp_phy_port *old,
+ const struct ofp_phy_port *new)
{
if (opp_differs(old, new)) {
int i;
for (i = 0; i < pw->n_cbs; i++) {
- pw->cbs[i].function(port_no, old, new, pw->cbs[i].aux);
+ port_changed_cb_func *port_changed = pw->cbs[i].port_changed;
+ if (port_changed) {
+ (port_changed)(port_no, old, new, pw->cbs[i].aux);
+ }
+ }
+ }
+}
+
+static void
+call_edit_port_callbacks(struct port_watcher *pw, struct ofp_phy_port *p)
+{
+ int i;
+ for (i = 0; i < pw->n_cbs; i++) {
+ edit_port_cb_func *edit_port = pw->cbs[i].edit_port;
+ if (edit_port) {
+ (edit_port)(p, pw->cbs[i].aux);
}
}
}
*pw_opp = *opp;
sanitize_opp(pw_opp);
}
- call_pw_callbacks(pw, port_no, &old, pw_opp);
+ call_port_changed_callbacks(pw, port_no, &old, pw_opp);
}
static bool
port_watcher_local_packet_cb(struct relay *r, void *pw_)
{
struct port_watcher *pw = pw_;
- struct buffer *msg = r->halves[HALF_LOCAL].rxbuf;
+ struct ofpbuf *msg = r->halves[HALF_LOCAL].rxbuf;
struct ofp_header *oh = msg->data;
if (oh->type == OFPT_FEATURES_REPLY
n_ports = ((msg->size - offsetof(struct ofp_switch_features, ports))
/ sizeof *osf->ports);
for (i = 0; i < n_ports; i++) {
- update_phy_port(pw, &osf->ports[i], OFPPR_MOD, seen);
+ struct ofp_phy_port *opp = &osf->ports[i];
+ call_edit_port_callbacks(pw, opp);
+ update_phy_port(pw, opp, OFPPR_MOD, seen);
}
/* Delete all the ports not included in the message. */
} else if (oh->type == OFPT_PORT_STATUS
&& msg->size >= sizeof(struct ofp_port_status)) {
struct ofp_port_status *ops = msg->data;
+ call_edit_port_callbacks(pw, &ops->desc);
update_phy_port(pw, &ops->desc, ops->reason, NULL);
}
return false;
}
+static bool
+port_watcher_remote_packet_cb(struct relay *r, void *pw_)
+{
+ struct port_watcher *pw = pw_;
+ struct ofpbuf *msg = r->halves[HALF_REMOTE].rxbuf;
+ struct ofp_header *oh = msg->data;
+
+ if (oh->type == OFPT_PORT_MOD
+ && msg->size >= sizeof(struct ofp_port_mod)) {
+ struct ofp_port_mod *opm = msg->data;
+ uint16_t port_no = ntohs(opm->desc.port_no);
+ int idx = port_no_to_pw_idx(port_no);
+ if (idx >= 0) {
+ struct ofp_phy_port *pw_opp = &pw->ports[idx];
+ if (pw_opp->port_no != htons(OFPP_NONE)) {
+ struct ofp_phy_port old = *pw_opp;
+ pw_opp->flags = ((pw_opp->flags & ~opm->mask)
+ | (opm->desc.flags & opm->mask));
+ call_port_changed_callbacks(pw, port_no, &old, pw_opp);
+ }
+ }
+ }
+ return false;
+}
+
static void
port_watcher_periodic_cb(void *pw_)
{
struct port_watcher *pw = pw_;
if (!pw->got_feature_reply && time_now() >= pw->last_feature_request + 5) {
- struct buffer *b;
+ struct ofpbuf *b;
make_openflow(sizeof(struct ofp_header), OFPT_FEATURES_REQUEST, &b);
rconn_send_with_limit(pw->local_rconn, b, &pw->n_txq, 1);
pw->last_feature_request = time_now();
static void
port_watcher_register_callback(struct port_watcher *pw,
- port_watcher_cb_func *function,
+ edit_port_cb_func *edit_port,
+ port_changed_cb_func *port_changed,
void *aux)
{
assert(pw->n_cbs < ARRAY_SIZE(pw->cbs));
- pw->cbs[pw->n_cbs].function = function;
+ pw->cbs[pw->n_cbs].edit_port = edit_port;
+ pw->cbs[pw->n_cbs].port_changed = port_changed;
pw->cbs[pw->n_cbs].aux = aux;
pw->n_cbs++;
}
struct ofp_phy_port *p;
struct ofp_port_mod *opm;
struct ofp_port_status *ops;
- struct buffer *b;
+ struct ofpbuf *b;
int idx;
idx = port_no_to_pw_idx(port_no);
old = *p;
/* Update our idea of the flags. */
- p->flags = ntohl(flags);
- call_pw_callbacks(pw, port_no, &old, p);
+ p->flags = htonl((ntohl(p->flags) & ~mask) | (flags & mask));
+ call_port_changed_callbacks(pw, port_no, &old, p);
/* Change the flags in the datapath. */
opm = make_openflow(sizeof *opm, OFPT_PORT_MOD, &b);
for (i = 0; i < OFPP_MAX; i++) {
pw->ports[i].port_no = htons(OFPP_NONE);
}
- port_watcher_register_callback(pw, log_port_status, NULL);
- return make_hook(port_watcher_local_packet_cb, NULL,
+ port_watcher_register_callback(pw, NULL, log_port_status, NULL);
+ return make_hook(port_watcher_local_packet_cb,
+ port_watcher_remote_packet_cb,
port_watcher_periodic_cb, NULL, pw);
}
\f
static bool
stp_local_packet_cb(struct relay *r, void *stp_)
{
+ struct ofpbuf *msg = r->halves[HALF_LOCAL].rxbuf;
+ struct ofp_header *oh;
struct stp_data *stp = stp_;
struct ofp_packet_in *opi;
struct eth_header *eth;
struct llc_header *llc;
- struct buffer payload;
+ struct ofpbuf payload;
uint16_t port_no;
struct flow flow;
+ oh = msg->data;
+ if (oh->type == OFPT_FEATURES_REPLY
+ && msg->size >= offsetof(struct ofp_switch_features, ports)) {
+ struct ofp_switch_features *osf = msg->data;
+ osf->capabilities |= htonl(OFPC_STP);
+ return false;
+ }
+
if (!get_ofp_packet_eth_header(r, &opi, ð)
|| !eth_addr_equals(eth->eth_dst, stp_eth_addr)) {
return false;
VLOG_DBG("non-LLC frame received on STP multicast address");
return false;
}
- llc = buffer_at_assert(&payload, sizeof *eth, sizeof *llc);
+ llc = ofpbuf_at_assert(&payload, sizeof *eth, sizeof *llc);
if (llc->llc_dsap != STP_LLC_DSAP) {
VLOG_DBG("bad DSAP 0x%02"PRIx8" received on STP multicast address",
llc->llc_dsap);
if (payload.size > ntohs(eth->eth_type) + ETH_HEADER_LEN) {
payload.size = ntohs(eth->eth_type) + ETH_HEADER_LEN;
}
- if (buffer_try_pull(&payload, ETH_HEADER_LEN + LLC_HEADER_LEN)) {
+ if (ofpbuf_try_pull(&payload, ETH_HEADER_LEN + LLC_HEADER_LEN)) {
struct stp_port *p = stp_get_port(stp->stp, port_no);
stp_received_bpdu(p, payload.data, payload.size);
}
struct stp_data *stp = stp_;
struct eth_header *eth;
struct llc_header *llc;
- struct buffer pkt, *opo;
+ struct ofpbuf pkt, *opo;
/* Packet skeleton. */
- buffer_init(&pkt, ETH_HEADER_LEN + LLC_HEADER_LEN + bpdu_size);
- eth = buffer_put_uninit(&pkt, sizeof *eth);
- llc = buffer_put_uninit(&pkt, sizeof *llc);
- buffer_put(&pkt, bpdu, bpdu_size);
+ ofpbuf_init(&pkt, ETH_HEADER_LEN + LLC_HEADER_LEN + bpdu_size);
+ eth = ofpbuf_put_uninit(&pkt, sizeof *eth);
+ llc = ofpbuf_put_uninit(&pkt, sizeof *llc);
+ ofpbuf_put(&pkt, bpdu, bpdu_size);
/* 802.2 header. */
memcpy(eth->eth_dst, stp_eth_addr, ETH_ADDR_LEN);
llc->llc_cntl = STP_LLC_CNTL;
opo = make_unbuffered_packet_out(&pkt, OFPP_NONE, port_no);
- buffer_uninit(&pkt);
+ ofpbuf_uninit(&pkt);
rconn_send_with_limit(stp->local_rconn, opo, &stp->n_txq, OFPP_MAX);
}
+static bool
+stp_is_port_supported(uint16_t port_no)
+{
+ /* STP only supports a maximum of 255 ports, one less than OpenFlow. We
+ * don't support STP on OFPP_LOCAL, either. */
+ return port_no < STP_MAX_PORTS;
+}
+
static void
-stp_port_watcher_cb(uint16_t port_no,
+stp_edit_port_cb(struct ofp_phy_port *p, void *stp_ UNUSED)
+{
+ uint16_t port_no = ntohs(p->port_no);
+ if (stp_is_port_supported(port_no)) {
+ p->features |= htonl(OFPPF_STP);
+ }
+}
+
+static void
+stp_port_changed_cb(uint16_t port_no,
const struct ofp_phy_port *old,
const struct ofp_phy_port *new,
void *stp_)
struct stp_data *stp = stp_;
struct stp_port *p;
- /* STP only supports a maximum of 255 ports, one less than OpenFlow. We
- * don't support STP on OFPP_LOCAL, either. */
- if (port_no >= STP_MAX_PORTS) {
+ if (!stp_is_port_supported(port_no)) {
return;
}
retval = netdev_open(s->of_name, NETDEV_ETH_TYPE_NONE, &netdev);
if (retval) {
- fatal(retval, "Could not open %s device", s->of_name);
+ ofp_fatal(retval, "Could not open %s device", s->of_name);
}
memcpy(dpid, netdev_get_etheraddr(netdev), ETH_ADDR_LEN);
netdev_close(netdev);
stp->remote_rconn = remote;
stp->last_tick_256ths = time_256ths();
- port_watcher_register_callback(pw, stp_port_watcher_cb, stp);
+ port_watcher_register_callback(pw, stp_edit_port_cb,
+ stp_port_changed_cb, stp);
return make_hook(stp_local_packet_cb, NULL,
stp_periodic_cb, stp_wait_cb, stp);
}
};
static void
-queue_tx(struct rconn *rc, struct in_band_data *in_band, struct buffer *b)
+queue_tx(struct rconn *rc, struct in_band_data *in_band, struct ofpbuf *b)
{
rconn_send_with_limit(rc, b, &in_band->n_queued, 10);
}
struct rconn *rc = r->halves[HALF_LOCAL].rconn;
struct ofp_packet_in *opi;
struct eth_header *eth;
- struct buffer payload;
+ struct ofpbuf payload;
struct flow flow;
uint16_t in_port;
int out_port;
} else {
/* We don't know that MAC. Send along the packet without setting up a
* flow. */
- struct buffer *b;
+ struct ofpbuf *b;
if (ntohl(opi->buffer_id) == UINT32_MAX) {
b = make_unbuffered_packet_out(&payload, in_port, out_port);
} else {
}
static void
-get_ofp_packet_payload(struct ofp_packet_in *opi, struct buffer *payload)
+get_ofp_packet_payload(struct ofp_packet_in *opi, struct ofpbuf *payload)
{
payload->data = opi->data;
payload->size = ntohs(opi->header.length) - offsetof(struct ofp_packet_in,
retval = netdev_open(s->of_name, NETDEV_ETH_TYPE_NONE,
&in_band->of_device);
if (retval) {
- fatal(retval, "Could not open %s device", s->of_name);
+ ofp_fatal(retval, "Could not open %s device", s->of_name);
}
memcpy(in_band->mac, netdev_get_etheraddr(in_band->of_device),
ETH_ADDR_LEN);
fail_open->remote_rconn = remote_rconn;
fail_open->lswitch = NULL;
fail_open->boot_deadline = time_now() + s->probe_interval * 3;
- fail_open->boot_deadline += STP_EXTRA_BOOT_TIME;
+ if (s->enable_stp) {
+ fail_open->boot_deadline += STP_EXTRA_BOOT_TIME;
+ }
switch_status_register_category(ss, "fail-open",
fail_open_status_cb, fail_open);
return make_hook(fail_open_local_packet_cb, NULL,
struct rconn *remote_rconn;
/* One queue per physical port. */
- struct queue queues[OFPP_MAX];
+ struct ofp_queue queues[OFPP_MAX];
int n_queued; /* Sum over queues[*].n. */
int next_tx_port; /* Next port to check in round-robin. */
static void
drop_packet(struct rate_limiter *rl)
{
- struct queue *longest; /* Queue currently selected as longest. */
+ struct ofp_queue *longest; /* Queue currently selected as longest. */
int n_longest; /* # of queues of same length as 'longest'. */
- struct queue *q;
+ struct ofp_queue *q;
longest = &rl->queues[0];
n_longest = 1;
}
/* FIXME: do we want to pop the tail instead? */
- buffer_delete(queue_pop_head(longest));
+ ofpbuf_delete(queue_pop_head(longest));
rl->n_queued--;
}
/* Remove and return the next packet to transmit (in round-robin order). */
-static struct buffer *
+static struct ofpbuf *
dequeue_packet(struct rate_limiter *rl)
{
unsigned int i;
for (i = 0; i < OFPP_MAX; i++) {
unsigned int port = (rl->next_tx_port + i) % OFPP_MAX;
- struct queue *q = &rl->queues[port];
+ struct ofp_queue *q = &rl->queues[port];
if (q->n) {
rl->next_tx_port = (port + 1) % OFPP_MAX;
rl->n_queued--;
return false;
} else {
/* Otherwise queue it up for the periodic callback to drain out. */
- struct buffer *msg = r->halves[HALF_LOCAL].rxbuf;
+ struct ofpbuf *msg = r->halves[HALF_LOCAL].rxbuf;
int port = ntohs(opi->in_port) % OFPP_MAX;
if (rl->n_queued >= s->burst_limit) {
drop_packet(rl);
}
- queue_push_tail(&rl->queues[port], buffer_clone(msg));
+ queue_push_tail(&rl->queues[port], ofpbuf_clone(msg));
rl->n_queued++;
rl->n_limited++;
return true;
* because the TCP connection is responsible for buffering and there is
* no point in trying to transmit faster than the TCP connection can
* handle. */
- struct buffer *b = dequeue_packet(rl);
+ struct ofpbuf *b = dequeue_packet(rl);
if (rconn_send_with_limit(rl->remote_rconn, b, &rl->n_txq, 10)) {
rl->n_tx_dropped++;
}
{
struct switch_status *ss = ss_;
struct rconn *rc = r->halves[HALF_REMOTE].rconn;
- struct buffer *msg = r->halves[HALF_REMOTE].rxbuf;
+ struct ofpbuf *msg = r->halves[HALF_REMOTE].rxbuf;
struct switch_status_category *c;
struct nicira_header *request;
struct nicira_header *reply;
struct status_reply sr;
- struct buffer *b;
+ struct ofpbuf *b;
int retval;
if (msg->size < sizeof(struct nicira_header)) {
/* Bring ofX network device up. */
retval = netdev_open(s->of_name, NETDEV_ETH_TYPE_NONE, &netdev);
if (retval) {
- fatal(retval, "Could not open %s device", s->of_name);
+ ofp_fatal(retval, "Could not open %s device", s->of_name);
}
retval = netdev_turn_flags_on(netdev, NETDEV_UP, true);
if (retval) {
- fatal(retval, "Could not bring %s device up", s->of_name);
+ ofp_fatal(retval, "Could not bring %s device up", s->of_name);
}
netdev_close(netdev);
retval = dhclient_create(s->of_name, modify_dhcp_request,
validate_dhcp_offer, (void *) s, &dhcp);
if (retval) {
- fatal(retval, "Failed to initialize DHCP client");
+ ofp_fatal(retval, "Failed to initialize DHCP client");
}
dhclient_init(dhcp, 0);
OPT_MAX_IDLE,
OPT_MAX_BACKOFF,
OPT_RATE_LIMIT,
- OPT_BURST_LIMIT
+ OPT_BURST_LIMIT,
+ OPT_BOOTSTRAP_CA_CERT,
+ OPT_NO_STP
};
static struct option long_options[] = {
{"accept-vconn", required_argument, 0, OPT_ACCEPT_VCONN},
{"monitor", required_argument, 0, 'm'},
{"rate-limit", optional_argument, 0, OPT_RATE_LIMIT},
{"burst-limit", required_argument, 0, OPT_BURST_LIMIT},
+ {"no-stp", no_argument, 0, OPT_NO_STP},
{"detach", no_argument, 0, 'D'},
{"force", no_argument, 0, 'f'},
{"pidfile", optional_argument, 0, 'P'},
{"verbose", optional_argument, 0, 'v'},
{"help", no_argument, 0, 'h'},
{"version", no_argument, 0, 'V'},
+#ifdef HAVE_OPENSSL
VCONN_SSL_LONG_OPTIONS
+ {"bootstrap-ca-cert", required_argument, 0, OPT_BOOTSTRAP_CA_CERT},
+#endif
{0, 0, 0, 0},
};
char *short_options = long_options_to_short_options(long_options);
s->update_resolv_conf = true;
s->rate_limit = 0;
s->burst_limit = 0;
+ s->enable_stp = true;
for (;;) {
int c;
} else if (!strcmp(optarg, "closed")) {
s->fail_mode = FAIL_CLOSED;
} else {
- fatal(0,
- "-f or --fail argument must be \"open\" or \"closed\"");
+ ofp_fatal(0, "-f or --fail argument must be \"open\" "
+ "or \"closed\"");
}
break;
case OPT_INACTIVITY_PROBE:
s->probe_interval = atoi(optarg);
if (s->probe_interval < 5) {
- fatal(0, "--inactivity-probe argument must be at least 5");
+ ofp_fatal(0, "--inactivity-probe argument must be at least 5");
}
break;
} else {
s->max_idle = atoi(optarg);
if (s->max_idle < 1 || s->max_idle > 65535) {
- fatal(0, "--max-idle argument must be between 1 and "
- "65535 or the word 'permanent'");
+ ofp_fatal(0, "--max-idle argument must be between 1 and "
+ "65535 or the word 'permanent'");
}
}
break;
case OPT_MAX_BACKOFF:
s->max_backoff = atoi(optarg);
if (s->max_backoff < 1) {
- fatal(0, "--max-backoff argument must be at least 1");
+ ofp_fatal(0, "--max-backoff argument must be at least 1");
} else if (s->max_backoff > 3600) {
s->max_backoff = 3600;
}
if (optarg) {
s->rate_limit = atoi(optarg);
if (s->rate_limit < 1) {
- fatal(0, "--rate-limit argument must be at least 1");
+ ofp_fatal(0, "--rate-limit argument must be at least 1");
}
} else {
s->rate_limit = 1000;
case OPT_BURST_LIMIT:
s->burst_limit = atoi(optarg);
if (s->burst_limit < 1) {
- fatal(0, "--burst-limit argument must be at least 1");
+ ofp_fatal(0, "--burst-limit argument must be at least 1");
}
break;
+ case OPT_NO_STP:
+ s->enable_stp = false;
+ break;
+
case 'D':
set_detach();
break;
case 'l':
if (s->n_listeners >= MAX_MGMT) {
- fatal(0, "-l or --listen may be specified at most %d times",
- MAX_MGMT);
+ ofp_fatal(0,
+ "-l or --listen may be specified at most %d times",
+ MAX_MGMT);
}
s->listener_names[s->n_listeners++] = optarg;
break;
case 'm':
if (s->monitor_name) {
- fatal(0, "-m or --monitor may only be specified once");
+ ofp_fatal(0, "-m or --monitor may only be specified once");
}
s->monitor_name = optarg;
break;
vlog_set_verbosity(optarg);
break;
+#ifdef HAVE_OPENSSL
VCONN_SSL_OPTION_HANDLERS
+ case OPT_BOOTSTRAP_CA_CERT:
+ vconn_ssl_set_ca_cert_file(optarg, true);
+ break;
+#endif
+
case '?':
exit(EXIT_FAILURE);
argc -= optind;
argv += optind;
if (argc < 1 || argc > 2) {
- fatal(0, "need one or two non-option arguments; use --help for usage");
+ ofp_fatal(0, "need one or two non-option arguments; "
+ "use --help for usage");
}
/* Local and remote vconns. */
if (strncmp(s->nl_name, "nl:", 3)
|| strlen(s->nl_name) < 4
|| s->nl_name[strspn(s->nl_name + 3, "0123456789") + 3]) {
- fatal(0, "%s: argument is not of the form \"nl:DP_IDX\"", s->nl_name);
+ ofp_fatal(0, "%s: argument is not of the form \"nl:DP_IDX\"",
+ s->nl_name);
}
s->of_name = xasprintf("of%s", s->nl_name + 3);
s->controller_name = argc > 1 ? xstrdup(argv[1]) : NULL;
size_t length = regerror(retval, &s->accept_controller_regex, NULL, 0);
char *buffer = xmalloc(length);
regerror(retval, &s->accept_controller_regex, buffer, length);
- fatal(0, "%s: %s", accept_re, buffer);
+ ofp_fatal(0, "%s: %s", accept_re, buffer);
}
s->accept_controller_re = accept_re;
retval = netdev_open(s->of_name, NETDEV_ETH_TYPE_NONE, &netdev);
if (retval) {
- fatal(retval, "Could not open %s device", s->of_name);
+ ofp_fatal(retval, "Could not open %s device", s->of_name);
}
retval = netdev_get_flags(netdev, &flags);
if (retval) {
- fatal(retval, "Could not get flags for %s device", s->of_name);
+ ofp_fatal(retval, "Could not get flags for %s device", s->of_name);
}
s->in_band = (flags & NETDEV_UP) != 0;
"CONTROLLER is an active OpenFlow connection method; if it is\n"
"omitted, then secchan performs controller discovery.\n",
program_name, program_name);
- vconn_usage(true, true);
+ vconn_usage(true, true, true);
printf("\nController discovery options:\n"
" --accept-vconn=REGEX accept matching discovered controllers\n"
" --no-resolv-conf do not update /etc/resolv.conf\n"
" (a passive OpenFlow connection method)\n"
" -m, --monitor=METHOD copy traffic to/from kernel to METHOD\n"
" (a passive OpenFlow connection method)\n"
+ " --no-stp disable 802.1D Spanning Tree Protocol\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"