/*
* Distributed under the terms of the GNU GPL version 2.
- * Copyright (c) 2007, 2008, 2009, 2010 Nicira Networks.
+ * Copyright (c) 2007, 2008, 2009, 2010, 2011 Nicira Networks.
*
* Significant portions of this file may be copied from parts of the Linux
* kernel, by Linus Torvalds and others.
#include "openvswitch/datapath-protocol.h"
#include "vport.h"
+static int do_execute_actions(struct datapath *, struct sk_buff *,
+ const struct sw_flow_key *,
+ const struct nlattr *actions, u32 actions_len);
+
static struct sk_buff *make_writable(struct sk_buff *skb, unsigned min_headroom)
{
if (skb_cloned(skb)) {
}
static struct sk_buff *modify_vlan_tci(struct datapath *dp, struct sk_buff *skb,
- const struct odp_flow_key *key,
+ const struct sw_flow_key *key,
const struct nlattr *a, u32 actions_len)
{
__be16 tci = nla_get_be16(a);
* groups configured). */
if (skb_is_gso(skb)) {
const struct nlattr *actions_left;
- u32 actions_len_left;
+ int actions_len_left;
struct sk_buff *segs;
segs = skb_gso_segment(skb, 0);
kfree_skb(skb);
- if (unlikely(IS_ERR(segs)))
+ if (IS_ERR(segs))
return ERR_CAST(segs);
actions_len_left = actions_len;
do {
struct sk_buff *nskb = segs->next;
- int err;
segs->next = NULL;
segs = __vlan_put_tag(segs, ntohs(tci));
err = -ENOMEM;
if (segs) {
- err = execute_actions(
+ err = do_execute_actions(
dp, segs, key, actions_left,
actions_len_left);
}
return skb;
}
-static bool is_ip(struct sk_buff *skb, const struct odp_flow_key *key)
+static bool is_ip(struct sk_buff *skb, const struct sw_flow_key *key)
{
return (key->dl_type == htons(ETH_P_IP) &&
skb->transport_header > skb->network_header);
}
-static __sum16 *get_l4_checksum(struct sk_buff *skb, const struct odp_flow_key *key)
+static __sum16 *get_l4_checksum(struct sk_buff *skb, const struct sw_flow_key *key)
{
int transport_len = skb->len - skb_transport_offset(skb);
if (key->nw_proto == IPPROTO_TCP) {
}
static struct sk_buff *set_nw_addr(struct sk_buff *skb,
- const struct odp_flow_key *key,
+ const struct sw_flow_key *key,
const struct nlattr *a)
{
__be32 new_nwaddr = nla_get_be32(a);
}
static struct sk_buff *set_nw_tos(struct sk_buff *skb,
- const struct odp_flow_key *key,
+ const struct sw_flow_key *key,
u8 nw_tos)
{
if (unlikely(!is_ip(skb, key)))
}
static struct sk_buff *set_tp_port(struct sk_buff *skb,
- const struct odp_flow_key *key,
+ const struct sw_flow_key *key,
const struct nlattr *a)
{
struct udphdr *th;
* or truncated header fields or one whose inner and outer Ethernet address
* differ.
*/
-static bool is_spoofed_arp(struct sk_buff *skb, const struct odp_flow_key *key)
+static bool is_spoofed_arp(struct sk_buff *skb, const struct sw_flow_key *key)
{
struct arp_eth_header *arp;
kfree_skb(skb);
}
-static int output_control(struct datapath *dp, struct sk_buff *skb, u32 arg)
+static int output_control(struct datapath *dp, struct sk_buff *skb, u64 arg,
+ const struct sw_flow_key *key)
{
+ struct dp_upcall_info upcall;
+
skb = skb_clone(skb, GFP_ATOMIC);
if (!skb)
return -ENOMEM;
- return dp_output_control(dp, skb, _ODPL_ACTION_NR, arg);
-}
-
-/* Send a copy of this packet up to the sFlow agent, along with extra
- * information about what happened to it. */
-static void sflow_sample(struct datapath *dp, struct sk_buff *skb,
- const struct nlattr *a, u32 actions_len,
- struct vport *vport)
-{
- struct odp_sflow_sample_header *hdr;
- unsigned int hdrlen = sizeof(struct odp_sflow_sample_header);
- struct sk_buff *nskb;
- nskb = skb_copy_expand(skb, actions_len + hdrlen, 0, GFP_ATOMIC);
- if (!nskb)
- return;
-
- memcpy(__skb_push(nskb, actions_len), a, actions_len);
- hdr = (struct odp_sflow_sample_header*)__skb_push(nskb, hdrlen);
- hdr->actions_len = actions_len;
- hdr->sample_pool = atomic_read(&vport->sflow_pool);
- dp_output_control(dp, nskb, _ODPL_SFLOW_NR, 0);
+ upcall.cmd = ODP_PACKET_CMD_ACTION;
+ upcall.key = key;
+ upcall.userdata = arg;
+ upcall.sample_pool = 0;
+ upcall.actions = NULL;
+ upcall.actions_len = 0;
+ return dp_upcall(dp, skb, &upcall);
}
/* Execute a list of actions against 'skb'. */
-int execute_actions(struct datapath *dp, struct sk_buff *skb,
- const struct odp_flow_key *key,
- const struct nlattr *actions, u32 actions_len)
+static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
+ const struct sw_flow_key *key,
+ const struct nlattr *actions, u32 actions_len)
{
/* 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
const struct nlattr *a;
int rem, err;
- if (dp->sflow_probability) {
- struct vport *p = OVS_CB(skb)->vport;
- if (p) {
- atomic_inc(&p->sflow_pool);
- if (dp->sflow_probability == UINT_MAX ||
- net_random() < dp->sflow_probability)
- sflow_sample(dp, skb, actions, actions_len, p);
- }
- }
-
- OVS_CB(skb)->tun_id = 0;
-
for (a = actions, rem = actions_len; rem > 0; a = nla_next(a, &rem)) {
if (prev_port != -1) {
do_output(dp, skb_clone(skb, GFP_ATOMIC), prev_port);
break;
case ODPAT_CONTROLLER:
- err = output_control(dp, skb, nla_get_u64(a));
+ err = output_control(dp, skb, nla_get_u64(a), key);
if (err) {
kfree_skb(skb);
return err;
kfree_skb(skb);
return 0;
}
+
+static void sflow_sample(struct datapath *dp, struct sk_buff *skb,
+ const struct sw_flow_key *key,
+ const struct nlattr *a, u32 actions_len)
+{
+ struct sk_buff *nskb;
+ struct vport *p = OVS_CB(skb)->vport;
+ struct dp_upcall_info upcall;
+
+ if (unlikely(!p))
+ return;
+
+ atomic_inc(&p->sflow_pool);
+ if (net_random() >= dp->sflow_probability)
+ return;
+
+ nskb = skb_clone(skb, GFP_ATOMIC);
+ if (unlikely(!nskb))
+ return;
+
+ upcall.cmd = ODP_PACKET_CMD_SAMPLE;
+ upcall.key = key;
+ upcall.userdata = 0;
+ upcall.sample_pool = atomic_read(&p->sflow_pool);
+ upcall.actions = a;
+ upcall.actions_len = actions_len;
+ dp_upcall(dp, nskb, &upcall);
+}
+
+/* Execute a list of actions against 'skb'. */
+int execute_actions(struct datapath *dp, struct sk_buff *skb,
+ const struct sw_flow_key *key,
+ const struct nlattr *actions, u32 actions_len)
+{
+ if (dp->sflow_probability)
+ sflow_sample(dp, skb, key, actions, actions_len);
+
+ OVS_CB(skb)->tun_id = 0;
+
+ return do_execute_actions(dp, skb, key, actions, actions_len);
+}