Skip to content

Commit

Permalink
OpenFlow-level flow-based tunneling support.
Browse files Browse the repository at this point in the history
Adds tun_src and tun_dst match and set capabilities via new NXM fields
NXM_NX_TUN_IPV4_SRC and NXM_NX_TUN_IPV4_DST.  This allows management of
large number of tunnels via the flow tables, without requiring the tunnels
to be pre-configured.

Flow-based tunnels can be configured with options remote_ip=flow and
local_ip=flow.  local_ip=flow requires remote_ip=flow.  When set, the
tunnel remote IP address and/or local IP address is set from the flow,
instead of the tunnel configuration.

Example:

$ ovs-vsctl add-port br0 gre -- set Interface gre ofport_request=1 type=gre options:remote_ip=flow options:key=flow
$ ovs-ofctl add-flow br0 "in_port=LOCAL actions=set_tunnel:1,set_field:192.168.0.1->tun_dst,output:1"
$ ovs-ofctl add-flow br0 "in_port=1 tun_src=192.168.0.1 tun_id=1 actions=LOCAL"

Signed-off-by: Jarno Rajahalme <[email protected]>
Signed-off-by: Ben Pfaff <[email protected]>
  • Loading branch information
Jarno Rajahalme authored and blp committed May 10, 2013
1 parent 500d243 commit 0ad90c8
Show file tree
Hide file tree
Showing 17 changed files with 264 additions and 42 deletions.
4 changes: 4 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
post-v1.11.0
---------------------
- OpenFlow:
* New support for matching outer source and destination IP address
of tunneled packets, for tunnel ports configured with the newly
added "remote_ip=flow" and "local_ip=flow" options.


v1.11.0 - xx xxx xxxx
Expand Down
23 changes: 21 additions & 2 deletions include/openflow/nicira-ext.h
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,8 @@ OFP_ASSERT(sizeof(struct nx_action_pop_queue) == 16);
* - NXM_NX_ND_SLL
* - NXM_NX_ND_TLL
* - NXM_NX_REG(idx) for idx in the switch's accepted range.
* - NXM_NX_TUN_IPV4_SRC
* - NXM_NX_TUN_IPV4_DST
*
* The following nxm_header values are potentially acceptable as 'dst':
*
Expand All @@ -503,8 +505,10 @@ OFP_ASSERT(sizeof(struct nx_action_pop_queue) == 16);
* adds or modifies the 802.1Q header appropriately, setting the TCI field
* to the field's new value (with the CFI bit masked out).
*
* - NXM_NX_TUN_ID. Modifying this value modifies the tunnel ID used for the
* packet's next tunnel encapsulation.
* - NXM_NX_TUN_ID, NXM_NX_TUN_IPV4_SRC, NXM_NX_TUN_IPV4_DST. Modifying
* any of these values modifies the corresponding tunnel header field used
* for the packet's next tunnel encapsulation, if allowed by the
* configuration of the output tunnel port.
*
* A given nxm_header value may be used as 'src' or 'dst' only on a flow whose
* nx_match satisfies its prerequisites. For example, NXM_OF_IP_TOS may be
Expand Down Expand Up @@ -1748,6 +1752,21 @@ OFP_ASSERT(sizeof(struct nx_action_output_reg) == 24);
#define NXM_NX_COOKIE NXM_HEADER (0x0001, 30, 8)
#define NXM_NX_COOKIE_W NXM_HEADER_W(0x0001, 30, 8)

/* The source or destination address in the outer IP header of a tunneled
* packet.
*
* For non-tunneled packets, the value is 0.
*
* Prereqs: None.
*
* Format: 32-bit integer in network byte order.
*
* Masking: Fully maskable. */
#define NXM_NX_TUN_IPV4_SRC NXM_HEADER (0x0001, 31, 4)
#define NXM_NX_TUN_IPV4_SRC_W NXM_HEADER_W(0x0001, 31, 4)
#define NXM_NX_TUN_IPV4_DST NXM_HEADER (0x0001, 32, 4)
#define NXM_NX_TUN_IPV4_DST_W NXM_HEADER_W(0x0001, 32, 4)

/* ## --------------------- ## */
/* ## Requests and replies. ## */
/* ## --------------------- ## */
Expand Down
2 changes: 2 additions & 0 deletions lib/flow.c
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,8 @@ flow_get_metadata(const struct flow *flow, struct flow_metadata *fmd)
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 20);

