datapath: Always use generic stats for devices (vports)
[sliver-openvswitch.git] / datapath / datapath.c
index 7499081..98c2baf 100644 (file)
@@ -49,8 +49,8 @@
 #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) || \
@@ -107,7 +107,7 @@ struct datapath *get_dp(int dp_ifindex)
 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());
 }
@@ -131,7 +131,6 @@ static inline size_t br_nlmsg_size(void)
               + 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 */
 }
 
@@ -218,7 +217,7 @@ static void destroy_dp_rcu(struct rcu_head *rcu)
 {
        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);
 }
@@ -242,7 +241,7 @@ static struct vport *new_vport(const struct vport_parms *parms)
 }
 
 /* Called with RTNL lock. */
-int dp_detach_port(struct vport *p)
+void dp_detach_port(struct vport *p)
 {
        ASSERT_RTNL();
 
@@ -255,13 +254,14 @@ int dp_detach_port(struct vport *p)
        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;
@@ -270,7 +270,6 @@ void dp_process_received_packet(struct vport *p, struct sk_buff *skb)
 
        if (!OVS_CB(skb)->flow) {
                struct sw_flow_key key;
-               struct tbl_node *flow_node;
                int key_len;
                bool is_frag;
 
@@ -288,9 +287,8 @@ void dp_process_received_packet(struct vport *p, struct sk_buff *skb)
                }
 
                /* 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;
@@ -304,7 +302,7 @@ void dp_process_received_packet(struct vport *p, struct sk_buff *skb)
                        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);
@@ -517,8 +515,8 @@ err_kfree_skbs:
 /* 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);
@@ -526,14 +524,13 @@ static int flush_flows(int 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;
 }
 
@@ -546,8 +543,8 @@ static int validate_actions(const struct nlattr *attr)
                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,
@@ -569,7 +566,7 @@ static int validate_actions(const struct nlattr *attr)
                        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:
@@ -587,7 +584,7 @@ static int validate_actions(const struct nlattr *attr)
                                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;
@@ -615,24 +612,6 @@ static void clear_stats(struct sw_flow *flow)
        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;
@@ -686,7 +665,6 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
        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,
@@ -694,6 +672,8 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
        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))
@@ -707,6 +687,11 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
        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();
 
@@ -740,9 +725,9 @@ static struct genl_ops dp_packet_genl_ops[] = {
 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) {
@@ -764,52 +749,6 @@ static void get_dp_stats(struct datapath *dp, struct ovs_dp_stats *stats)
        }
 }
 
-/* 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 },
@@ -933,13 +872,11 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
 {
        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;
 
@@ -966,10 +903,9 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
        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. */
@@ -978,11 +914,15 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
                        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. */
@@ -1002,9 +942,8 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
                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);
@@ -1024,7 +963,6 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
                        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] &&
@@ -1072,11 +1010,10 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info)
        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;
 
@@ -1091,12 +1028,10 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info)
                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);
@@ -1109,11 +1044,10 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info)
        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;
 
@@ -1128,21 +1062,15 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info)
                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);
@@ -1165,17 +1093,15 @@ static int ovs_flow_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
                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)
@@ -1370,7 +1296,7 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
 
        /* 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;
 
@@ -1416,7 +1342,7 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
 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:
@@ -1578,13 +1504,12 @@ static const struct nla_policy vport_policy[OVS_VPORT_ATTR_MAX + 1] = {
        [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 },
 };
 
@@ -1607,7 +1532,6 @@ static int ovs_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb,
        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,
@@ -1621,17 +1545,13 @@ static int ovs_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb,
        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)
@@ -1708,12 +1628,13 @@ static struct vport *lookup_vport(struct ovs_header *ovs_header,
 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;
 }
 
@@ -1776,7 +1697,6 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info)
        if (IS_ERR(vport))
                goto exit_unlock;
 
-       set_internal_devs_mtu(dp);
        dp_sysfs_add_if(vport);
 
        err = change_vport(vport, a);
@@ -1869,7 +1789,7 @@ static int ovs_vport_cmd_del(struct sk_buff *skb, struct genl_info *info)
        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);
@@ -2042,10 +1962,14 @@ static int __init dp_init(void)
 
        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;
@@ -2066,6 +1990,8 @@ error_vport_exit:
        vport_exit();
 error_flow_exit:
        flow_exit();
+error_tnl_exit:
+       tnl_exit();
 error:
        return err;
 }
@@ -2077,6 +2003,7 @@ static void dp_cleanup(void)
        unregister_netdevice_notifier(&dp_device_notifier);
        vport_exit();
        flow_exit();
+       tnl_exit();
 }
 
 module_init(dp_init);