Add --max-idle option to secchan and controller.
This commit is contained in:
1 parent
58dc4ead3b
commit
5aca80fab9
8 files changed
+105
-16
No files matched your search
@@ -73,6 +73,21 @@ in the network passes through the controller.
|
||||
This option is most useful for debugging. It reduces switching
|
||||
performance, so it should not be used in production.
|
||||
|
||||
.TP
|
||||
\fB--max-idle=\fIsecs\fR|\fBpermanent\fR
|
||||
Sets \fIsecs\fR as the number of seconds that a flow set up by the
|
||||
controller will remain in the switch's flow table without any matching
|
||||
packets being seen. If \fBpermanent\fR is specified, which is not
|
||||
recommended, flows will never expire. The default is 60 seconds.
|
||||
|
||||
This option affects only flows set up by the OpenFlow controller. In
|
||||
some configurations, the OpenFlow secure channel can set up some flows
|
||||
on its own. To set the idle time for those flows, pass
|
||||
\fB--max-idle\fR to \fBsecchan\fR(8).
|
||||
|
||||
This option has no effect when \fB-n\fR (or \fB--noflow\fR) is in use
|
||||
(because the controller does not set up flows in that case).
|
||||
|
||||
.TP
|
||||
.BR \-H ", " \-\^\-hub
|
||||
By default, the controller acts as an L2 MAC-learning switch. This
|
||||
|
||||
+22
-1
@@ -33,6 +33,7 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -42,6 +43,7 @@
|
||||
#include "daemon.h"
|
||||
#include "fault.h"
|
||||
#include "learning-switch.h"
|
||||
#include "openflow.h"
|
||||
#include "poll-loop.h"
|
||||
#include "rconn.h"
|
||||
#include "util.h"
|
||||
@@ -66,6 +68,9 @@ static bool learn_macs = true;
|
||||
/* 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[]);
|
||||
@@ -189,7 +194,8 @@ 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->lswitch = lswitch_create(sw->rconn, learn_macs,
|
||||
setup_flows ? max_idle : -1);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -215,11 +221,13 @@ do_switching(struct switch_ *sw)
|
||||
static void
|
||||
parse_options(int argc, char *argv[])
|
||||
{
|
||||
enum { OPT_MAX_IDLE = UCHAR_MAX + 1 };
|
||||
static struct option long_options[] = {
|
||||
{"detach", no_argument, 0, 'D'},
|
||||
{"pidfile", optional_argument, 0, 'P'},
|
||||
{"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'},
|
||||
@@ -254,6 +262,18 @@ parse_options(int argc, char *argv[])
|
||||
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) {
|
||||
fatal(0, "--max-idle argument must be between 1 and "
|
||||
"65535 or the word 'permanent'");
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
usage();
|
||||
|
||||
@@ -290,6 +310,7 @@ usage(void)
|
||||
" -P, --pidfile[=FILE] create pidfile (default: %s/controller.pid)\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 configure logging levels\n"
|
||||
" -v, --verbose set maximum verbosity level\n"
|
||||
" -h, --help display this help message\n"
|
||||
|
||||
@@ -39,8 +39,7 @@
|
||||
struct buffer;
|
||||
struct rconn;
|
||||
|
||||
struct lswitch *lswitch_create(struct rconn *,
|
||||
bool learn_macs, bool setup_flows);
|
||||
struct lswitch *lswitch_create(struct rconn *, bool learn_macs, int max_idle);
|
||||
void lswitch_destroy(struct lswitch *);
|
||||
void lswitch_process_packet(struct lswitch *, struct rconn *,
|
||||
const struct buffer *);
|
||||
|
||||
+2
-1
@@ -75,7 +75,8 @@ void vconn_recv_wait(struct vconn *);
|
||||
void vconn_send_wait(struct vconn *);
|
||||
|
||||
struct buffer *make_add_simple_flow(const struct flow *,
|
||||
uint32_t buffer_id, uint16_t out_port);
|
||||
uint32_t buffer_id, uint16_t out_port,
|
||||
uint16_t max_idle);
|
||||
struct buffer *make_buffered_packet_out(uint32_t buffer_id,
|
||||
uint16_t in_port, uint16_t out_port);
|
||||
struct buffer *make_unbuffered_packet_out(const struct buffer *packet,
|
||||
|
||||
+12
-7
@@ -53,7 +53,11 @@
|
||||
#include "vlog.h"
|
||||
|
||||
struct lswitch {
|
||||
bool setup_flows; /* Set up flows? (or controller processes all packets) */
|
||||
/* If nonnegative, the switch sets up flows that expire after the given
|
||||
* number of seconds (or never expire, if the value is OFP_FLOW_PERMANENT).
|
||||
* Otherwise, the switch processes every packet. */
|
||||
int max_idle;
|
||||
|
||||
uint64_t datapath_id;
|
||||
time_t last_features_request;
|
||||
struct mac_learning *ml; /* NULL to act as hub instead of switch. */
|
||||
@@ -69,16 +73,17 @@ static void process_packet_in(struct lswitch *, struct rconn *,
|
||||
* If 'learn_macs' is true, the new switch will learn the ports on which MAC
|
||||
* addresses appear. Otherwise, the new switch will flood all packets.
|
||||
*
|
||||
* If 'setup_flows' is true, the new switch will set up flows. Otherwise, the
|
||||
* new switch will process every packet.
|
||||
* If 'max_idle' is nonnegative, the new switch will set up flows that expire
|
||||
* after the given number of seconds (or never expire, if 'max_idle' is
|
||||
* OFP_FLOW_PERMANENT). Otherwise, the new switch will process every packet.
|
||||
*
|
||||
* 'rconn' is used to send out an OpenFlow features request. */
|
||||
struct lswitch *
|
||||
lswitch_create(struct rconn *rconn, bool learn_macs, bool setup_flows)
|
||||
lswitch_create(struct rconn *rconn, bool learn_macs, int max_idle)
|
||||
{
|
||||
struct lswitch *sw = xmalloc(sizeof *sw);
|
||||
memset(sw, 0, sizeof *sw);
|
||||
sw->setup_flows = setup_flows;
|
||||
sw->max_idle = max_idle;
|
||||
sw->datapath_id = 0;
|
||||
sw->last_features_request = 0;
|
||||
sw->ml = learn_macs ? mac_learning_create() : NULL;
|
||||
@@ -213,11 +218,11 @@ process_packet_in(struct lswitch *sw, struct rconn *rconn,
|
||||
out_port = mac_learning_lookup(sw->ml, flow.dl_dst);
|
||||
}
|
||||
|
||||
if (sw->setup_flows && (!sw->ml || out_port != OFPP_FLOOD)) {
|
||||
if (sw->max_idle >= 0 && (!sw->ml || out_port != OFPP_FLOOD)) {
|
||||
/* The output port is known, or we always flood everything, so add a
|
||||
* new flow. */
|
||||
queue_tx(sw, rconn, make_add_simple_flow(&flow, ntohl(opi->buffer_id),
|
||||
out_port));
|
||||
out_port, sw->max_idle));
|
||||
|
||||
/* If the switch didn't buffer the packet, we need to send a copy. */
|
||||
if (ntohl(opi->buffer_id) == UINT32_MAX) {
|
||||
|
||||
+2
-2
@@ -370,7 +370,7 @@ vconn_send_wait(struct vconn *vconn)
|
||||
|
||||
struct buffer *
|
||||
make_add_simple_flow(const struct flow *flow,
|
||||
uint32_t buffer_id, uint16_t out_port)
|
||||
uint32_t buffer_id, uint16_t out_port, uint16_t max_idle)
|
||||
{
|
||||
struct ofp_flow_mod *ofm;
|
||||
size_t size = sizeof *ofm + sizeof ofm->actions[0];
|
||||
@@ -392,7 +392,7 @@ make_add_simple_flow(const struct flow *flow,
|
||||
ofm->match.tp_src = flow->tp_src;
|
||||
ofm->match.tp_dst = flow->tp_dst;
|
||||
ofm->command = htons(OFPFC_ADD);
|
||||
ofm->max_idle = htons(60);
|
||||
ofm->max_idle = htons(max_idle);
|
||||
ofm->buffer_id = htonl(buffer_id);
|
||||
ofm->actions[0].type = htons(OFPAT_OUTPUT);
|
||||
ofm->actions[0].arg.output.max_len = htons(0);
|
||||
|
||||
+29
-1
@@ -115,7 +115,35 @@ seconds.
|
||||
This option has no effect when \fB--fail=closed\fR is specified.
|
||||
|
||||
.TP
|
||||
\fB-l\Fr, \Fb--listen=\fImethod\fR
|
||||
\fB--max-idle=\fIsecs\fR|\fBpermanent\fR
|
||||
Sets \fIsecs\fR as the number of seconds that a flow set up by the
|
||||
secure channel will remain in the switch's flow table without any
|
||||
matching packets being seen. If \fBpermanent\fR is specified, which
|
||||
is not recommended, flows set up by the secure channel will never
|
||||
expire. The default is 15 seconds.
|
||||
|
||||
Most flows are set up by the OpenFlow controller, not by the secure
|
||||
channel. This option affects only the following flows, which the
|
||||
secure channel sets up itself:
|
||||
|
||||
.RS
|
||||
.IP \(bu
|
||||
When \fB--fail=open\fR is specified, flows set up when the secure
|
||||
channel has not been able to contact the controller for the configured
|
||||
fail-open delay.
|
||||
|
||||
.IP \(bu
|
||||
When in-band control is in use, flows set up to bootstrap contacting
|
||||
the controller (see \fBCONTACTING THE CONTROLLER\fR, above, for
|
||||
more information about in-band control).
|
||||
.RE
|
||||
|
||||
.IP
|
||||
As a result, when both \fB--fail=open\fR and in-band control are not
|
||||
in use, this option has no effect.
|
||||
|
||||
.TP
|
||||
\fB-l\fR, \fB--listen=\fImethod\fR
|
||||
Configures the switch to additionally listen for incoming OpenFlow
|
||||
connections for switch management with \fBdpctl\fR. The \fImethod\fR
|
||||
must be given as one of the following passive OpenFlow connection
|
||||
|
||||
+22
-2
@@ -107,6 +107,10 @@ static enum fail_mode fail_mode = FAIL_OPEN;
|
||||
* fail_mode is FAIL_OPEN. */
|
||||
static int fail_open_delay = 30;
|
||||
|
||||
/* --max-idle: Idle time to assign to flows created by learning switch when in
|
||||
* fail-open mode. */
|
||||
static int max_idle = 15;
|
||||
|
||||
static void parse_options(int argc, char *argv[]);
|
||||
static void usage(void) NO_RETURN;
|
||||
|
||||
@@ -409,7 +413,8 @@ local_hook(struct relay *r)
|
||||
|
||||
/* Add new flow. */
|
||||
if (out_port != OFPP_FLOOD) {
|
||||
b = make_add_simple_flow(&flow, ntohl(opi->buffer_id), out_port);
|
||||
b = make_add_simple_flow(&flow, ntohl(opi->buffer_id), out_port,
|
||||
max_idle);
|
||||
if (rconn_force_send(rc, b)) {
|
||||
buffer_delete(b);
|
||||
}
|
||||
@@ -453,7 +458,7 @@ fail_open_hook(struct relay *r)
|
||||
if (!r->lswitch) {
|
||||
VLOG_WARN("Could not connect to controller for %d seconds, "
|
||||
"failing open", disconnected_duration);
|
||||
r->lswitch = lswitch_create(local, true, true);
|
||||
r->lswitch = lswitch_create(local, true, max_idle);
|
||||
}
|
||||
|
||||
/* Do switching. */
|
||||
@@ -465,9 +470,11 @@ fail_open_hook(struct relay *r)
|
||||
static void
|
||||
parse_options(int argc, char *argv[])
|
||||
{
|
||||
enum { OPT_MAX_IDLE = UCHAR_MAX + 1 };
|
||||
static struct option long_options[] = {
|
||||
{"fail", required_argument, 0, 'f'},
|
||||
{"fail-open-delay", required_argument, 0, 'd'},
|
||||
{"max-idle", required_argument, 0, OPT_MAX_IDLE},
|
||||
{"listen", required_argument, 0, 'l'},
|
||||
{"detach", no_argument, 0, 'D'},
|
||||
{"pidfile", optional_argument, 0, 'P'},
|
||||
@@ -507,6 +514,18 @@ parse_options(int argc, char *argv[])
|
||||
}
|
||||
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) {
|
||||
fatal(0, "--max-idle argument must be between 1 and "
|
||||
"65535 or the word 'permanent'");
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
set_detach();
|
||||
break;
|
||||
@@ -560,6 +579,7 @@ usage(void)
|
||||
" open (default): act as learning switch\n"
|
||||
" -d, --fail-open-delay=SECS number of seconds after which to\n"
|
||||
" fail open if --fail=open (default: 30)\n"
|
||||
" --max-idle=SECS max idle for flows set up by secchan\n"
|
||||
" -l, --listen=METHOD allow management connections on METHOD\n"
|
||||
" (a passive OpenFlow connection method)\n"
|
||||
"\nOther options:\n"
|
||||
|
||||
Reference in new issue
Block a user