Skip to content

Commit

Permalink
tunnel: Geneve TLV handling support for OpenFlow.
Browse files Browse the repository at this point in the history
The current support for Geneve in OVS is exactly equivalent to VXLAN:
it is possible to set and match on the VNI but not on any options
contained in the header. This patch enables the use of options.

The goal for Geneve support is not to add support for any particular option
but to allow end users or controllers to specify what they would like to
match. That is, the full range of Geneve's capabilities should be exposed
without modifying the code (the one exception being options that require
per-packet computation in the fast path).

The main issue with supporting Geneve options is how to integrate the
fields into the existing OpenFlow pipeline. All existing operations
are referred to by their NXM/OXM field name - matches, action generation,
arithmetic operations (i.e. tranfer to a register). However, the Geneve
option space is exactly the same as the OXM space, so a direct mapping
is not feasible. Instead, we create a pool of 64 NXMs that are then
dynamically mapped on Geneve option TLVs using OpenFlow. Once mapped,
these fields become first-class citizens in the OpenFlow pipeline.

An example of how to use Geneve options:
ovs-ofctl add-geneve-map br0 {class=0xffff,type=0,len=4}->tun_metadata0
ovs-ofctl add-flow br0 in_port=LOCAL,actions=set_field:0xffffffff->tun_metadata0,1

