Skip to content

Commit

Permalink
datapath: Add support for tun_key to Open vSwitch datapath
Browse files Browse the repository at this point in the history
This is a first pass at providing a tun_key which can be
used as the basis for flow-based tunnelling. The
tun_key includes and replaces the tun_id in both struct
ovs_skb_cb and struct sw_tun_key.

This patch allows all existing tun_id behaviour to still work. Existing
users of tun_id are redirected to tun_key->tun_id to retain compatibility.
However, when the userspace code is updated to make use of the new
tun_key, the old behaviour will be deprecated and removed.

NOTE: With these changes, the tunneling code no longer assumes input and
output keys are symmetric.  If they are not, PMTUD needs to be disabled
for tunneling to work.

Signed-off-by: Kyle Mestery <[email protected]>
Signed-off-by: Pravin B Shelar <[email protected]>
Reviewed-by: Jesse Gross <[email protected]>
Acked-by: Ben Pfaff <[email protected]>
  • Loading branch information
mestery authored and Pravin B Shelar committed Oct 20, 2012
1 parent 4206b80 commit 356af50
Show file tree
Hide file tree
Showing 15 changed files with 486 additions and 170 deletions.
3 changes: 3 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
post-v1.8.0
------------------------
- The tunneling code no longer assumes input and output keys are symmetric.
If they are not, PMTUD needs to be disabled for tunneling to work. Note
this only applies to flow-based keys.
- FreeBSD is now a supported platform, thanks to code contributions from
Gaetano Catalli, Ed Maste, and Giuseppe Lettieri.
- ovs-bugtool: New --ovs option to report only OVS related information.
Expand Down
40 changes: 30 additions & 10 deletions datapath/actions.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@
#include "vport.h"

static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
const struct nlattr *attr, int len, bool keep_skb);
const struct nlattr *attr, int len,
struct ovs_key_ipv4_tunnel *tun_key, bool keep_skb);

static int make_writable(struct sk_buff *skb, int write_len)
{
Expand Down Expand Up @@ -308,7 +309,8 @@ static int output_userspace(struct datapath *dp, struct sk_buff *skb,
}

static int sample(struct datapath *dp, struct sk_buff *skb,
const struct nlattr *attr)
const struct nlattr *attr,
struct ovs_key_ipv4_tunnel *tun_key)
{
const struct nlattr *acts_list = NULL;
const struct nlattr *a;
Expand All @@ -329,11 +331,12 @@ static int sample(struct datapath *dp, struct sk_buff *skb,
}

return do_execute_actions(dp, skb, nla_data(acts_list),
nla_len(acts_list), true);
nla_len(acts_list), tun_key, true);
}

static int execute_set_action(struct sk_buff *skb,
const struct nlattr *nested_attr)
const struct nlattr *nested_attr,
struct ovs_key_ipv4_tunnel *tun_key)
{
int err = 0;

Expand All @@ -343,7 +346,22 @@ static int execute_set_action(struct sk_buff *skb,
break;

case OVS_KEY_ATTR_TUN_ID:
OVS_CB(skb)->tun_id = nla_get_be64(nested_attr);
if (!OVS_CB(skb)->tun_key) {
/* If tun_key is NULL for this skb, assign it to
* a value the caller passed in for action processing
* and output. This can disappear once we drop support
* for setting tun_id outside of tun_key.
*/
memset(tun_key, 0, sizeof(struct ovs_key_ipv4_tunnel));
OVS_CB(skb)->tun_key = tun_key;
}

OVS_CB(skb)->tun_key->tun_id = nla_get_be64(nested_attr);
OVS_CB(skb)->tun_key->tun_flags |= OVS_FLOW_TNL_F_KEY;
break;

case OVS_KEY_ATTR_IPV4_TUNNEL:
OVS_CB(skb)->tun_key = nla_data(nested_attr);
break;

case OVS_KEY_ATTR_ETHERNET:
Expand All @@ -368,7 +386,8 @@ static int execute_set_action(struct sk_buff *skb,

/* Execute a list of actions against 'skb'. */
static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
const struct nlattr *attr, int len, bool keep_skb)
const struct nlattr *attr, int len,
struct ovs_key_ipv4_tunnel *tun_key, bool keep_skb)
{
/* Every output action needs a separate clone of 'skb', but the common
* case is just a single output action, so that doing a clone and
Expand Down Expand Up @@ -407,11 +426,11 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
break;

case OVS_ACTION_ATTR_SET:
err = execute_set_action(skb, nla_data(a));
err = execute_set_action(skb, nla_data(a), tun_key);
break;

case OVS_ACTION_ATTR_SAMPLE:
err = sample(dp, skb, a);
err = sample(dp, skb, a, tun_key);
break;
}

Expand Down Expand Up @@ -458,6 +477,7 @@ int ovs_execute_actions(struct datapath *dp, struct sk_buff *skb)
struct sw_flow_actions *acts = rcu_dereference(OVS_CB(skb)->flow->sf_acts);
struct loop_counter *loop;
int error;
struct ovs_key_ipv4_tunnel tun_key;

/* Check whether we've looped too much. */
loop = &__get_cpu_var(loop_counters);
Expand All @@ -469,9 +489,9 @@ int ovs_execute_actions(struct datapath *dp, struct sk_buff *skb)
goto out_loop;
}

OVS_CB(skb)->tun_id = 0;
OVS_CB(skb)->tun_key = NULL;
error = do_execute_actions(dp, skb, acts->actions,
acts->actions_len, false);
acts->actions_len, &tun_key, false);

