aboutsummaryrefslogtreecommitdiff
path: root/utilities
diff options
context:
space:
mode:
authorBen Pfaff <blp@nicira.com>2011-10-19 21:33:44 -0700
committerBen Pfaff <blp@nicira.com>2011-10-21 15:07:36 -0700
commit7257b535ab8e5fafd811c5f6788205eefdd44948 (patch)
tree75072ea003837f756ce6910fb5e0ba3113db30be /utilities
parent4edb9ae90e4092f5f56b9d914d2b88783c49860d (diff)
Implement new fragment handling policy.
Until now, OVS has handled IP fragments more awkwardly than necessary. It has not been possible to match on L4 headers, even in fragments with offset 0 where they are actually present. This means that there was no way to implement ACLs that treat, say, different TCP ports differently, on fragmented traffic; instead, all decisions for fragment forwarding had to be made on the basis of L2 and L3 headers alone. This commit improves the situation significantly. It is still not possible to match on L4 headers in fragments with nonzero offset, because that information is simply not present in such fragments, but this commit adds the ability to match on L4 headers for fragments with zero offset. This means that it becomes possible to implement ACLs that drop such "first fragments" on the basis of L4 headers. In practice, that effectively blocks even fragmented traffic on an L4 basis, because the receiving IP stack cannot reassemble a full packet when the first fragment is missing. This commit works by adding a new "fragment type" to the kernel flow match and making it available through OpenFlow as a new NXM field named NXM_NX_IP_FRAG. Because OpenFlow 1.0 explicitly says that the L4 fields are always 0 for IP fragments, it adds a new OpenFlow fragment handling mode that fills in the L4 fields for "first fragments". It also enhances ovs-ofctl to allow users to configure this new fragment handling mode and to parse the new field. Signed-off-by: Ben Pfaff <blp@nicira.com> Bug #7557.
Diffstat (limited to 'utilities')
-rw-r--r--utilities/ovs-dpctl.c9
-rw-r--r--utilities/ovs-ofctl.8.in54
-rw-r--r--utilities/ovs-ofctl.c105
3 files changed, 154 insertions, 14 deletions
diff --git a/utilities/ovs-dpctl.c b/utilities/ovs-dpctl.c
index 4d0d3c2d..d78fb317 100644
--- a/utilities/ovs-dpctl.c
+++ b/utilities/ovs-dpctl.c
@@ -371,12 +371,9 @@ show_dpif(struct dpif *dpif)
printf("%s:\n", dpif_name(dpif));
if (!dpif_get_dp_stats(dpif, &stats)) {
- printf("\tlookups: frags:%"PRIu64, stats.n_frags);
- printf(" hit:%"PRIu64, stats.n_hit);
- printf(" missed:%"PRIu64, stats.n_missed);
- printf(" lost:%"PRIu64"\n", stats.n_lost);
-
- printf("\tflows: %"PRIu64"\n", stats.n_flows);
+ printf("\tlookups: hit:%"PRIu64" missed:%"PRIu64" lost:%"PRIu64"\n"
+ "\tflows: %"PRIu64"\n",
+ stats.n_hit, stats.n_missed, stats.n_lost, stats.n_flows);
}
DPIF_PORT_FOR_EACH (&dpif_port, &dump, dpif) {
printf("\tport %u: %s", dpif_port.port_no, dpif_port.name);
diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in
index f2ed8a48..215f8f92 100644
--- a/utilities/ovs-ofctl.8.in
+++ b/utilities/ovs-ofctl.8.in
@@ -92,6 +92,39 @@ spanning tree protocol is not in use.
.
.RE
.
+.IP "\fBget\-frags \fIswitch\fR"
+Prints \fIswitch\fR's fragment handling mode. See \fBset\-frags\fR,
+below, for a description of each fragment handling mode.
+.IP
+The \fBshow\fR command also prints the fragment handling mode among
+its other output.
+.
+.IP "\fBset\-frags \fIswitch frag_mode\fR"
+Configures \fIswitch\fR's treatment of IPv4 and IPv6 fragments. The
+choices for \fIfrag_mode\fR are:
+.RS
+.IP "\fBnormal\fR"
+Fragments pass through the flow table like non-fragmented packets.
+The TCP ports, UDP ports, and ICMP type and code fields are always set
+to 0, even for fragments where that information would otherwise be
+available (fragments with offset 0). This is the default fragment
+handling mode for an OpenFlow switch.
+.IP "\fBdrop\fR"
+Fragments are dropped without passing through the flow table.
+.IP "\fBreassemble\fR"
+The switch reassembles fragments into full IP packets before passing
+them through the flow table. Open vSwitch does not implement this
+fragment handling mode.
+.IP "\fBnx\-match\fR"
+Fragments pass through the flow table like non-fragmented packets.
+The TCP ports, UDP ports, and ICMP type and code fields are available
+for matching for fragments with offset 0, and set to 0 in fragments
+with nonzero offset. This mode is a Nicira extension.
+.RE
+.IP
+See the description of \fBip_frag\fR, below, for a way to match on
+whether a packet is a fragment and on its fragment offset.
+.
.TP
\fBdump\-flows \fIswitch \fR[\fIflows\fR]
Prints to the console all flow entries in \fIswitch\fR's
@@ -476,6 +509,27 @@ Match packets with no 802.1Q header or tagged with VLAN 0 and priority
Some of these matching possibilities can also be achieved with
\fBdl_vlan\fR and \fBdl_vlan_pcp\fR.
.
+.IP \fBip_frag=\fIfrag_type\fR
+When \fBdl_type\fR specifies IP or IPv6, \fIfrag_type\fR
+specifies what kind of IP fragments or non-fragments to match. The
+following values of \fIfrag_type\fR are supported:
+.RS
+.IP "\fBno\fR"
+Matches only non-fragmented packets.
+.IP "\fByes\fR"
+Matches all fragments.
+.IP "\fBfirst\fR"
+Matches only fragments with offset 0.
+.IP "\fBlater\fR"
+Matches only fragments with nonzero offset.
+.IP "\fBnot_later\fR"
+Matches non-fragmented packets and fragments with zero offset.
+.RE
+.IP
+The \fBip_frag\fR match type is likely to be most useful in
+\fBnx\-match\fR mode. See the description of the \fBset\-frags\fR
+command, above, for more details.
+.
.IP \fBarp_sha=\fIxx\fB:\fIxx\fB:\fIxx\fB:\fIxx\fB:\fIxx\fB:\fIxx\fR
.IQ \fBarp_tha=\fIxx\fB:\fIxx\fB:\fIxx\fB:\fIxx\fB:\fIxx\fB:\fIxx\fR
When \fBdl_type\fR specifies ARP, \fBarp_sha\fR and \fBarp_tha\fR match
diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c
index 164d0830..ce9723b9 100644
--- a/utilities/ovs-ofctl.c
+++ b/utilities/ovs-ofctl.c
@@ -172,6 +172,8 @@ usage(void)
" dump-desc SWITCH print switch description\n"
" dump-tables SWITCH print table stats\n"
" mod-port SWITCH IFACE ACT modify port behavior\n"
+ " get-frags SWITCH print fragment handling behavior\n"
+ " set-frags SWITCH FRAG_MODE set fragment handling behavior\n"
" dump-ports SWITCH [PORT] print port statistics\n"
" dump-flows SWITCH print all flow entries\n"
" dump-flows SWITCH FLOW print matching FLOWs\n"
@@ -351,7 +353,9 @@ dump_trivial_stats_transaction(const char *vconn_name, uint8_t stats_type)
/* Sends 'request', which should be a request that only has a reply if an error
* occurs, and waits for it to succeed or fail. If an error does occur, prints
- * it and exits with an error. */
+ * it and exits with an error.
+ *
+ * Destroys all of the 'requests'. */
static void
transact_multiple_noreply(struct vconn *vconn, struct list *requests)
{
@@ -372,7 +376,9 @@ transact_multiple_noreply(struct vconn *vconn, struct list *requests)
/* Sends 'request', which should be a request that only has a reply if an error
* occurs, and waits for it to succeed or fail. If an error does occur, prints
- * it and exits with an error. */
+ * it and exits with an error.
+ *
+ * Destroys 'request'. */
static void
transact_noreply(struct vconn *vconn, struct ofpbuf *request)
{
@@ -384,6 +390,44 @@ transact_noreply(struct vconn *vconn, struct ofpbuf *request)
}
static void
+fetch_switch_config(struct vconn *vconn, struct ofp_switch_config *config_)
+{
+ struct ofp_switch_config *config;
+ struct ofp_header *header;
+ struct ofpbuf *request;
+ struct ofpbuf *reply;
+
+ make_openflow(sizeof(struct ofp_header), OFPT_GET_CONFIG_REQUEST,
+ &request);
+ run(vconn_transact(vconn, request, &reply),
+ "talking to %s", vconn_get_name(vconn));
+
+ header = reply->data;
+ if (header->type != OFPT_GET_CONFIG_REPLY ||
+ header->length != htons(sizeof *config)) {
+ ovs_fatal(0, "%s: bad reply to config request", vconn_get_name(vconn));
+ }
+
+ config = reply->data;
+ *config_ = *config;
+}
+
+static void
+set_switch_config(struct vconn *vconn, struct ofp_switch_config *config_)
+{
+ struct ofp_switch_config *config;
+ struct ofp_header save_header;
+ struct ofpbuf *request;
+
+ config = make_openflow(sizeof *config, OFPT_SET_CONFIG, &request);
+ save_header = config->header;
+ *config = *config_;
+ config->header = save_header;
+
+ transact_noreply(vconn, request);
+}
+
+static void
do_show(int argc OVS_UNUSED, char *argv[])
{
dump_trivial_transaction(argv[1], OFPT_FEATURES_REQUEST);
@@ -720,13 +764,11 @@ do_monitor(int argc, char *argv[])
open_vconn(argv[1], &vconn);
if (argc > 2) {
- int miss_send_len = atoi(argv[2]);
- struct ofp_switch_config *osc;
- struct ofpbuf *buf;
+ struct ofp_switch_config config;
- osc = make_openflow(sizeof *osc, OFPT_SET_CONFIG, &buf);
- osc->miss_send_len = htons(miss_send_len);
- transact_noreply(vconn, buf);
+ fetch_switch_config(vconn, &config);
+ config.miss_send_len = htons(atoi(argv[2]));
+ set_switch_config(vconn, &config);
}
monitor_vconn(vconn);
}
@@ -807,6 +849,51 @@ do_mod_port(int argc OVS_UNUSED, char *argv[])
}
static void
+do_get_frags(int argc OVS_UNUSED, char *argv[])
+{
+ struct ofp_switch_config config;
+ struct vconn *vconn;
+
+ open_vconn(argv[1], &vconn);
+ fetch_switch_config(vconn, &config);
+ puts(ofputil_frag_handling_to_string(ntohs(config.flags)));
+ vconn_close(vconn);
+}
+
+static void
+do_set_frags(int argc OVS_UNUSED, char *argv[])
+{
+ struct ofp_switch_config config;
+ enum ofp_config_flags mode;
+ struct vconn *vconn;
+ ovs_be16 flags;
+
+ if (!ofputil_frag_handling_from_string(argv[2], &mode)) {
+ ovs_fatal(0, "%s: unknown fragment handling mode", argv[2]);
+ }
+
+ open_vconn(argv[1], &vconn);
+ fetch_switch_config(vconn, &config);
+ flags = htons(mode) | (config.flags & htons(~OFPC_FRAG_MASK));
+ if (flags != config.flags) {
+ /* Set the configuration. */
+ config.flags = flags;
+ set_switch_config(vconn, &config);
+
+ /* Then retrieve the configuration to see if it really took. OpenFlow
+ * doesn't define error reporting for bad modes, so this is all we can
+ * do. */
+ fetch_switch_config(vconn, &config);
+ if (flags != config.flags) {
+ ovs_fatal(0, "%s: setting fragment handling mode failed (this "
+ "switch probably doesn't support mode \"%s\")",
+ argv[1], ofputil_frag_handling_to_string(mode));
+ }
+ }
+ vconn_close(vconn);
+}
+
+static void
do_ping(int argc, char *argv[])
{
size_t max_payload = 65535 - sizeof(struct ofp_header);
@@ -1442,6 +1529,8 @@ static const struct command all_commands[] = {
{ "diff-flows", 2, 2, do_diff_flows },
{ "dump-ports", 1, 2, do_dump_ports },
{ "mod-port", 3, 3, do_mod_port },
+ { "get-frags", 1, 1, do_get_frags },
+ { "set-frags", 2, 2, do_set_frags },
{ "probe", 1, 1, do_probe },
{ "ping", 1, 2, do_ping },
{ "benchmark", 3, 3, do_benchmark },