#include "datapath.h"
#include "actions.h"
#include "flow.h"
-#include "table.h"
#include "vlan.h"
+#include "tunnel.h"
#include "vport-internal_dev.h"
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) || \
EXPORT_SYMBOL_GPL(get_dp);
/* Must be called with genl_mutex. */
-static struct tbl *get_table_protected(struct datapath *dp)
+static struct flow_table *get_table_protected(struct datapath *dp)
{
return rcu_dereference_protected(dp->table, lockdep_genl_is_held());
}
+ nla_total_size(MAX_ADDR_LEN) /* IFLA_ADDRESS */
+ nla_total_size(4) /* IFLA_MASTER */
+ nla_total_size(4) /* IFLA_MTU */
- + nla_total_size(4) /* IFLA_LINK */
+ nla_total_size(1); /* IFLA_OPERSTATE */
}
{
struct datapath *dp = container_of(rcu, struct datapath, rcu);
- tbl_destroy((struct tbl __force *)dp->table, flow_free_tbl);
+ flow_tbl_destroy(dp->table);
free_percpu(dp->stats_percpu);
kobject_put(&dp->ifobj);
}
}
/* Called with RTNL lock. */
-int dp_detach_port(struct vport *p)
+void dp_detach_port(struct vport *p)
{
ASSERT_RTNL();
rcu_assign_pointer(p->dp->ports[p->port_no], NULL);
/* Then destroy it. */
- return vport_del(p);
+ vport_del(p);
}
/* Must be called with rcu_read_lock. */
void dp_process_received_packet(struct vport *p, struct sk_buff *skb)
{
struct datapath *dp = p->dp;
+ struct sw_flow *flow;
struct dp_stats_percpu *stats;
int stats_counter_off;
int error;
if (!OVS_CB(skb)->flow) {
struct sw_flow_key key;
- struct tbl_node *flow_node;
int key_len;
bool is_frag;
}
/* Look up flow. */
- flow_node = tbl_lookup(rcu_dereference(dp->table), &key, key_len,
- flow_hash(&key, key_len), flow_cmp);
- if (unlikely(!flow_node)) {
+ flow = flow_tbl_lookup(rcu_dereference(dp->table), &key, key_len);
+ if (unlikely(!flow)) {
struct dp_upcall_info upcall;
upcall.cmd = OVS_PACKET_CMD_MISS;
goto out;
}
- OVS_CB(skb)->flow = flow_cast(flow_node);
+ OVS_CB(skb)->flow = flow;
}
stats_counter_off = offsetof(struct dp_stats_percpu, n_hit);
/* Called with genl_mutex. */
static int flush_flows(int dp_ifindex)
{
- struct tbl *old_table;
- struct tbl *new_table;
+ struct flow_table *old_table;
+ struct flow_table *new_table;
struct datapath *dp;
dp = get_dp(dp_ifindex);
return -ENODEV;
old_table = get_table_protected(dp);
- new_table = tbl_create(TBL_MIN_BUCKETS);
+ new_table = flow_tbl_alloc(TBL_MIN_BUCKETS);
if (!new_table)
return -ENOMEM;
rcu_assign_pointer(dp->table, new_table);
- tbl_deferred_destroy(old_table, flow_free_tbl);
-
+ flow_tbl_deferred_destroy(old_table);
return 0;
}
static const u32 action_lens[OVS_ACTION_ATTR_MAX + 1] = {
[OVS_ACTION_ATTR_OUTPUT] = 4,
[OVS_ACTION_ATTR_USERSPACE] = 8,
- [OVS_ACTION_ATTR_SET_DL_TCI] = 2,
- [OVS_ACTION_ATTR_STRIP_VLAN] = 0,
+ [OVS_ACTION_ATTR_PUSH_VLAN] = 2,
+ [OVS_ACTION_ATTR_POP_VLAN] = 0,
[OVS_ACTION_ATTR_SET_DL_SRC] = ETH_ALEN,
[OVS_ACTION_ATTR_SET_DL_DST] = ETH_ALEN,
[OVS_ACTION_ATTR_SET_NW_SRC] = 4,
return -EINVAL;
case OVS_ACTION_ATTR_USERSPACE:
- case OVS_ACTION_ATTR_STRIP_VLAN:
+ case OVS_ACTION_ATTR_POP_VLAN:
case OVS_ACTION_ATTR_SET_DL_SRC:
case OVS_ACTION_ATTR_SET_DL_DST:
case OVS_ACTION_ATTR_SET_NW_SRC:
return -EINVAL;
break;
- case OVS_ACTION_ATTR_SET_DL_TCI:
+ case OVS_ACTION_ATTR_PUSH_VLAN:
if (nla_get_be16(a) & htons(VLAN_CFI_MASK))
return -EINVAL;
break;
flow->byte_count = 0;
}
-/* Called with genl_mutex. */
-static int expand_table(struct datapath *dp)
-{
- struct tbl *old_table = get_table_protected(dp);
- struct tbl *new_table;
-
- new_table = tbl_expand(old_table);
- if (IS_ERR(new_table)) {
- if (PTR_ERR(new_table) != -ENOSPC)
- return PTR_ERR(new_table);
- } else {
- rcu_assign_pointer(dp->table, new_table);
- tbl_deferred_destroy(old_table, NULL);
- }
-
- return 0;
-}
-
static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
{
struct ovs_header *ovs_header = info->userhdr;
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,
if (err)
goto err_flow_put;
+ flow->hash = flow_hash(&flow->key, key_len);
+
acts = flow_actions_alloc(a[OVS_PACKET_ATTR_ACTIONS]);
err = PTR_ERR(acts);
if (IS_ERR(acts))
err = -ENODEV;
if (!dp)
goto err_unlock;
+
+ if (flow->key.eth.in_port < DP_MAX_PORTS)
+ OVS_CB(packet)->vport = get_vport_protected(dp,
+ flow->key.eth.in_port);
+
err = execute_actions(dp, packet);
rcu_read_unlock();
static void get_dp_stats(struct datapath *dp, struct ovs_dp_stats *stats)
{
int i;
- struct tbl *table = get_table_protected(dp);
+ struct flow_table *table = get_table_protected(dp);
- stats->n_flows = tbl_count(table);
+ stats->n_flows = flow_tbl_count(table);
stats->n_frags = stats->n_hit = stats->n_missed = stats->n_lost = 0;
for_each_possible_cpu(i) {
}
}
-/* MTU of the dp pseudo-device: ETH_DATA_LEN or the minimum of the ports.
- * Called with RTNL lock.
- */
-int dp_min_mtu(const struct datapath *dp)
-{
- struct vport *p;
- int mtu = 0;
-
- ASSERT_RTNL();
-
- list_for_each_entry (p, &dp->port_list, node) {
- int dev_mtu;
-
- /* Skip any internal ports, since that's what we're trying to
- * set. */
- if (is_internal_vport(p))
- continue;
-
- dev_mtu = vport_get_mtu(p);
- if (!dev_mtu)
- continue;
- if (!mtu || dev_mtu < mtu)
- mtu = dev_mtu;
- }
-
- return mtu ? mtu : ETH_DATA_LEN;
-}
-
-/* Sets the MTU of all datapath devices to the minimum of the ports
- * Called with RTNL lock.
- */
-void set_internal_devs_mtu(const struct datapath *dp)
-{
- struct vport *p;
- int mtu;
-
- ASSERT_RTNL();
-
- mtu = dp_min_mtu(dp);
-
- list_for_each_entry (p, &dp->port_list, node) {
- if (is_internal_vport(p))
- vport_set_mtu(p, mtu);
- }
-}
-
static const struct nla_policy flow_policy[OVS_FLOW_ATTR_MAX + 1] = {
[OVS_FLOW_ATTR_KEY] = { .type = NLA_NESTED },
[OVS_FLOW_ATTR_ACTIONS] = { .type = NLA_NESTED },
{
struct nlattr **a = info->attrs;
struct ovs_header *ovs_header = info->userhdr;
- struct tbl_node *flow_node;
struct sw_flow_key key;
struct sw_flow *flow;
struct sk_buff *reply;
struct datapath *dp;
- struct tbl *table;
- u32 hash;
+ struct flow_table *table;
int error;
int key_len;
if (!dp)
goto error;
- hash = flow_hash(&key, key_len);
table = get_table_protected(dp);
- flow_node = tbl_lookup(table, &key, key_len, hash, flow_cmp);
- if (!flow_node) {
+ flow = flow_tbl_lookup(table, &key, key_len);
+ if (!flow) {
struct sw_flow_actions *acts;
/* Bail out if we're not allowed to create a new flow. */
goto error;
/* Expand table, if necessary, to make room. */
- if (tbl_count(table) >= tbl_n_buckets(table)) {
- error = expand_table(dp);
- if (error)
- goto error;
- table = get_table_protected(dp);
+ if (flow_tbl_need_to_expand(table)) {
+ struct flow_table *new_table;
+
+ new_table = flow_tbl_expand(table);
+ if (!IS_ERR(new_table)) {
+ rcu_assign_pointer(dp->table, new_table);
+ flow_tbl_deferred_destroy(table);
+ table = get_table_protected(dp);
+ }
}
/* Allocate flow. */
rcu_assign_pointer(flow->sf_acts, acts);
/* Put flow in bucket. */
- error = tbl_insert(table, &flow->tbl_node, hash);
- if (error)
- goto error_free_flow;
+ flow->hash = flow_hash(&key, key_len);
+ flow_tbl_insert(table, flow);
reply = ovs_flow_cmd_build_info(flow, dp, info->snd_pid,
info->snd_seq, OVS_FLOW_CMD_NEW);
goto error;
/* Update actions. */
- flow = flow_cast(flow_node);
old_acts = rcu_dereference_protected(flow->sf_acts,
lockdep_genl_is_held());
if (a[OVS_FLOW_ATTR_ACTIONS] &&
struct nlattr **a = info->attrs;
struct ovs_header *ovs_header = info->userhdr;
struct sw_flow_key key;
- struct tbl_node *flow_node;
struct sk_buff *reply;
struct sw_flow *flow;
struct datapath *dp;
- struct tbl *table;
+ struct flow_table *table;
int err;
int key_len;
return -ENODEV;
table = get_table_protected(dp);
- flow_node = tbl_lookup(table, &key, key_len, flow_hash(&key, key_len),
- flow_cmp);
- if (!flow_node)
+ flow = flow_tbl_lookup(table, &key, key_len);
+ if (!flow)
return -ENOENT;
- flow = flow_cast(flow_node);
reply = ovs_flow_cmd_build_info(flow, dp, info->snd_pid, info->snd_seq, OVS_FLOW_CMD_NEW);
if (IS_ERR(reply))
return PTR_ERR(reply);
struct nlattr **a = info->attrs;
struct ovs_header *ovs_header = info->userhdr;
struct sw_flow_key key;
- struct tbl_node *flow_node;
struct sk_buff *reply;
struct sw_flow *flow;
struct datapath *dp;
- struct tbl *table;
+ struct flow_table *table;
int err;
int key_len;
return -ENODEV;
table = get_table_protected(dp);
- flow_node = tbl_lookup(table, &key, key_len, flow_hash(&key, key_len),
- flow_cmp);
- if (!flow_node)
+ flow = flow_tbl_lookup(table, &key, key_len);
+ if (!flow)
return -ENOENT;
- flow = flow_cast(flow_node);
reply = ovs_flow_cmd_alloc_info(flow);
if (!reply)
return -ENOMEM;
- err = tbl_remove(table, flow_node);
- if (err) {
- kfree_skb(reply);
- return err;
- }
+ flow_tbl_remove(table, flow);
err = ovs_flow_cmd_fill_info(flow, dp, reply, info->snd_pid,
info->snd_seq, 0, OVS_FLOW_CMD_DEL);
return -ENODEV;
for (;;) {
- struct tbl_node *flow_node;
struct sw_flow *flow;
u32 bucket, obj;
bucket = cb->args[0];
obj = cb->args[1];
- flow_node = tbl_next(get_table_protected(dp), &bucket, &obj);
- if (!flow_node)
+ flow = flow_tbl_next(get_table_protected(dp), &bucket, &obj);
+ if (!flow)
break;
- flow = flow_cast(flow_node);
if (ovs_flow_cmd_fill_info(flow, dp, skb, NETLINK_CB(cb->skb).pid,
cb->nlh->nlmsg_seq, NLM_F_MULTI,
OVS_FLOW_CMD_NEW) < 0)
/* Allocate table. */
err = -ENOMEM;
- rcu_assign_pointer(dp->table, tbl_create(TBL_MIN_BUCKETS));
+ rcu_assign_pointer(dp->table, flow_tbl_alloc(TBL_MIN_BUCKETS));
if (!dp->table)
goto err_free_dp;
err_destroy_local_port:
dp_detach_port(get_vport_protected(dp, OVSP_LOCAL));
err_destroy_table:
- tbl_destroy(get_table_protected(dp), NULL);
+ flow_tbl_destroy(get_table_protected(dp));
err_free_dp:
kfree(dp);
err_put_module:
[OVS_VPORT_ATTR_NAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ - 1 },
[OVS_VPORT_ATTR_PORT_NO] = { .type = NLA_U32 },
[OVS_VPORT_ATTR_TYPE] = { .type = NLA_U32 },
- [OVS_VPORT_ATTR_STATS] = { .len = sizeof(struct rtnl_link_stats64) },
+ [OVS_VPORT_ATTR_STATS] = { .len = sizeof(struct ovs_vport_stats) },
[OVS_VPORT_ATTR_ADDRESS] = { .len = ETH_ALEN },
#else
- [OVS_VPORT_ATTR_STATS] = { .minlen = sizeof(struct rtnl_link_stats64) },
+ [OVS_VPORT_ATTR_STATS] = { .minlen = sizeof(struct ovs_vport_stats) },
[OVS_VPORT_ATTR_ADDRESS] = { .minlen = ETH_ALEN },
#endif
- [OVS_VPORT_ATTR_MTU] = { .type = NLA_U32 },
[OVS_VPORT_ATTR_OPTIONS] = { .type = NLA_NESTED },
};
struct ovs_header *ovs_header;
struct nlattr *nla;
int ifindex;
- int mtu;
int err;
ovs_header = genlmsg_put(skb, pid, seq, &dp_vport_genl_family,
NLA_PUT_U32(skb, OVS_VPORT_ATTR_TYPE, vport_get_type(vport));
NLA_PUT_STRING(skb, OVS_VPORT_ATTR_NAME, vport_get_name(vport));
- nla = nla_reserve(skb, OVS_VPORT_ATTR_STATS, sizeof(struct rtnl_link_stats64));
+ nla = nla_reserve(skb, OVS_VPORT_ATTR_STATS, sizeof(struct ovs_vport_stats));
if (!nla)
goto nla_put_failure;
- if (vport_get_stats(vport, nla_data(nla)))
- __skb_trim(skb, skb->len - nla->nla_len);
- NLA_PUT(skb, OVS_VPORT_ATTR_ADDRESS, ETH_ALEN, vport_get_addr(vport));
+ vport_get_stats(vport, nla_data(nla));
- mtu = vport_get_mtu(vport);
- if (mtu)
- NLA_PUT_U32(skb, OVS_VPORT_ATTR_MTU, mtu);
+ NLA_PUT(skb, OVS_VPORT_ATTR_ADDRESS, ETH_ALEN, vport_get_addr(vport));
err = vport_get_options(vport, skb);
if (err == -EMSGSIZE)
static int change_vport(struct vport *vport, struct nlattr *a[OVS_VPORT_ATTR_MAX + 1])
{
int err = 0;
+
if (a[OVS_VPORT_ATTR_STATS])
- err = vport_set_stats(vport, nla_data(a[OVS_VPORT_ATTR_STATS]));
- if (!err && a[OVS_VPORT_ATTR_ADDRESS])
+ vport_set_stats(vport, nla_data(a[OVS_VPORT_ATTR_STATS]));
+
+ if (a[OVS_VPORT_ATTR_ADDRESS])
err = vport_set_addr(vport, nla_data(a[OVS_VPORT_ATTR_ADDRESS]));
- if (!err && a[OVS_VPORT_ATTR_MTU])
- err = vport_set_mtu(vport, nla_get_u32(a[OVS_VPORT_ATTR_MTU]));
+
return err;
}
if (IS_ERR(vport))
goto exit_unlock;
- set_internal_devs_mtu(dp);
dp_sysfs_add_if(vport);
err = change_vport(vport, a);
if (IS_ERR(reply))
goto exit_unlock;
- err = dp_detach_port(vport);
+ dp_detach_port(vport);
genl_notify(reply, genl_info_net(info), info->snd_pid,
dp_vport_multicast_group.id, info->nlhdr, GFP_KERNEL);
printk("Open vSwitch %s, built "__DATE__" "__TIME__"\n", VERSION BUILDNR);
- err = flow_init();
+ err = tnl_init();
if (err)
goto error;
+ err = flow_init();
+ if (err)
+ goto error_tnl_exit;
+
err = vport_init();
if (err)
goto error_flow_exit;
vport_exit();
error_flow_exit:
flow_exit();
+error_tnl_exit:
+ tnl_exit();
error:
return err;
}
unregister_netdevice_notifier(&dp_device_notifier);
vport_exit();
flow_exit();
+ tnl_exit();
}
module_init(dp_init);