/* Check whether sub-actions looped too much. */
if (unlikely(loop->looping))
Expand Down
9 changes: 8 additions & 1 deletion datapath/datapath.c
Original file line number Diff line number Diff line change
Expand Up @@ -587,12 +587,19 @@ static int validate_set(const struct nlattr *a,

switch (key_type) {
const struct ovs_key_ipv4 *ipv4_key;
const struct ovs_key_ipv4_tunnel *tun_key;

case OVS_KEY_ATTR_PRIORITY:
case OVS_KEY_ATTR_TUN_ID:
case OVS_KEY_ATTR_ETHERNET:
break;

case OVS_KEY_ATTR_IPV4_TUNNEL:
tun_key = nla_data(ovs_key);
if (!tun_key->ipv4_dst)
return -EINVAL;
break;

case OVS_KEY_ATTR_IPV4:
if (flow_key->eth.type != htons(ETH_P_IP))
return -EINVAL;
Expand Down Expand Up @@ -785,7 +792,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)

err = ovs_flow_metadata_from_nlattrs(&flow->key.phy.priority,
&flow->key.phy.in_port,
&flow->key.phy.tun_id,
&flow->key.tun.tun_key,
a[OVS_PACKET_ATTR_KEY]);
if (err)
goto err_flow_put;
Expand Down
5 changes: 3 additions & 2 deletions datapath/datapath.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,8 @@ struct datapath {
/**
* struct ovs_skb_cb - OVS data in skb CB
* @flow: The flow associated with this packet. May be %NULL if no flow.
* @tun_id: ID of the tunnel that encapsulated this packet. It is 0 if the
* @tun_key: Key for the tunnel that encapsulated this packet. NULL if the
* packet is not being tunneled.
* @ip_summed: Consistently stores L4 checksumming status across different
* kernel versions.
* @csum_start: Stores the offset from which to start checksumming independent
Expand All @@ -107,7 +108,7 @@ struct datapath {
*/
struct ovs_skb_cb {
struct sw_flow *flow;
__be64 tun_id;
struct ovs_key_ipv4_tunnel *tun_key;
#ifdef NEED_CSUM_NORMALIZE
enum csum_type ip_summed;
u16 csum_start;
Expand Down
86 changes: 78 additions & 8 deletions datapath/flow.c
Original file line number Diff line number Diff line change
Expand Up @@ -629,7 +629,8 @@ int ovs_flow_extract(struct sk_buff *skb, u16 in_port, struct sw_flow_key *key,
memset(key, 0, sizeof(*key));

key->phy.priority = skb->priority;
key->phy.tun_id = OVS_CB(skb)->tun_id;
if (OVS_CB(skb)->tun_key)
memcpy(&key->tun.tun_key, OVS_CB(skb)->tun_key, sizeof(key->tun.tun_key));
key->phy.in_port = in_port;

skb_reset_mac_header(skb);
Expand Down Expand Up @@ -847,6 +848,7 @@ const int ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = {

/* Not upstream. */
[OVS_KEY_ATTR_TUN_ID] = sizeof(__be64),
[OVS_KEY_ATTR_IPV4_TUNNEL] = sizeof(struct ovs_key_ipv4_tunnel),
};

static int ipv4_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_len,
Expand Down Expand Up @@ -1022,9 +1024,39 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp,
swkey->phy.in_port = DP_MAX_PORTS;
}

if (attrs & (1ULL << OVS_KEY_ATTR_TUN_ID)) {
swkey->phy.tun_id = nla_get_be64(a[OVS_KEY_ATTR_TUN_ID]);
if (attrs & (1ULL << OVS_KEY_ATTR_TUN_ID) &&
attrs & (1ULL << OVS_KEY_ATTR_IPV4_TUNNEL)) {
struct ovs_key_ipv4_tunnel *tun_key;
__be64 tun_id;

tun_key = nla_data(a[OVS_KEY_ATTR_IPV4_TUNNEL]);

if (!tun_key->ipv4_dst)
return -EINVAL;
if (!(tun_key->tun_flags & OVS_FLOW_TNL_F_KEY))
return -EINVAL;

tun_id = nla_get_be64(a[OVS_KEY_ATTR_TUN_ID]);
if (tun_id != tun_key->tun_id)
return -EINVAL;

memcpy(&swkey->tun.tun_key, tun_key, sizeof(swkey->tun.tun_key));
attrs &= ~(1ULL << OVS_KEY_ATTR_TUN_ID);
attrs &= ~(1ULL << OVS_KEY_ATTR_IPV4_TUNNEL);
} else if (attrs & (1ULL << OVS_KEY_ATTR_TUN_ID)) {
swkey->tun.tun_key.tun_id = nla_get_be64(a[OVS_KEY_ATTR_TUN_ID]);
swkey->tun.tun_key.tun_flags |= OVS_FLOW_TNL_F_KEY;

attrs &= ~(1ULL << OVS_KEY_ATTR_TUN_ID);
} else if (attrs & (1ULL << OVS_KEY_ATTR_IPV4_TUNNEL)) {
struct ovs_key_ipv4_tunnel *tun_key;
tun_key = nla_data(a[OVS_KEY_ATTR_IPV4_TUNNEL]);

if (!tun_key->ipv4_dst)
return -EINVAL;

memcpy(&swkey->tun.tun_key, tun_key, sizeof(swkey->tun.tun_key));
attrs &= ~(1ULL << OVS_KEY_ATTR_IPV4_TUNNEL);
}

/* Data attributes. */
Expand Down Expand Up @@ -1162,14 +1194,16 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp,
* get the metadata, that is, the parts of the flow key that cannot be
* extracted from the packet itself.
*/
int ovs_flow_metadata_from_nlattrs(u32 *priority, u16 *in_port, __be64 *tun_id,
int ovs_flow_metadata_from_nlattrs(u32 *priority, u16 *in_port,
struct ovs_key_ipv4_tunnel *tun_key,
const struct nlattr *attr)
{
const struct nlattr *nla;
int rem;
__be64 tun_id;

*in_port = DP_MAX_PORTS;
*tun_id = 0;
memset(tun_key, 0, sizeof(*tun_key));
*priority = 0;

nla_for_each_nested(nla, attr, rem) {
Expand All @@ -1185,7 +1219,35 @@ int ovs_flow_metadata_from_nlattrs(u32 *priority, u16 *in_port, __be64 *tun_id,
break;

case OVS_KEY_ATTR_TUN_ID:
*tun_id = nla_get_be64(nla);
tun_id = nla_get_be64(nla);

if (tun_key->ipv4_dst) {
if (!(tun_key->tun_flags & OVS_FLOW_TNL_F_KEY))
return -EINVAL;
if (tun_key->tun_id != tun_id)
return -EINVAL;
break;
}
tun_key->tun_id = tun_id;
tun_key->tun_flags |= OVS_FLOW_TNL_F_KEY;

break;

case OVS_KEY_ATTR_IPV4_TUNNEL:
if (tun_key->tun_flags & OVS_FLOW_TNL_F_KEY) {
tun_id = tun_key->tun_id;

memcpy(tun_key, nla_data(nla), sizeof(*tun_key));
if (!(tun_key->tun_flags & OVS_FLOW_TNL_F_KEY))
return -EINVAL;

if (tun_key->tun_id != tun_id)
return -EINVAL;
} else
memcpy(tun_key, nla_data(nla), sizeof(*tun_key));

if (!tun_key->ipv4_dst)
return -EINVAL;
break;

case OVS_KEY_ATTR_IN_PORT:
Expand All @@ -1210,8 +1272,16 @@ int ovs_flow_to_nlattrs(const struct sw_flow_key *swkey, struct sk_buff *skb)
nla_put_u32(skb, OVS_KEY_ATTR_PRIORITY, swkey->phy.priority))
goto nla_put_failure;

if (swkey->phy.tun_id != cpu_to_be64(0) &&
nla_put_be64(skb, OVS_KEY_ATTR_TUN_ID, swkey->phy.tun_id))
if (swkey->tun.tun_key.ipv4_dst) {
struct ovs_key_ipv4_tunnel *tun_key;
nla = nla_reserve(skb, OVS_KEY_ATTR_IPV4_TUNNEL, sizeof(*tun_key));
if (!nla)
goto nla_put_failure;
tun_key = nla_data(nla);
memcpy(tun_key, &swkey->tun.tun_key, sizeof(*tun_key));
}
if ((swkey->tun.tun_key.tun_flags & OVS_FLOW_TNL_F_KEY) &&
nla_put_be64(skb, OVS_KEY_ATTR_TUN_ID, swkey->tun.tun_key.tun_id))
goto nla_put_failure;

if (swkey->phy.in_port != DP_MAX_PORTS &&
Expand Down
12 changes: 8 additions & 4 deletions datapath/flow.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,12 @@ struct sw_flow_actions {

struct sw_flow_key {
struct {
__be64 tun_id; /* Encapsulating tunnel ID. */
u32 priority; /* Packet QoS priority. */
u16 in_port; /* Input switch port (or DP_MAX_PORTS). */
} phy;
struct {
struct ovs_key_ipv4_tunnel tun_key; /* Encapsulating tunnel key. */
} tun;
struct {
u8 src[ETH_ALEN]; /* Ethernet source address. */
u8 dst[ETH_ALEN]; /* Ethernet destination address. */
Expand Down Expand Up @@ -150,6 +152,7 @@ u64 ovs_flow_used_time(unsigned long flow_jiffies);
* ------ --- ------ -----
* OVS_KEY_ATTR_PRIORITY 4 -- 4 8
* OVS_KEY_ATTR_TUN_ID 8 -- 4 12
* OVS_KEY_ATTR_IPV4_TUNNEL 24 -- 4 28
* OVS_KEY_ATTR_IN_PORT 4 -- 4 8
* OVS_KEY_ATTR_ETHERNET 12 -- 4 16
* OVS_KEY_ATTR_ETHERTYPE 2 2 4 8 (outer VLAN ethertype)
Expand All @@ -160,14 +163,15 @@ u64 ovs_flow_used_time(unsigned long flow_jiffies);
* OVS_KEY_ATTR_ICMPV6 2 2 4 8
* OVS_KEY_ATTR_ND 28 -- 4 32
* -------------------------------------------------
* total 156
* total 184
*/
#define FLOW_BUFSIZE 156
#define FLOW_BUFSIZE 184

int ovs_flow_to_nlattrs(const struct sw_flow_key *, struct sk_buff *);
int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp,
const struct nlattr *);
int ovs_flow_metadata_from_nlattrs(u32 *priority, u16 *in_port, __be64 *tun_id,
int ovs_flow_metadata_from_nlattrs(u32 *priority, u16 *in_port,
struct ovs_key_ipv4_tunnel *tun_key,
const struct nlattr *);

#define MAX_ACTIONS_BUFSIZE (16 * 1024)
Expand Down
Loading

0 comments on commit 356af50

Please sign in to comment.