Skip to content

Commit

Permalink
openvswitch: refactor ovs flow extract API.
Browse files Browse the repository at this point in the history
OVS flow extract is called on packet receive or packet
execute code path.  Following patch defines separate API
for extracting flow-key in packet execute code path.

Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
Acked-by: Andy Zhou <azhou@nicira.com>
  • Loading branch information
Pravin B Shelar committed Sep 16, 2014
1 parent 2ff3e4e commit 83c8df2
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 41 deletions.
21 changes: 15 additions & 6 deletions net/openvswitch/datapath.c
Original file line number Diff line number Diff line change
Expand Up @@ -237,8 +237,9 @@ void ovs_dp_detach_port(struct vport *p)
}

/* Must be called with rcu_read_lock. */
void ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb)
void ovs_dp_process_received_packet(struct sk_buff *skb)
{
const struct vport *p = OVS_CB(skb)->input_vport;
struct datapath *dp = p->dp;
struct sw_flow *flow;
struct dp_stats_percpu *stats;
Expand All @@ -250,7 +251,7 @@ void ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb)
stats = this_cpu_ptr(dp->stats_percpu);

/* Extract flow from 'skb' into 'key'. */
error = ovs_flow_extract(skb, p->port_no, &key);
error = ovs_flow_key_extract(skb, &key);
if (unlikely(error)) {
kfree_skb(skb);
return;
Expand Down Expand Up @@ -514,6 +515,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
struct sw_flow *flow;
struct datapath *dp;
struct ethhdr *eth;
struct vport *input_vport;
int len;
int err;

Expand Down Expand Up @@ -548,13 +550,11 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
if (IS_ERR(flow))
goto err_kfree_skb;

err = ovs_flow_extract(packet, -1, &flow->key);
err = ovs_flow_key_extract_userspace(a[OVS_PACKET_ATTR_KEY], packet,
&flow->key);
if (err)
goto err_flow_free;

err = ovs_nla_get_flow_metadata(flow, a[OVS_PACKET_ATTR_KEY]);
if (err)
goto err_flow_free;
acts = ovs_nla_alloc_flow_actions(nla_len(a[OVS_PACKET_ATTR_ACTIONS]));
err = PTR_ERR(acts);
if (IS_ERR(acts))
Expand All @@ -576,6 +576,15 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
if (!dp)
goto err_unlock;

input_vport = ovs_vport_rcu(dp, flow->key.phy.in_port);
if (!input_vport)
input_vport = ovs_vport_rcu(dp, OVSP_LOCAL);

if (!input_vport)
goto err_unlock;

OVS_CB(packet)->input_vport = input_vport;

local_bh_disable();
err = ovs_execute_actions(dp, packet, &flow->key);
local_bh_enable();
Expand Down
5 changes: 4 additions & 1 deletion net/openvswitch/datapath.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,13 @@ struct datapath {
* @flow: The flow associated with this packet. May be %NULL if no flow.
* @tun_key: Key for the tunnel that encapsulated this packet. NULL if the
* packet is not being tunneled.
* @input_vport: The original vport packet came in on. This value is cached
* when a packet is received by OVS.
*/
struct ovs_skb_cb {
struct sw_flow *flow;
struct ovs_key_ipv4_tunnel *tun_key;
struct vport *input_vport;
};
#define OVS_CB(skb) ((struct ovs_skb_cb *)(skb)->cb)

Expand Down Expand Up @@ -181,7 +184,7 @@ static inline struct vport *ovs_vport_ovsl(const struct datapath *dp, int port_n
extern struct notifier_block ovs_dp_device_notifier;
extern struct genl_family dp_vport_genl_family;

void ovs_dp_process_received_packet(struct vport *, struct sk_buff *);
void ovs_dp_process_received_packet(struct sk_buff *);
void ovs_dp_detach_port(struct vport *);
int ovs_dp_upcall(struct datapath *, struct sk_buff *,
const struct dp_upcall_info *);
Expand Down
49 changes: 35 additions & 14 deletions net/openvswitch/flow.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@
* 02110-1301, USA
*/

#include "flow.h"
#include "datapath.h"
#include <linux/uaccess.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
Expand Down Expand Up @@ -46,6 +44,10 @@
#include <net/ipv6.h>
#include <net/ndisc.h>

#include "datapath.h"
#include "flow.h"
#include "flow_netlink.h"

u64 ovs_flow_used_time(unsigned long flow_jiffies)
{
struct timespec cur_ts;
Expand Down Expand Up @@ -420,10 +422,9 @@ static int parse_icmpv6(struct sk_buff *skb, struct sw_flow_key *key,
}

/**
* ovs_flow_extract - extracts a flow key from an Ethernet frame.
* key_extract - extracts a flow key from an Ethernet frame.
* @skb: sk_buff that contains the frame, with skb->data pointing to the
* Ethernet header
* @in_port: port number on which @skb was received.
* @key: output flow key
*
* The caller must ensure that skb->len >= ETH_HLEN.
Expand All @@ -442,19 +443,11 @@ static int parse_icmpv6(struct sk_buff *skb, struct sw_flow_key *key,
* of a correct length, otherwise the same as skb->network_header.
* For other key->eth.type values it is left untouched.
*/
int ovs_flow_extract(struct sk_buff *skb, u16 in_port, struct sw_flow_key *key)
static int key_extract(struct sk_buff *skb, struct sw_flow_key *key)
{
int error;
struct ethhdr *eth;

memset(key, 0, sizeof(*key));

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

skb_reset_mac_header(skb);

/* Link layer. We are guaranteed to have at least the 14 byte Ethernet
Expand Down Expand Up @@ -610,6 +603,34 @@ int ovs_flow_extract(struct sk_buff *skb, u16 in_port, struct sw_flow_key *key)
}
}
}

return 0;
}

int ovs_flow_key_extract(struct sk_buff *skb, struct sw_flow_key *key)
{
/* Extract metadata from packet. */
memset(key, 0, sizeof(*key));
if (OVS_CB(skb)->tun_key)
memcpy(&key->tun_key, OVS_CB(skb)->tun_key, sizeof(key->tun_key));

key->phy.priority = skb->priority;
key->phy.in_port = OVS_CB(skb)->input_vport->port_no;
key->phy.skb_mark = skb->mark;

return key_extract(skb, key);
}

int ovs_flow_key_extract_userspace(const struct nlattr *attr,
struct sk_buff *skb,
struct sw_flow_key *key)
{
int err;

memset(key, 0, sizeof(*key));
/* Extract metadata from netlink attributes. */
err = ovs_nla_get_flow_metadata(attr, key);
if (err)
return err;

return key_extract(skb, key);
}
6 changes: 5 additions & 1 deletion net/openvswitch/flow.h
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,10 @@ void ovs_flow_stats_get(const struct sw_flow *, struct ovs_flow_stats *,
void ovs_flow_stats_clear(struct sw_flow *);
u64 ovs_flow_used_time(unsigned long flow_jiffies);

int ovs_flow_extract(struct sk_buff *, u16 in_port, struct sw_flow_key *);
int ovs_flow_key_extract(struct sk_buff *skb, struct sw_flow_key *key);
/* Extract key from packet coming from userspace. */
int ovs_flow_key_extract_userspace(const struct nlattr *attr,
struct sk_buff *skb,
struct sw_flow_key *key);

#endif /* flow.h */
22 changes: 7 additions & 15 deletions net/openvswitch/flow_netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -836,7 +836,7 @@ int ovs_nla_get_match(struct sw_flow_match *match,

/**
* ovs_nla_get_flow_metadata - parses Netlink attributes into a flow key.
* @flow: Receives extracted in_port, priority, tun_key and skb_mark.
* @key: Receives extracted in_port, priority, tun_key and skb_mark.
* @attr: Netlink attribute holding nested %OVS_KEY_ATTR_* Netlink attribute
* sequence.
*
Expand All @@ -846,32 +846,24 @@ int ovs_nla_get_match(struct sw_flow_match *match,
* extracted from the packet itself.
*/

int ovs_nla_get_flow_metadata(struct sw_flow *flow,
const struct nlattr *attr)
int ovs_nla_get_flow_metadata(const struct nlattr *attr,
struct sw_flow_key *key)
{
struct ovs_key_ipv4_tunnel *tun_key = &flow->key.tun_key;
const struct nlattr *a[OVS_KEY_ATTR_MAX + 1];
struct sw_flow_match match;
u64 attrs = 0;
int err;
struct sw_flow_match match;

flow->key.phy.in_port = DP_MAX_PORTS;
flow->key.phy.priority = 0;
flow->key.phy.skb_mark = 0;
memset(tun_key, 0, sizeof(flow->key.tun_key));

err = parse_flow_nlattrs(attr, a, &attrs);
if (err)
return -EINVAL;

memset(&match, 0, sizeof(match));
match.key = &flow->key;
match.key = key;

err = metadata_from_nlattrs(&match, &attrs, a, false);
if (err)
return err;
key->phy.in_port = DP_MAX_PORTS;

return 0;
return metadata_from_nlattrs(&match, &attrs, a, false);
}

int ovs_nla_put_flow(const struct sw_flow_key *swkey,
Expand Down
4 changes: 2 additions & 2 deletions net/openvswitch/flow_netlink.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ void ovs_match_init(struct sw_flow_match *match,

int ovs_nla_put_flow(const struct sw_flow_key *,
const struct sw_flow_key *, struct sk_buff *);
int ovs_nla_get_flow_metadata(struct sw_flow *flow,
const struct nlattr *attr);
int ovs_nla_get_flow_metadata(const struct nlattr *, struct sw_flow_key *);

int ovs_nla_get_match(struct sw_flow_match *match,
const struct nlattr *,
const struct nlattr *);
Expand Down
5 changes: 3 additions & 2 deletions net/openvswitch/vport.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2007-2012 Nicira, Inc.
* Copyright (c) 2007-2014 Nicira, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
Expand Down Expand Up @@ -443,7 +443,8 @@ void ovs_vport_receive(struct vport *vport, struct sk_buff *skb,
u64_stats_update_end(&stats->syncp);

OVS_CB(skb)->tun_key = tun_key;
ovs_dp_process_received_packet(vport, skb);
OVS_CB(skb)->input_vport = vport;
ovs_dp_process_received_packet(skb);
}

/**
Expand Down

0 comments on commit 83c8df2

Please sign in to comment.