2010-05-27 13:14:05 -07:00
|
|
|
|
/*
|
ofp-actions: Fix variable length meta-flow OXMs.
Previously, if a flow action that involves a tunnel metadata meta-flow
field is dumped from vswitchd, the replied field length in the OXM header
is filled with the maximum possible field length, instead of the length
configured in the tunnel TLV mapping table. To solve this issue, this patch
introduces the following changes.
In order to maintain the correct length of variable length mf_fields (i.e.
tun_metadata), this patch creates a per-switch based map (struct vl_mff_map)
that hosts the variable length mf_fields. This map is updated when a
controller adds/deletes tlv-mapping entries to/from a switch. Although the
per-swtch based vl_mff_map only hosts tun_metadata for now, it is able to
support new variable length mf_fields in the future.
With this commit, when a switch decodes a flow action with mf_field, the switch
firstly looks up the global mf_fields map to identify the mf_field type. For
the variable length mf_fields, the switch uses the vl_mff_map to get the
configured mf_field entries. By lookig up vl_mff_map, the switch can check
if the added flow action access beyond the configured size of a variable
length mf_field, and the switch reports an ofperr if the controller adds a flow
with unmapped variable length mf_field. Later on, when a controller request
flows from the switch, with the per-switch based mf_fields, the switch will
encode the OXM header with correct length for variable length mf_fields.
To use the vl_mff_map for decoding flow actions, extract-ofp-actions is
updated to pass the vl_mff_map to the required action decoding functions.
Also, a new error code is introduced to identify a flow with an invalid
variable length mf_field. Moreover, a testcase is added to prevent future
regressions.
Committer notes:
- Factor out common code
- Style fixups
- Rename OFPERR_NXFMFC_INVALID_VL_MFF -> OFPERR_NXFMFC_INVALID_TLV_FIELD
VMWare-BZ: #1768370
Reported-by: Harold Lim <haroldl@vmware.com>
Suggested-by: Joe Stringer <joe@ovn.org>
Suggested-by: Jarno Rajahalme <jarno@ovn.org>
Signed-off-by: Yi-Hung Wei <yihung.wei@gmail.com>
Signed-off-by: Joe Stringer <joe@ovn.org>
2017-01-20 15:12:21 -08:00
|
|
|
|
* Copyright (c) 2008-2017 Nicira, Inc.
|
2010-05-27 13:14:05 -07:00
|
|
|
|
*
|
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
|
* You may obtain a copy of the License at:
|
|
|
|
|
*
|
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
*
|
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
|
* limitations under the License.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <config.h>
|
2018-02-09 10:04:26 -08:00
|
|
|
|
#include "openvswitch/ofp-util.h"
|
2012-11-04 21:40:54 -08:00
|
|
|
|
#include <ctype.h>
|
2011-01-12 13:42:50 -08:00
|
|
|
|
#include <errno.h>
|
2010-05-27 13:14:05 -07:00
|
|
|
|
#include <inttypes.h>
|
2011-11-01 13:25:49 +01:00
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
#include <netinet/in.h>
|
2011-05-09 16:25:48 -07:00
|
|
|
|
#include <netinet/icmp6.h>
|
2010-05-27 13:14:05 -07:00
|
|
|
|
#include <stdlib.h>
|
2016-04-14 15:20:21 -07:00
|
|
|
|
#include "bitmap.h"
|
2011-06-10 17:45:45 -07:00
|
|
|
|
#include "bundle.h"
|
2010-10-28 17:13:18 -07:00
|
|
|
|
#include "byte-order.h"
|
2010-11-10 14:39:54 -08:00
|
|
|
|
#include "classifier.h"
|
2011-09-12 16:19:57 -07:00
|
|
|
|
#include "learn.h"
|
2012-02-15 16:33:04 -08:00
|
|
|
|
#include "multipath.h"
|
2012-02-15 14:23:38 -08:00
|
|
|
|
#include "netdev.h"
|
2010-11-11 10:41:33 -08:00
|
|
|
|
#include "nx-match.h"
|
2014-11-11 12:39:19 +09:00
|
|
|
|
#include "id-pool.h"
|
2016-04-04 21:32:10 -04:00
|
|
|
|
#include "openflow/netronome-ext.h"
|
|
|
|
|
#include "openvswitch/dynamic-string.h"
|
2017-05-31 16:06:12 -07:00
|
|
|
|
#include "openvswitch/json.h"
|
2016-04-04 21:32:10 -04:00
|
|
|
|
#include "openvswitch/meta-flow.h"
|
2016-04-14 15:20:19 -07:00
|
|
|
|
#include "openvswitch/ofp-actions.h"
|
2016-04-04 21:32:10 -04:00
|
|
|
|
#include "openvswitch/ofp-errors.h"
|
|
|
|
|
#include "openvswitch/ofp-msgs.h"
|
2016-04-14 15:20:21 -07:00
|
|
|
|
#include "openvswitch/ofp-print.h"
|
2016-04-14 15:20:20 -07:00
|
|
|
|
#include "openvswitch/ofp-prop.h"
|
2016-03-25 14:10:24 -07:00
|
|
|
|
#include "openvswitch/ofpbuf.h"
|
2016-04-04 21:32:10 -04:00
|
|
|
|
#include "openvswitch/type-props.h"
|
|
|
|
|
#include "openvswitch/vlog.h"
|
2016-05-05 09:46:01 +01:00
|
|
|
|
#include "openflow/intel-ext.h"
|
2010-05-27 13:14:05 -07:00
|
|
|
|
#include "packets.h"
|
|
|
|
|
#include "random.h"
|
openflow: Table maintenance commands for Geneve options.
In order to work with Geneve options, we need to maintain a mapping
table between an option (defined by <class, type, length>) and
an NXM field that can be operated on for the purposes of matches,
actions, etc. This mapping must be explicitly specified by the
user.
Conceptually, this table could be communicated using either OpenFlow
or OVSDB. Using OVSDB requires less code and definition of extensions
than OpenFlow but introduces the possibility that mapping table
updates and flow modifications are desynchronized from each other.
This is dangerous because the mapping table signifcantly impacts the
way that flows using Geneve options are installed and processed by
OVS. Therefore, the mapping table is maintained using OpenFlow commands
instead, which opens the possibility of using synchronization between
table changes and flow modifications through barriers, bundles, etc.
There are two primary groups of OpenFlow messages that are introduced
as Nicira extensions: modification commands (add, delete, clear mappings)
and table status request/reply to dump the current table along with switch
information.
Note that mappings should not be changed while they are in active use by
a flow. The result of doing so is undefined.
This only adds the OpenFlow infrastructure but doesn't actually
do anything with the information yet after the messages have been
decoded.
Signed-off-by: Jesse Gross <jesse@nicira.com>
Acked-by: Ben Pfaff <blp@nicira.com>
2015-06-02 15:11:00 -07:00
|
|
|
|
#include "tun-metadata.h"
|
2011-03-10 15:02:05 -08:00
|
|
|
|
#include "unaligned.h"
|
2016-07-12 16:37:34 -05:00
|
|
|
|
#include "util.h"
|
2016-04-04 21:32:04 -04:00
|
|
|
|
#include "uuid.h"
|
2010-05-27 13:14:05 -07:00
|
|
|
|
|
2010-10-19 14:47:01 -07:00
|
|
|
|
VLOG_DEFINE_THIS_MODULE(ofp_util);
|
2010-05-27 13:14:05 -07:00
|
|
|
|
|
|
|
|
|
/* Rate limit for OpenFlow message parse errors. These always indicate a bug
|
|
|
|
|
* in the peer and so there's not much point in showing a lot of them. */
|
|
|
|
|
static struct vlog_rate_limit bad_ofmsg_rl = VLOG_RATE_LIMIT_INIT(1, 5);
|
2018-02-09 10:04:26 -08:00
|
|
|
|
|
|
|
|
|
static bool
|
|
|
|
|
ofputil_decode_hello_bitmap(const struct ofp_hello_elem_header *oheh,
|
|
|
|
|
uint32_t *allowed_versionsp)
|
2010-11-10 14:39:54 -08:00
|
|
|
|
{
|
2018-02-09 10:04:26 -08:00
|
|
|
|
uint16_t bitmap_len = ntohs(oheh->length) - sizeof *oheh;
|
|
|
|
|
const ovs_be32 *bitmap = ALIGNED_CAST(const ovs_be32 *, oheh + 1);
|
|
|
|
|
uint32_t allowed_versions;
|
2012-06-18 14:11:13 -07:00
|
|
|
|
|
2018-02-09 10:04:26 -08:00
|
|
|
|
if (!bitmap_len || bitmap_len % sizeof *bitmap) {
|
|
|
|
|
return false;
|
2010-11-10 14:39:54 -08:00
|
|
|
|
}
|
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.
2011-10-19 21:33:44 -07:00
|
|
|
|
|
2018-02-09 10:04:26 -08:00
|
|
|
|
/* Only use the first 32-bit element of the bitmap as that is all the
|
|
|
|
|
* current implementation supports. Subsequent elements are ignored which
|
|
|
|
|
* should have no effect on session negotiation until Open vSwitch supports
|
|
|
|
|
* wire-protocol versions greater than 31.
|
|
|
|
|
*/
|
|
|
|
|
allowed_versions = ntohl(bitmap[0]);
|
2010-11-10 14:39:54 -08:00
|
|
|
|
|
2018-02-09 10:04:26 -08:00
|
|
|
|
if (allowed_versions & 1) {
|
|
|
|
|
/* There's no OpenFlow version 0. */
|
|
|
|
|
VLOG_WARN_RL(&bad_ofmsg_rl, "peer claims to support invalid OpenFlow "
|
|
|
|
|
"version 0x00");
|
|
|
|
|
allowed_versions &= ~1u;
|
2012-01-27 17:16:05 -08:00
|
|
|
|
}
|
|
|
|
|
|
2018-02-09 10:04:26 -08:00
|
|
|
|
if (!allowed_versions) {
|
|
|
|
|
VLOG_WARN_RL(&bad_ofmsg_rl, "peer does not support any OpenFlow "
|
|
|
|
|
"version (between 0x01 and 0x1f)");
|
|
|
|
|
return false;
|
2012-06-18 13:33:13 -07:00
|
|
|
|
}
|
2010-11-10 14:39:54 -08:00
|
|
|
|
|
2018-02-09 10:04:26 -08:00
|
|
|
|
*allowed_versionsp = allowed_versions;
|
|
|
|
|
return true;
|
2011-05-31 16:15:45 -07:00
|
|
|
|
}
|
|
|
|
|
|
2018-02-09 10:04:26 -08:00
|
|
|
|
static uint32_t
|
|
|
|
|
version_bitmap_from_version(uint8_t ofp_version)
|
2012-08-07 15:28:18 -07:00
|
|
|
|
{
|
2018-02-09 10:04:26 -08:00
|
|
|
|
return ((ofp_version < 32 ? 1u << ofp_version : 0) - 1) << 1;
|
2010-11-10 14:39:54 -08:00
|
|
|
|
}
|
|
|
|
|
|
2018-02-09 10:04:26 -08:00
|
|
|
|
/* Decodes OpenFlow OFPT_HELLO message 'oh', storing into '*allowed_versions'
|
|
|
|
|
* the set of OpenFlow versions for which 'oh' announces support.
|
|
|
|
|
*
|
|
|
|
|
* Because of how OpenFlow defines OFPT_HELLO messages, this function is always
|
|
|
|
|
* successful, and thus '*allowed_versions' is always initialized. However, it
|
|
|
|
|
* returns false if 'oh' contains some data that could not be fully understood,
|
|
|
|
|
* true if 'oh' was completely parsed. */
|
|
|
|
|
bool
|
|
|
|
|
ofputil_decode_hello(const struct ofp_header *oh, uint32_t *allowed_versions)
|
2010-11-10 14:39:54 -08:00
|
|
|
|
{
|
2018-02-09 10:04:26 -08:00
|
|
|
|
struct ofpbuf msg = ofpbuf_const_initializer(oh, ntohs(oh->length));
|
|
|
|
|
ofpbuf_pull(&msg, sizeof *oh);
|
2010-11-10 14:39:54 -08:00
|
|
|
|
|
2018-02-09 10:04:26 -08:00
|
|
|
|
*allowed_versions = version_bitmap_from_version(oh->version);
|
2010-12-09 14:19:51 -08:00
|
|
|
|
|
2018-02-09 10:04:26 -08:00
|
|
|
|
bool ok = true;
|
|
|
|
|
while (msg.size) {
|
|
|
|
|
const struct ofp_hello_elem_header *oheh;
|
|
|
|
|
unsigned int len;
|
2010-11-23 10:06:28 -08:00
|
|
|
|
|
2018-02-09 10:04:26 -08:00
|
|
|
|
if (msg.size < sizeof *oheh) {
|
|
|
|
|
return false;
|
2010-11-23 10:06:28 -08:00
|
|
|
|
}
|
2010-11-10 14:39:54 -08:00
|
|
|
|
|
2018-02-09 10:04:26 -08:00
|
|
|
|
oheh = msg.data;
|
|
|
|
|
len = ntohs(oheh->length);
|
|
|
|
|
if (len < sizeof *oheh || !ofpbuf_try_pull(&msg, ROUND_UP(len, 8))) {
|
|
|
|
|
return false;
|
2012-08-08 06:49:36 +09:00
|
|
|
|
}
|
|
|
|
|
|
2018-02-09 10:04:26 -08:00
|
|
|
|
if (oheh->type != htons(OFPHET_VERSIONBITMAP)
|
|
|
|
|
|| !ofputil_decode_hello_bitmap(oheh, allowed_versions)) {
|
|
|
|
|
ok = false;
|
2012-08-08 06:49:36 +09:00
|
|
|
|
}
|
2012-06-12 00:27:35 -07:00
|
|
|
|
}
|
2018-02-09 10:04:26 -08:00
|
|
|
|
|
|
|
|
|
return ok;
|
2012-06-12 00:27:35 -07:00
|
|
|
|
}
|
|
|
|
|
|
2018-02-09 10:04:26 -08:00
|
|
|
|
/* Returns true if 'allowed_versions' needs to be accompanied by a version
|
|
|
|
|
* bitmap to be correctly expressed in an OFPT_HELLO message. */
|
|
|
|
|
static bool
|
|
|
|
|
should_send_version_bitmap(uint32_t allowed_versions)
|
2012-06-09 15:49:16 -07:00
|
|
|
|
{
|
2018-02-09 10:04:26 -08:00
|
|
|
|
return !is_pow2((allowed_versions >> 1) + 1);
|
2012-06-09 15:49:16 -07:00
|
|
|
|
}
|
|
|
|
|
|
2018-02-09 10:04:26 -08:00
|
|
|
|
/* Create an OFPT_HELLO message that expresses support for the OpenFlow
|
|
|
|
|
* versions in the 'allowed_versions' bitmaps and returns the message. */
|
|
|
|
|
struct ofpbuf *
|
|
|
|
|
ofputil_encode_hello(uint32_t allowed_versions)
|
2012-06-09 15:49:16 -07:00
|
|
|
|
{
|
2018-02-09 10:04:26 -08:00
|
|
|
|
enum ofp_version ofp_version;
|
|
|
|
|
struct ofpbuf *msg;
|
2012-06-09 15:49:16 -07:00
|
|
|
|
|
2018-02-09 10:04:26 -08:00
|
|
|
|
ofp_version = leftmost_1bit_idx(allowed_versions);
|
|
|
|
|
msg = ofpraw_alloc(OFPRAW_OFPT_HELLO, ofp_version, 0);
|
2012-06-09 15:49:16 -07:00
|
|
|
|
|
2018-02-09 10:04:26 -08:00
|
|
|
|
if (should_send_version_bitmap(allowed_versions)) {
|
|
|
|
|
struct ofp_hello_elem_header *oheh;
|
|
|
|
|
uint16_t map_len;
|
2012-06-09 15:49:16 -07:00
|
|
|
|
|
2018-02-09 10:04:26 -08:00
|
|
|
|
map_len = sizeof allowed_versions;
|
|
|
|
|
oheh = ofpbuf_put_zeros(msg, ROUND_UP(map_len + sizeof *oheh, 8));
|
|
|
|
|
oheh->type = htons(OFPHET_VERSIONBITMAP);
|
|
|
|
|
oheh->length = htons(map_len + sizeof *oheh);
|
|
|
|
|
*ALIGNED_CAST(ovs_be32 *, oheh + 1) = htonl(allowed_versions);
|
2013-10-24 13:19:34 -07:00
|
|
|
|
|
2018-02-09 10:04:26 -08:00
|
|
|
|
ofpmsg_update_length(msg);
|
2013-10-24 13:19:34 -07:00
|
|
|
|
}
|
2012-06-09 15:49:16 -07:00
|
|
|
|
|
2018-02-09 10:04:26 -08:00
|
|
|
|
return msg;
|
2012-06-09 15:49:16 -07:00
|
|
|
|
}
|
2018-02-09 10:04:26 -08:00
|
|
|
|
|
|
|
|
|
/* Creates and returns an OFPT_ECHO_REQUEST message with an empty payload. */
|
|
|
|
|
struct ofpbuf *
|
|
|
|
|
make_echo_request(enum ofp_version ofp_version)
|
2013-07-08 14:48:05 -07:00
|
|
|
|
{
|
2018-02-09 10:04:26 -08:00
|
|
|
|
return ofpraw_alloc_xid(OFPRAW_OFPT_ECHO_REQUEST, ofp_version,
|
|
|
|
|
htonl(0), 0);
|
2013-07-08 14:48:05 -07:00
|
|
|
|
}
|
|
|
|
|
|
2018-02-09 10:04:26 -08:00
|
|
|
|
/* Creates and returns an OFPT_ECHO_REPLY message matching the
|
|
|
|
|
* OFPT_ECHO_REQUEST message in 'rq'. */
|
|
|
|
|
struct ofpbuf *
|
|
|
|
|
make_echo_reply(const struct ofp_header *rq)
|
2013-07-08 14:48:05 -07:00
|
|
|
|
{
|
2018-02-09 10:04:26 -08:00
|
|
|
|
struct ofpbuf rq_buf = ofpbuf_const_initializer(rq, ntohs(rq->length));
|
|
|
|
|
ofpraw_pull_assert(&rq_buf);
|
2013-07-08 14:48:05 -07:00
|
|
|
|
|
2018-02-09 10:04:26 -08:00
|
|
|
|
struct ofpbuf *reply = ofpraw_alloc_reply(OFPRAW_OFPT_ECHO_REPLY,
|
|
|
|
|
rq, rq_buf.size);
|
|
|
|
|
ofpbuf_put(reply, rq_buf.data, rq_buf.size);
|
|
|
|
|
return reply;
|
2011-01-23 18:44:44 -08:00
|
|
|
|
}
|
|
|
|
|
|
2018-02-09 10:04:26 -08:00
|
|
|
|
struct ofpbuf *
|
|
|
|
|
ofputil_encode_barrier_request(enum ofp_version ofp_version)
|
2011-01-23 18:44:44 -08:00
|
|
|
|
{
|
2018-02-09 10:04:26 -08:00
|
|
|
|
enum ofpraw type;
|
2012-02-10 13:30:23 -08:00
|
|
|
|
|
2018-02-09 10:04:26 -08:00
|
|
|
|
switch (ofp_version) {
|
2016-04-10 14:39:12 -07:00
|
|
|
|
case OFP16_VERSION:
|
2018-02-09 10:04:26 -08:00
|
|
|
|
case OFP15_VERSION:
|
|
|
|
|
case OFP14_VERSION:
|
|
|
|
|
case OFP13_VERSION:
|
|
|
|
|
case OFP12_VERSION:
|
|
|
|
|
case OFP11_VERSION:
|
|
|
|
|
type = OFPRAW_OFPT11_BARRIER_REQUEST;
|
|
|
|
|
break;
|
2012-02-10 13:30:23 -08:00
|
|
|
|
|
2018-02-09 10:04:26 -08:00
|
|
|
|
case OFP10_VERSION:
|
|
|
|
|
type = OFPRAW_OFPT10_BARRIER_REQUEST;
|
|
|
|
|
break;
|
2012-11-28 21:41:05 -08:00
|
|
|
|
|
2018-02-09 10:04:26 -08:00
|
|
|
|
default:
|
|
|
|
|
OVS_NOT_REACHED();
|
2012-02-15 16:33:04 -08:00
|
|
|
|
}
|
|
|
|
|
|
2018-02-09 10:04:26 -08:00
|
|
|
|
return ofpraw_alloc(type, ofp_version, 0);
|
2016-02-18 15:54:26 +05:30
|
|
|
|
}
|