/*
- * Copyright (c) 2007, 2008, 2009, 2010, 2011 Nicira Networks.
- * Distributed under the terms of the GNU GPL version 2.
+ * Copyright (c) 2007-2011 Nicira Networks.
*
- * Significant portions of this file may be copied from parts of the Linux
- * kernel, by Linus Torvalds and others.
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
*/
-/* Functions for managing the dp interface/device. */
-
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/init.h>
#include "checksum.h"
#include "datapath.h"
-#include "actions.h"
#include "flow.h"
#include "vlan.h"
#include "tunnel.h"
const struct dp_upcall_info *);
/* Must be called with rcu_read_lock, genl_mutex, or RTNL lock. */
-struct datapath *get_dp(int dp_ifindex)
+static struct datapath *get_dp(int dp_ifindex)
{
struct datapath *dp = NULL;
struct net_device *dev;
return dp;
}
-EXPORT_SYMBOL_GPL(get_dp);
/* Must be called with genl_mutex. */
static struct flow_table *get_table_protected(struct datapath *dp)
{
struct datapath *dp = container_of(rcu, struct datapath, rcu);
- flow_tbl_destroy(dp->table);
+ flow_tbl_destroy((__force struct flow_table *)dp->table);
free_percpu(dp->stats_percpu);
kobject_put(&dp->ifobj);
}
const struct dp_upcall_info *upcall_info)
{
struct ovs_header *upcall;
+ struct sk_buff *nskb = NULL;
struct sk_buff *user_skb; /* to be queued to userspace */
struct nlattr *nla;
unsigned int len;
int err;
- err = vlan_deaccel_tag(skb);
- if (unlikely(err))
- return err;
+ if (vlan_tx_tag_present(skb)) {
+ nskb = skb_clone(skb, GFP_ATOMIC);
+ if (!nskb)
+ return -ENOMEM;
+
+ err = vlan_deaccel_tag(nskb);
+ if (err)
+ return err;
+
+ skb = nskb;
+ }
- if (nla_attr_size(skb->len) > USHRT_MAX)
- return -EFBIG;
+ if (nla_attr_size(skb->len) > USHRT_MAX) {
+ err = -EFBIG;
+ goto out;
+ }
len = sizeof(struct ovs_header);
len += nla_total_size(skb->len);
len += nla_total_size(8);
user_skb = genlmsg_new(len, GFP_ATOMIC);
- if (!user_skb)
- return -ENOMEM;
+ if (!user_skb) {
+ err = -ENOMEM;
+ goto out;
+ }
upcall = genlmsg_put(user_skb, 0, 0, &dp_packet_genl_family,
0, upcall_info->cmd);
skb_copy_and_csum_dev(skb, nla_data(nla));
- return genlmsg_unicast(&init_net, user_skb, upcall_info->pid);
+ err = genlmsg_unicast(&init_net, user_skb, upcall_info->pid);
+
+out:
+ kfree_skb(nskb);
+ return err;
}
/* Called with genl_mutex. */
return validate_actions(actions, key, depth + 1);
}
-static int validate_action_key(const struct nlattr *a,
- const struct sw_flow_key *flow_key)
+static int validate_set(const struct nlattr *a,
+ const struct sw_flow_key *flow_key)
{
- int act_type = nla_type(a);
const struct nlattr *ovs_key = nla_data(a);
int key_type = nla_type(ovs_key);
nla_len(ovs_key) != ovs_key_lens[key_type])
return -EINVAL;
-#define ACTION(act, key) (((act) << 8) | (key))
-
- switch (ACTION(act_type, key_type)) {
+ switch (key_type) {
const struct ovs_key_ipv4 *ipv4_key;
- const struct ovs_key_8021q *q_key;
- case ACTION(OVS_ACTION_ATTR_SET, OVS_KEY_ATTR_PRIORITY):
- case ACTION(OVS_ACTION_ATTR_SET, OVS_KEY_ATTR_TUN_ID):
- case ACTION(OVS_ACTION_ATTR_SET, OVS_KEY_ATTR_ETHERNET):
+ case OVS_KEY_ATTR_PRIORITY:
+ case OVS_KEY_ATTR_TUN_ID:
+ case OVS_KEY_ATTR_ETHERNET:
break;
- case ACTION(OVS_ACTION_ATTR_PUSH, OVS_KEY_ATTR_8021Q):
- q_key = nla_data(ovs_key);
- if (q_key->q_tpid != htons(ETH_P_8021Q))
- return -EINVAL;
-
- if (q_key->q_tci & htons(VLAN_TAG_PRESENT))
- return -EINVAL;
- break;
-
- case ACTION(OVS_ACTION_ATTR_SET, OVS_KEY_ATTR_IPV4):
+ case OVS_KEY_ATTR_IPV4:
if (flow_key->eth.type != htons(ETH_P_IP))
return -EINVAL;
break;
- case ACTION(OVS_ACTION_ATTR_SET, OVS_KEY_ATTR_TCP):
+ case OVS_KEY_ATTR_TCP:
if (flow_key->ip.proto != IPPROTO_TCP)
return -EINVAL;
break;
- case ACTION(OVS_ACTION_ATTR_SET, OVS_KEY_ATTR_UDP):
+ case OVS_KEY_ATTR_UDP:
if (flow_key->ip.proto != IPPROTO_UDP)
return -EINVAL;
default:
return -EINVAL;
}
-#undef ACTION
+
return 0;
}
nla_for_each_nested(a, attr, rem) {
/* Expected argument lengths, (u32)-1 for variable length. */
static const u32 action_lens[OVS_ACTION_ATTR_MAX + 1] = {
- [OVS_ACTION_ATTR_OUTPUT] = 4,
+ [OVS_ACTION_ATTR_OUTPUT] = sizeof(u32),
[OVS_ACTION_ATTR_USERSPACE] = (u32)-1,
- [OVS_ACTION_ATTR_PUSH] = (u32)-1,
- [OVS_ACTION_ATTR_POP] = 2,
+ [OVS_ACTION_ATTR_PUSH_VLAN] = sizeof(struct ovs_action_push_vlan),
+ [OVS_ACTION_ATTR_POP_VLAN] = 0,
[OVS_ACTION_ATTR_SET] = (u32)-1,
[OVS_ACTION_ATTR_SAMPLE] = (u32)-1
};
+ const struct ovs_action_push_vlan *vlan;
int type = nla_type(a);
if (type > OVS_ACTION_ATTR_MAX ||
break;
- case OVS_ACTION_ATTR_POP:
- if (nla_get_u16(a) != OVS_KEY_ATTR_8021Q)
+ case OVS_ACTION_ATTR_POP_VLAN:
+ break;
+
+ case OVS_ACTION_ATTR_PUSH_VLAN:
+ vlan = nla_data(a);
+ if (vlan->vlan_tpid != htons(ETH_P_8021Q))
+ return -EINVAL;
+ if (!(vlan->vlan_tci & htons(VLAN_TAG_PRESENT)))
return -EINVAL;
break;
case OVS_ACTION_ATTR_SET:
- case OVS_ACTION_ATTR_PUSH:
- err = validate_action_key(a, key);
+ err = validate_set(a, key);
if (err)
return err;
break;
u32 pid, u32 seq, u32 flags, u8 cmd)
{
struct ovs_header *ovs_header;
- struct nlattr *nla;
+ struct ovs_dp_stats dp_stats;
int err;
ovs_header = genlmsg_put(skb, pid, seq, &dp_datapath_genl_family,
if (err)
goto nla_put_failure;
- nla = nla_reserve(skb, OVS_DP_ATTR_STATS, sizeof(struct ovs_dp_stats));
- if (!nla)
- goto nla_put_failure;
- get_dp_stats(dp, nla_data(nla));
+ get_dp_stats(dp, &dp_stats);
+ NLA_PUT(skb, OVS_DP_ATTR_STATS, sizeof(struct ovs_dp_stats), &dp_stats);
return genlmsg_end(skb, ovs_header);
u32 pid, u32 seq, u32 flags, u8 cmd)
{
struct ovs_header *ovs_header;
- struct nlattr *nla;
+ struct ovs_vport_stats vport_stats;
int err;
ovs_header = genlmsg_put(skb, pid, seq, &dp_vport_genl_family,
NLA_PUT_STRING(skb, OVS_VPORT_ATTR_NAME, vport->ops->get_name(vport));
NLA_PUT_U32(skb, OVS_VPORT_ATTR_UPCALL_PID, vport->upcall_pid);
- nla = nla_reserve(skb, OVS_VPORT_ATTR_STATS,
- sizeof(struct ovs_vport_stats));
- if (!nla)
- goto nla_put_failure;
-
- vport_get_stats(vport, nla_data(nla));
+ vport_get_stats(vport, &vport_stats);
+ NLA_PUT(skb, OVS_VPORT_ATTR_STATS, sizeof(struct ovs_vport_stats),
+ &vport_stats);
NLA_PUT(skb, OVS_VPORT_ATTR_ADDRESS, ETH_ALEN,
vport->ops->get_addr(vport));
BUILD_BUG_ON(sizeof(struct ovs_skb_cb) > sizeof(dummy_skb->cb));
- pr_info("Open vSwitch %s, built "__DATE__" "__TIME__"\n",
+ pr_info("Open vSwitch switching datapath %s, built "__DATE__" "__TIME__"\n",
VERSION BUILDNR);
err = tnl_init();