This will add a 4 bytes option (filled will all 1's) to all packets
coming from the LOCAL port and then send then out to port 1.

A limitation of this patch is that although the option table is specified
for a particular switch over OpenFlow, it is currently global to all
switches. This will be addressed in a future patch.

Based on work originally done by Madhu Challa. Ben Pfaff also significantly
improved the comments.

Signed-off-by: Madhu Challa <[email protected]>
Signed-off-by: Jesse Gross <[email protected]>
Acked-by: Ben Pfaff <[email protected]>
  • Loading branch information
jessegross committed Jun 25, 2015
1 parent ec1f6f3 commit 9558d2a
Show file tree
Hide file tree
Showing 25 changed files with 1,350 additions and 77 deletions.
1 change: 1 addition & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Post-v2.4.0
- OpenFlow:
* Group chaining (where one OpenFlow group triggers another) is
now supported.
- Support for matching and generating options with Geneve tunnels.


v2.4.0 - xx xxx xxxx
Expand Down
13 changes: 7 additions & 6 deletions build-aux/extract-ofp-fields
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@ VERSION = {"1.0": 0x01,
"1.4": 0x05,
"1.5": 0x06}

TYPES = {"u8": (1, False),
"be16": (2, False),
"be32": (4, False),
"MAC": (6, False),
"be64": (8, False),
"IPv6": (16, False)}
TYPES = {"u8": (1, False),
"be16": (2, False),
"be32": (4, False),
"MAC": (6, False),
"be64": (8, False),
"IPv6": (16, False),
"tunnelMD": (124, True)}

FORMATTING = {"decimal": ("MFS_DECIMAL", 1, 8),
"hexadecimal": ("MFS_HEXADECIMAL", 1, 127),
Expand Down
1 change: 1 addition & 0 deletions lib/automake.mk
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ lib_libopenvswitch_la_SOURCES = \
lib/tnl-ports.c \
lib/tnl-ports.h \
lib/token-bucket.c \
lib/tun-metadata.c \
lib/tun-metadata.h \
lib/type-props.h \
lib/unaligned.h \
Expand Down
18 changes: 12 additions & 6 deletions lib/flow.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ struct mf_ctx {
* away. Some GCC versions gave warnings on ALWAYS_INLINE, so these are
* defined as macros. */

#if (FLOW_WC_SEQ != 31)
#if (FLOW_WC_SEQ != 32)
#define MINIFLOW_ASSERT(X) ovs_assert(X)
BUILD_MESSAGE("FLOW_WC_SEQ changed: miniflow_extract() will have runtime "
"assertions enabled. Consider updating FLOW_WC_SEQ after "
Expand Down Expand Up @@ -766,7 +766,7 @@ flow_get_metadata(const struct flow *flow, struct match *flow_metadata)
{
int i;

BUILD_ASSERT_DECL(FLOW_WC_SEQ == 31);
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 32);

match_init_catchall(flow_metadata);
if (flow->tunnel.tun_id != htonll(0)) {
Expand All @@ -784,6 +784,7 @@ flow_get_metadata(const struct flow *flow, struct match *flow_metadata)
if (flow->tunnel.gbp_flags) {
match_set_tun_gbp_flags(flow_metadata, flow->tunnel.gbp_flags);
}
tun_metadata_get_fmd(&flow->tunnel.metadata, flow_metadata);
if (flow->metadata != htonll(0)) {
match_set_metadata(flow_metadata, flow->metadata);
}
Expand Down Expand Up @@ -942,7 +943,7 @@ void flow_wildcards_init_for_packet(struct flow_wildcards *wc,
memset(&wc->masks, 0x0, sizeof wc->masks);

/* Update this function whenever struct flow changes. */
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 31);
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 32);

if (flow->tunnel.ip_dst) {
if (flow->tunnel.flags & FLOW_TNL_F_KEY) {
Expand All @@ -957,6 +958,11 @@ void flow_wildcards_init_for_packet(struct flow_wildcards *wc,
WC_MASK_FIELD(wc, tunnel.tp_dst);
WC_MASK_FIELD(wc, tunnel.gbp_id);
WC_MASK_FIELD(wc, tunnel.gbp_flags);

if (flow->tunnel.metadata.opt_map) {
wc->masks.tunnel.metadata.opt_map = flow->tunnel.metadata.opt_map;
WC_MASK_FIELD(wc, tunnel.metadata.opts);
}
} else if (flow->tunnel.tun_id) {
WC_MASK_FIELD(wc, tunnel.tun_id);
}
Expand Down Expand Up @@ -1041,7 +1047,7 @@ uint64_t
flow_wc_map(const struct flow *flow)
{
/* Update this function whenever struct flow changes. */
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 31);
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 32);

uint64_t map = (flow->tunnel.ip_dst) ? MINIFLOW_MAP(tunnel) : 0;

Expand Down Expand Up @@ -1093,7 +1099,7 @@ void
flow_wildcards_clear_non_packet_fields(struct flow_wildcards *wc)
{
/* Update this function whenever struct flow changes. */
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 31);
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 32);

memset(&wc->masks.metadata, 0, sizeof wc->masks.metadata);
memset(&wc->masks.regs, 0, sizeof wc->masks.regs);
Expand Down Expand Up @@ -1648,7 +1654,7 @@ flow_push_mpls(struct flow *flow, int n, ovs_be16 mpls_eth_type,
flow->mpls_lse[0] = set_mpls_lse_values(ttl, tc, 1, htonl(label));

/* Clear all L3 and L4 fields and dp_hash. */
BUILD_ASSERT(FLOW_WC_SEQ == 31);
BUILD_ASSERT(FLOW_WC_SEQ == 32);
memset((char *) flow + FLOW_SEGMENT_2_ENDS_AT, 0,
sizeof(struct flow) - FLOW_SEGMENT_2_ENDS_AT);
flow->dp_hash = 0;
Expand Down
4 changes: 2 additions & 2 deletions lib/flow.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ struct match;
/* This sequence number should be incremented whenever anything involving flows
* or the wildcarding of flows changes. This will cause build assertion
* failures in places which likely need to be updated. */
#define FLOW_WC_SEQ 31
#define FLOW_WC_SEQ 32

/* Number of Open vSwitch extension 32-bit registers. */
#define FLOW_N_REGS 8
Expand Down Expand Up @@ -157,7 +157,7 @@ BUILD_ASSERT_DECL(sizeof(struct flow) % sizeof(uint64_t) == 0);
/* Remember to update FLOW_WC_SEQ when changing 'struct flow'. */
BUILD_ASSERT_DECL(offsetof(struct flow, igmp_group_ip4) + sizeof(uint32_t)
== sizeof(struct flow_tnl) + 192
&& FLOW_WC_SEQ == 31);
&& FLOW_WC_SEQ == 32);

/* Incremental points at which flow classification may be performed in
* segments.
Expand Down
9 changes: 8 additions & 1 deletion lib/match.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "dynamic-string.h"
#include "ofp-util.h"
#include "packets.h"
#include "tun-metadata.h"

/* Converts the flow in 'flow' into a match in 'match', with the given
* 'wildcards'. */
Expand All @@ -31,6 +32,7 @@ match_init(struct match *match,
match->flow = *flow;
match->wc = *wc;
match_zero_wildcarded_fields(match);
memset(&match->tun_md, 0, sizeof match->tun_md);
}

/* Converts a flow into a match. It sets the wildcard masks based on
Expand All @@ -44,6 +46,8 @@ match_wc_init(struct match *match, const struct flow *flow)
flow_wildcards_init_for_packet(&match->wc, flow);
WC_MASK_FIELD(&match->wc, regs);
WC_MASK_FIELD(&match->wc, metadata);

memset(&match->tun_md, 0, sizeof match->tun_md);
}

/* Initializes 'match' as a "catch-all" match that matches every packet. */
Expand All @@ -52,6 +56,7 @@ match_init_catchall(struct match *match)
{
memset(&match->flow, 0, sizeof match->flow);
flow_wildcards_init_catchall(&match->wc);
memset(&match->tun_md, 0, sizeof match->tun_md);
}

/* For each bit or field wildcarded in 'match', sets the corresponding bit or
Expand Down Expand Up @@ -897,6 +902,7 @@ format_flow_tunnel(struct ds *s, const struct match *match)
format_flags(s, flow_tun_flag_to_string, tnl->flags, '|');
ds_put_char(s, ',');
}
tun_metadata_match_format(s, match);
}

/* Appends a string representation of 'match' to 's'. If 'priority' is
Expand All @@ -912,7 +918,7 @@ match_format(const struct match *match, struct ds *s, int priority)

int i;

BUILD_ASSERT_DECL(FLOW_WC_SEQ == 31);
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 32);

if (priority != OFP_DEFAULT_PRIORITY) {
ds_put_format(s, "priority=%d,", priority);
Expand Down Expand Up @@ -1226,6 +1232,7 @@ minimatch_expand(const struct minimatch *src, struct match *dst)
{
miniflow_expand(&src->flow, &dst->flow);
minimask_expand(&src->mask, &dst->wc);
memset(&dst->tun_md, 0, sizeof dst->tun_md);
}

/* Returns true if 'a' and 'b' match the same packets, false otherwise. */
Expand Down
2 changes: 2 additions & 0 deletions lib/match.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

#include "flow.h"
#include "packets.h"
#include "tun-metadata.h"

struct ds;

Expand All @@ -33,6 +34,7 @@ struct ds;
struct match {
struct flow flow;
struct flow_wildcards wc;
struct tun_metadata_allocation tun_md;
};

/* Initializer for a "struct match" that matches every packet. */
Expand Down
22 changes: 22 additions & 0 deletions lib/meta-flow.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include "random.h"
#include "shash.h"
#include "socket-util.h"
#include "tun-metadata.h"
#include "unaligned.h"
#include "util.h"
#include "openvswitch/vlog.h"
Expand Down Expand Up @@ -189,6 +190,12 @@ mf_is_all_wild(const struct mf_field *mf, const struct flow_wildcards *wc)
return !wc->masks.tunnel.gbp_id;
case MFF_TUN_GBP_FLAGS:
return !wc->masks.tunnel.gbp_flags;
CASE_MFF_TUN_METADATA: {
union mf_value value;

tun_metadata_read(&wc->masks.tunnel.metadata, mf, &value);
return is_all_zeros(&value.tun_metadata, mf->n_bytes);
}
case MFF_METADATA:
return !wc->masks.metadata;
case MFF_IN_PORT:
Expand Down Expand Up @@ -480,6 +487,7 @@ mf_is_value_valid(const struct mf_field *mf, const union mf_value *value)
case MFF_TUN_FLAGS:
case MFF_TUN_GBP_ID:
case MFF_TUN_GBP_FLAGS:
CASE_MFF_TUN_METADATA:
case MFF_METADATA:
case MFF_IN_PORT:
case MFF_SKB_PRIORITY:
Expand Down Expand Up @@ -602,6 +610,9 @@ mf_get_value(const struct mf_field *mf, const struct flow *flow,
case MFF_TUN_TOS:
value->u8 = flow->tunnel.ip_tos;
break;
CASE_MFF_TUN_METADATA:
tun_metadata_read(&flow->tunnel.metadata, mf, value);
break;

case MFF_METADATA:
value->be64 = flow->metadata;
Expand Down Expand Up @@ -816,6 +827,9 @@ mf_set_value(const struct mf_field *mf,
case MFF_TUN_TTL:
match_set_tun_ttl(match, value->u8);
break;
CASE_MFF_TUN_METADATA:
tun_metadata_set_match(mf, value, NULL, match);
break;

case MFF_METADATA:
match_set_metadata(match, value->be64);
Expand Down Expand Up @@ -1098,6 +1112,8 @@ mf_set_flow_value(const struct mf_field *mf,
case MFF_TUN_TTL:
flow->tunnel.ip_ttl = value->u8;
break;
CASE_MFF_TUN_METADATA:
tun_metadata_write(&flow->tunnel.metadata, mf, value);

case MFF_METADATA:
flow->metadata = value->be64;
Expand Down Expand Up @@ -1362,6 +1378,9 @@ mf_set_wild(const struct mf_field *mf, struct match *match)
case MFF_TUN_TTL:
match_set_tun_ttl_masked(match, 0, 0);
break;
CASE_MFF_TUN_METADATA:
tun_metadata_set_match(mf, NULL, NULL, match);
break;

case MFF_METADATA:
match_set_metadata_masked(match, htonll(0), htonll(0));
Expand Down Expand Up @@ -1616,6 +1635,9 @@ mf_set(const struct mf_field *mf,
case MFF_TUN_TOS:
match_set_tun_tos_masked(match, value->u8, mask->u8);
break;
CASE_MFF_TUN_METADATA:
tun_metadata_set_match(mf, value, mask, match);
break;

case MFF_METADATA:
match_set_metadata_masked(match, value->be64, mask->be64);
Expand Down
Loading

0 comments on commit 9558d2a

Please sign in to comment.