#include "vlan.h"
#include "vport-internal_dev.h"
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) || \
+ LINUX_VERSION_CODE > KERNEL_VERSION(2,6,39)
+#error Kernels before 2.6.18 or after 2.6.39 are not supported by this version of Open vSwitch.
+#endif
+
int (*dp_ioctl_hook)(struct net_device *dev, struct ifreq *rq, int cmd);
EXPORT_SYMBOL(dp_ioctl_hook);
if (!OVS_CB(skb)->flow) {
struct sw_flow_key key;
struct tbl_node *flow_node;
+ int key_len;
bool is_frag;
/* Extract flow from 'skb' into 'key'. */
- error = flow_extract(skb, p->port_no, &key, &is_frag);
+ error = flow_extract(skb, p->port_no, &key, &key_len, &is_frag);
if (unlikely(error)) {
kfree_skb(skb);
return;
}
/* Look up flow. */
- flow_node = tbl_lookup(rcu_dereference(dp->table), &key,
- flow_hash(&key), flow_cmp);
+ flow_node = tbl_lookup(rcu_dereference(dp->table), &key, key_len,
+ flow_hash(&key, key_len), flow_cmp);
if (unlikely(!flow_node)) {
struct dp_upcall_info upcall;
WARN_ON_ONCE(skb_shared(skb));
- forward_ip_summed(skb);
-
- err = vswitch_skb_checksum_setup(skb);
- if (err)
- goto err_kfree_skb;
+ forward_ip_summed(skb, true);
/* Break apart GSO packets into their component pieces. Otherwise
* userspace may try to stuff a 64kB packet into a 1500-byte MTU. */
return 0;
-err_kfree_skb:
- kfree_skb(skb);
err:
local_bh_disable();
stats = per_cpu_ptr(dp->stats_percpu, smp_processor_id());
{
u32 group = packet_mc_group(dp, upcall_info->cmd);
struct sk_buff *nskb;
- int port_no;
int err;
- if (OVS_CB(skb)->vport)
- port_no = OVS_CB(skb)->vport->port_no;
- else
- port_no = ODPP_LOCAL;
-
do {
struct odp_header *upcall;
struct sk_buff *user_skb; /* to be queued to userspace */
[ODP_ACTION_ATTR_SET_TUNNEL] = 8,
[ODP_ACTION_ATTR_SET_PRIORITY] = 4,
[ODP_ACTION_ATTR_POP_PRIORITY] = 0,
- [ODP_ACTION_ATTR_DROP_SPOOFED_ARP] = 0,
};
int type = nla_type(a);
case ODP_ACTION_ATTR_SET_TUNNEL:
case ODP_ACTION_ATTR_SET_PRIORITY:
case ODP_ACTION_ATTR_POP_PRIORITY:
- case ODP_ACTION_ATTR_DROP_SPOOFED_ARP:
/* No validation needed. */
break;
bool is_frag;
int len;
int err;
+ int key_len;
err = -EINVAL;
- if (!a[ODP_PACKET_ATTR_PACKET] || !a[ODP_PACKET_ATTR_ACTIONS] ||
+ if (!a[ODP_PACKET_ATTR_PACKET] || !a[ODP_PACKET_ATTR_KEY] ||
+ !a[ODP_PACKET_ATTR_ACTIONS] ||
nla_len(a[ODP_PACKET_ATTR_PACKET]) < ETH_HLEN)
goto err;
if (IS_ERR(flow))
goto err_kfree_skb;
- err = flow_extract(packet, -1, &flow->key, &is_frag);
+ err = flow_extract(packet, -1, &flow->key, &key_len, &is_frag);
+ if (err)
+ goto err_flow_put;
+ flow->tbl_node.hash = flow_hash(&flow->key, key_len);
+
+ err = flow_metadata_from_nlattrs(&flow->key.eth.in_port,
+ &flow->key.eth.tun_id,
+ a[ODP_PACKET_ATTR_KEY]);
if (err)
goto err_flow_put;
- flow->tbl_node.hash = flow_hash(&flow->key);
acts = flow_actions_alloc(a[ODP_PACKET_ATTR_ACTIONS]);
err = PTR_ERR(acts);
static const struct nla_policy packet_policy[ODP_PACKET_ATTR_MAX + 1] = {
[ODP_PACKET_ATTR_PACKET] = { .type = NLA_UNSPEC },
+ [ODP_PACKET_ATTR_KEY] = { .type = NLA_NESTED },
[ODP_PACKET_ATTR_ACTIONS] = { .type = NLA_NESTED },
};
struct tbl *table;
u32 hash;
int error;
+ int key_len;
/* Extract key. */
error = -EINVAL;
if (!a[ODP_FLOW_ATTR_KEY])
goto error;
- error = flow_from_nlattrs(&key, a[ODP_FLOW_ATTR_KEY]);
+ error = flow_from_nlattrs(&key, &key_len, a[ODP_FLOW_ATTR_KEY]);
if (error)
goto error;
if (!dp)
goto error;
- hash = flow_hash(&key);
+ hash = flow_hash(&key, key_len);
table = get_table_protected(dp);
- flow_node = tbl_lookup(table, &key, hash, flow_cmp);
+ flow_node = tbl_lookup(table, &key, key_len, hash, flow_cmp);
if (!flow_node) {
struct sw_flow_actions *acts;
struct datapath *dp;
struct tbl *table;
int err;
+ int key_len;
if (!a[ODP_FLOW_ATTR_KEY])
return -EINVAL;
- err = flow_from_nlattrs(&key, a[ODP_FLOW_ATTR_KEY]);
+ err = flow_from_nlattrs(&key, &key_len, a[ODP_FLOW_ATTR_KEY]);
if (err)
return err;
return -ENODEV;
table = get_table_protected(dp);
- flow_node = tbl_lookup(table, &key, flow_hash(&key), flow_cmp);
+ flow_node = tbl_lookup(table, &key, key_len, flow_hash(&key, key_len),
+ flow_cmp);
if (!flow_node)
return -ENOENT;
struct datapath *dp;
struct tbl *table;
int err;
+ int key_len;
if (!a[ODP_FLOW_ATTR_KEY])
return flush_flows(odp_header->dp_ifindex);
- err = flow_from_nlattrs(&key, a[ODP_FLOW_ATTR_KEY]);
+ err = flow_from_nlattrs(&key, &key_len, a[ODP_FLOW_ATTR_KEY]);
if (err)
return err;
return -ENODEV;
table = get_table_protected(dp);
- flow_node = tbl_lookup(table, &key, flow_hash(&key), flow_cmp);
+ flow_node = tbl_lookup(table, &key, key_len, flow_hash(&key, key_len),
+ flow_cmp);
if (!flow_node)
return -ENOENT;
flow = flow_cast(flow_node);
if (IS_ERR(reply))
goto exit_unlock;
- err = genlmsg_reply(reply, info);
+ rcu_read_unlock();
+
+ return genlmsg_reply(reply, info);
exit_unlock:
rcu_read_unlock();