fmd->tun_id = flow->tunnel.tun_id;
fmd->tun_src = flow->tunnel.ip_src;
fmd->tun_dst = flow->tunnel.ip_dst;
fmd->metadata = flow->metadata;
memcpy(fmd->regs, flow->regs, sizeof fmd->regs);
fmd->in_port = flow->in_port;
Expand Down
2 changes: 2 additions & 0 deletions lib/flow.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@ BUILD_ASSERT_DECL(sizeof(struct flow) == sizeof(struct flow_tnl) + 160 &&
/* Represents the metadata fields of struct flow. */
struct flow_metadata {
ovs_be64 tun_id; /* Encapsulating tunnel ID. */
ovs_be32 tun_src; /* Tunnel outer IPv4 src addr */
ovs_be32 tun_dst; /* Tunnel outer IPv4 dst addr */
ovs_be64 metadata; /* OpenFlow 1.1+ metadata field. */
uint32_t regs[FLOW_N_REGS]; /* Registers. */
uint16_t in_port; /* OpenFlow port or zero. */
Expand Down
4 changes: 0 additions & 4 deletions lib/match.c
Original file line number Diff line number Diff line change
Expand Up @@ -135,13 +135,9 @@ match_wc_init(struct match *match, const struct flow *flow)
void
match_init_exact(struct match *match, const struct flow *flow)
{
ovs_be64 tun_id = flow->tunnel.tun_id;

match->flow = *flow;
match->flow.skb_priority = 0;
match->flow.skb_mark = 0;
memset(&match->flow.tunnel, 0, sizeof match->flow.tunnel);
match->flow.tunnel.tun_id = tun_id;
flow_wildcards_init_exact(&match->wc);
}

Expand Down
20 changes: 11 additions & 9 deletions lib/meta-flow.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,21 +57,21 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
}, {
MFF_TUN_SRC, "tun_src", NULL,
MF_FIELD_SIZES(be32),
MFM_NONE,
MFM_FULLY,
MFS_IPV4,
MFP_NONE,
false,
0, NULL,
0, NULL,
true,
NXM_NX_TUN_IPV4_SRC, "NXM_NX_TUN_IPV4_SRC",
NXM_NX_TUN_IPV4_SRC, "NXM_NX_TUN_IPV4_SRC",
}, {
MFF_TUN_DST, "tun_dst", NULL,
MF_FIELD_SIZES(be32),
MFM_NONE,
MFM_FULLY,
MFS_IPV4,
MFP_NONE,
false,
0, NULL,
0, NULL,
true,
NXM_NX_TUN_IPV4_DST, "NXM_NX_TUN_IPV4_DST",
NXM_NX_TUN_IPV4_DST, "NXM_NX_TUN_IPV4_DST",
}, {
MFF_TUN_FLAGS, "tun_flags", NULL,
MF_FIELD_SIZES(be16),
Expand Down Expand Up @@ -676,9 +676,11 @@ bool
mf_is_all_wild(const struct mf_field *mf, const struct flow_wildcards *wc)
{
switch (mf->id) {
case MFF_TUN_ID:
case MFF_TUN_SRC:
return !wc->masks.tunnel.ip_src;
case MFF_TUN_DST:
return !wc->masks.tunnel.ip_dst;
case MFF_TUN_ID:
case MFF_TUN_TOS:
case MFF_TUN_TTL:
case MFF_TUN_FLAGS:
Expand Down
21 changes: 18 additions & 3 deletions lib/netdev-vport.c
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,10 @@ set_tunnel_config(struct netdev_dev *dev_, const struct smap *args)
SMAP_FOR_EACH (node, args) {
if (!strcmp(node->key, "remote_ip")) {
struct in_addr in_addr;
if (lookup_ip(node->value, &in_addr)) {
if (!strcmp(node->value, "flow")) {
tnl_cfg.ip_dst_flow = true;
tnl_cfg.ip_dst = htonl(0);
} else if (lookup_ip(node->value, &in_addr)) {
VLOG_WARN("%s: bad %s 'remote_ip'", name, type);
} else if (ip_is_multicast(in_addr.s_addr)) {
VLOG_WARN("%s: multicast remote_ip="IP_FMT" not allowed",
Expand All @@ -336,7 +339,10 @@ set_tunnel_config(struct netdev_dev *dev_, const struct smap *args)
}
} else if (!strcmp(node->key, "local_ip")) {
struct in_addr in_addr;
if (lookup_ip(node->value, &in_addr)) {
if (!strcmp(node->value, "flow")) {
tnl_cfg.ip_src_flow = true;
tnl_cfg.ip_src = htonl(0);
} else if (lookup_ip(node->value, &in_addr)) {
VLOG_WARN("%s: bad %s 'local_ip'", name, type);
} else {
tnl_cfg.ip_src = in_addr.s_addr;
Expand Down Expand Up @@ -443,11 +449,16 @@ set_tunnel_config(struct netdev_dev *dev_, const struct smap *args)
}
}

if (!tnl_cfg.ip_dst) {
if (!tnl_cfg.ip_dst && !tnl_cfg.ip_dst_flow) {
VLOG_ERR("%s: %s type requires valid 'remote_ip' argument",
name, type);
return EINVAL;
}
if (tnl_cfg.ip_src_flow && !tnl_cfg.ip_dst_flow) {
VLOG_ERR("%s: %s type requires 'remote_ip=flow' with 'local_ip=flow'",
name, type);
return EINVAL;
}
if (!tnl_cfg.ttl) {
tnl_cfg.ttl = DEFAULT_TTL;
}
Expand All @@ -474,10 +485,14 @@ get_tunnel_config(struct netdev_dev *dev, struct smap *args)

if (tnl_cfg->ip_dst) {
smap_add_format(args, "remote_ip", IP_FMT, IP_ARGS(tnl_cfg->ip_dst));
} else if (tnl_cfg->ip_dst_flow) {
smap_add(args, "remote_ip", "flow");
}

if (tnl_cfg->ip_src) {
smap_add_format(args, "local_ip", IP_FMT, IP_ARGS(tnl_cfg->ip_src));
} else if (tnl_cfg->ip_src_flow) {
smap_add(args, "local_ip", "flow");
}

if (tnl_cfg->in_key_flow && tnl_cfg->out_key_flow) {
Expand Down
2 changes: 2 additions & 0 deletions lib/netdev.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ struct netdev_tunnel_config {

ovs_be16 dst_port;

bool ip_src_flow;
bool ip_dst_flow;
ovs_be32 ip_src;
ovs_be32 ip_dst;

Expand Down
8 changes: 7 additions & 1 deletion lib/nx-match.c
Original file line number Diff line number Diff line change
Expand Up @@ -690,7 +690,13 @@ nx_put_raw(struct ofpbuf *b, bool oxm, const struct match *match,

/* Tunnel ID. */
nxm_put_64m(b, oxm ? OXM_OF_TUNNEL_ID : NXM_NX_TUN_ID,
flow->tunnel.tun_id, match->wc.masks.tunnel.tun_id);
flow->tunnel.tun_id, match->wc.masks.tunnel.tun_id);

/* Other tunnel metadata. */
nxm_put_32m(b, NXM_NX_TUN_IPV4_SRC,
flow->tunnel.ip_src, match->wc.masks.tunnel.ip_src);
nxm_put_32m(b, NXM_NX_TUN_IPV4_DST,
flow->tunnel.ip_dst, match->wc.masks.tunnel.ip_dst);

/* Registers. */
for (i = 0; i < FLOW_N_REGS; i++) {
Expand Down
8 changes: 8 additions & 0 deletions lib/ofp-print.c
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,14 @@ ofp_print_packet_in(struct ds *string, const struct ofp_header *oh,
ds_put_format(string, " tun_id=0x%"PRIx64, ntohll(pin.fmd.tun_id));
}

if (pin.fmd.tun_src != htonl(0)) {
ds_put_format(string, " tun_src="IP_FMT, IP_ARGS(pin.fmd.tun_src));
}

if (pin.fmd.tun_dst != htonl(0)) {
ds_put_format(string, " tun_dst="IP_FMT, IP_ARGS(pin.fmd.tun_dst));
}

if (pin.fmd.metadata != htonll(0)) {
ds_put_format(string, " metadata=0x%"PRIx64, ntohll(pin.fmd.metadata));
}
Expand Down
29 changes: 15 additions & 14 deletions lib/ofp-util.c
Original file line number Diff line number Diff line change
Expand Up @@ -1039,16 +1039,6 @@ regs_fully_wildcarded(const struct flow_wildcards *wc)
return true;
}

static bool
tun_parms_fully_wildcarded(const struct flow_wildcards *wc)
{
return (!wc->masks.tunnel.ip_src &&
!wc->masks.tunnel.ip_dst &&
!wc->masks.tunnel.ip_ttl &&
!wc->masks.tunnel.ip_tos &&
!wc->masks.tunnel.flags);
}

/* Returns a bit-mask of ofputil_protocols that can be used for sending 'match'
* to a switch (e.g. to add or remove a flow). Only NXM can handle tunnel IDs,
* registers, or fixing the Ethernet multicast bit. Otherwise, it's better to
Expand All @@ -1060,8 +1050,9 @@ ofputil_usable_protocols(const struct match *match)

BUILD_ASSERT_DECL(FLOW_WC_SEQ == 20);

/* tunnel params other than tun_id can't be sent in a flow_mod */
if (!tun_parms_fully_wildcarded(wc)) {
/* These tunnel params can't be sent in a flow_mod */
if (wc->masks.tunnel.ip_ttl
|| wc->masks.tunnel.ip_tos || wc->masks.tunnel.flags) {
return OFPUTIL_P_NONE;
}

Expand Down Expand Up @@ -1107,8 +1098,10 @@ ofputil_usable_protocols(const struct match *match)
| OFPUTIL_P_OF13_OXM;
}

/* NXM and OXM support matching tun_id. */
if (wc->masks.tunnel.tun_id != htonll(0)) {
/* NXM and OXM support matching tun_id, tun_src, and tun_dst. */
if (wc->masks.tunnel.tun_id != htonll(0)
|| wc->masks.tunnel.ip_src != htonl(0)
|| wc->masks.tunnel.ip_dst != htonl(0)) {
return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
| OFPUTIL_P_OF13_OXM;
}
Expand Down Expand Up @@ -2450,6 +2443,8 @@ ofputil_decode_packet_in_finish(struct ofputil_packet_in *pin,

pin->fmd.in_port = match->flow.in_port;
pin->fmd.tun_id = match->flow.tunnel.tun_id;
pin->fmd.tun_src = match->flow.tunnel.ip_src;
pin->fmd.tun_dst = match->flow.tunnel.ip_dst;
pin->fmd.metadata = match->flow.metadata;
memcpy(pin->fmd.regs, match->flow.regs, sizeof pin->fmd.regs);
}
Expand Down Expand Up @@ -2550,6 +2545,12 @@ ofputil_packet_in_to_match(const struct ofputil_packet_in *pin,
if (pin->fmd.tun_id != htonll(0)) {
match_set_tun_id(match, pin->fmd.tun_id);
}
if (pin->fmd.tun_src != htonl(0)) {
match_set_tun_src(match, pin->fmd.tun_src);
}
if (pin->fmd.tun_dst != htonl(0)) {
match_set_tun_dst(match, pin->fmd.tun_dst);
}
if (pin->fmd.metadata != htonll(0)) {
match_set_metadata(match, pin->fmd.metadata);
}
Expand Down
18 changes: 16 additions & 2 deletions ofproto/ofproto-dpif.c
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,17 @@ struct action_xlate_ctx {
* this flow when actions change header fields. */
struct flow flow;

/* Flow at the last commit. */
struct flow base_flow;

/* Tunnel IP destination address as received. This is stored separately
* as the base_flow.tunnel is cleared on init to reflect the datapath
* behavior. Used to make sure not to send tunneled output to ourselves,
* which might lead to an infinite loop. This could happen easily
* if a tunnel is marked as 'ip_remote=flow', and the flow does not
* actually set the tun_dst field. */
ovs_be32 orig_tunnel_ip_dst;

/* stack for the push and pop actions.
* Each stack element is of the type "union mf_subvalue". */
struct ofpbuf stack;
Expand Down Expand Up @@ -283,7 +294,6 @@ struct action_xlate_ctx {

int recurse; /* Recursion level, via xlate_table_action. */
bool max_resubmit_trigger; /* Recursed too deeply during translation. */
struct flow base_flow; /* Flow at the last commit. */
uint32_t orig_skb_priority; /* Priority when packet arrived. */
uint8_t table_id; /* OpenFlow table ID where flow was found. */
uint32_t sflow_n_outputs; /* Number of output ports. */
Expand Down Expand Up @@ -6160,7 +6170,10 @@ compose_output_action__(struct action_xlate_ctx *ctx, uint16_t ofp_port,
xlate_report(ctx, "Tunneling decided against output");
goto out; /* restore flow_nw_tos */
}

if (ctx->flow.tunnel.ip_dst == ctx->orig_tunnel_ip_dst) {
xlate_report(ctx, "Not tunneling to our own address");
goto out; /* restore flow_nw_tos */
}
if (ctx->resubmit_stats) {
netdev_vport_inc_tx(ofport->up.netdev, ctx->resubmit_stats);
}
Expand Down Expand Up @@ -7025,6 +7038,7 @@ action_xlate_ctx_init(struct action_xlate_ctx *ctx,
ctx->flow = *flow;
ctx->base_flow = ctx->flow;
memset(&ctx->base_flow.tunnel, 0, sizeof ctx->base_flow.tunnel);
ctx->orig_tunnel_ip_dst = flow->tunnel.ip_dst;
ctx->rule = rule;
ctx->packet = packet;
ctx->may_learn = packet != NULL;
Expand Down
Loading

0 comments on commit 0ad90c8

Please sign in to comment.