datapath: Remove compat workqueue.
[sliver-openvswitch.git] / datapath / datapath.c
index e5e0616..4defcdb 100644 (file)
 #include <net/net_namespace.h>
 #include <net/netns/generic.h>
 
-#include "checksum.h"
 #include "datapath.h"
 #include "flow.h"
 #include "vlan.h"
-#include "tunnel.h"
 #include "vport-internal_dev.h"
 #include "vport-netdev.h"
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) || \
-    LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
-#error Kernels before 2.6.18 or after 3.9 are not supported by this version of Open vSwitch.
-#endif
-
 #define REHASH_FLOW_INTERVAL (10 * 60 * HZ)
-static void rehash_flow_table(struct work_struct *work);
-static DECLARE_DELAYED_WORK(rehash_flow_wq, rehash_flow_table);
 
 int ovs_net_id __read_mostly;
 
@@ -279,7 +270,8 @@ static struct genl_family dp_packet_genl_family = {
        .name = OVS_PACKET_FAMILY,
        .version = OVS_PACKET_VERSION,
        .maxattr = OVS_PACKET_ATTR_MAX,
-        SET_NETNSOK
+       .netnsok = true,
+        SET_PARALLEL_OPS
 };
 
 int ovs_dp_upcall(struct datapath *dp, struct sk_buff *skb,
@@ -300,8 +292,6 @@ int ovs_dp_upcall(struct datapath *dp, struct sk_buff *skb,
                goto err;
        }
 
-       forward_ip_summed(skb, true);
-
        if (!skb_is_gso(skb))
                err = queue_userspace_packet(ovs_dp_get_net(dp), dp_ifindex, skb, upcall_info);
        else
@@ -419,10 +409,12 @@ static int queue_userspace_packet(struct net *net, int dp_ifindex,
                nskb = skb_clone(skb, GFP_ATOMIC);
                if (!nskb)
                        return -ENOMEM;
-               
-               err = vlan_deaccel_tag(nskb);
-               if (err)
-                       return err;
+
+               nskb = __vlan_put_tag(nskb, nskb->vlan_proto, vlan_tx_tag_get(nskb));
+               if (!nskb)
+                       return -ENOMEM;
+
+               vlan_set_tci(nskb, 0);
 
                skb = nskb;
        }
@@ -624,7 +616,7 @@ static int validate_and_copy_set_tun(const struct nlattr *attr,
        int err, start;
 
        ovs_match_init(&match, &key, NULL);
-       err = ipv4_tun_from_nlattr(nla_data(attr), &match, false);
+       err = ovs_ipv4_tun_from_nlattr(nla_data(attr), &match, false);
        if (err)
                return err;
 
@@ -662,14 +654,8 @@ static int validate_set(const struct nlattr *a,
        int err;
 
        case OVS_KEY_ATTR_PRIORITY:
-       case OVS_KEY_ATTR_ETHERNET:
-               break;
-
        case OVS_KEY_ATTR_SKB_MARK:
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) && !defined(CONFIG_NETFILTER)
-               if (nla_get_u32(ovs_key) != 0)
-                       return -EINVAL;
-#endif
+       case OVS_KEY_ATTR_ETHERNET:
                break;
 
        case OVS_KEY_ATTR_TUNNEL:
@@ -726,6 +712,12 @@ static int validate_set(const struct nlattr *a,
 
                return validate_tp_port(flow_key);
 
+       case OVS_KEY_ATTR_SCTP:
+               if (flow_key->ip.proto != IPPROTO_SCTP)
+                       return -EINVAL;
+
+               return validate_tp_port(flow_key);
+
        default:
                return -EINVAL;
        }
@@ -926,7 +918,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
        OVS_CB(packet)->flow = flow;
        OVS_CB(packet)->pkt_key = &flow->key;
        packet->priority = flow->key.phy.priority;
-       skb_set_mark(packet, flow->key.phy.skb_mark);
+       packet->mark = flow->key.phy.skb_mark;
 
        rcu_read_lock();
        dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
@@ -953,11 +945,7 @@ err:
 }
 
 static const struct nla_policy packet_policy[OVS_PACKET_ATTR_MAX + 1] = {
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)
        [OVS_PACKET_ATTR_PACKET] = { .len = ETH_HLEN },
-#else
-       [OVS_PACKET_ATTR_PACKET] = { .minlen = ETH_HLEN },
-#endif
        [OVS_PACKET_ATTR_KEY] = { .type = NLA_NESTED },
        [OVS_PACKET_ATTR_ACTIONS] = { .type = NLA_NESTED },
 };
@@ -1009,7 +997,8 @@ static struct genl_family dp_flow_genl_family = {
        .name = OVS_FLOW_FAMILY,
        .version = OVS_FLOW_VERSION,
        .maxattr = OVS_FLOW_ATTR_MAX,
-        SET_NETNSOK
+       .netnsok = true,
+        SET_PARALLEL_OPS
 };
 
 static struct genl_multicast_group ovs_dp_flow_multicast_group = {
@@ -1065,8 +1054,8 @@ static int set_action_to_attr(const struct nlattr *a, struct sk_buff *skb)
                if (!start)
                        return -EMSGSIZE;
 
-               err = ipv4_tun_to_nlattr(skb,
-                               nla_data(ovs_key), nla_data(ovs_key));
+               err = ovs_ipv4_tun_to_nlattr(skb, nla_data(ovs_key),
+                                            nla_data(ovs_key));
                if (err)
                        return err;
                nla_nest_end(skb, start);
@@ -1300,22 +1289,25 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
        /* Check if this is a duplicate flow */
        flow = ovs_flow_lookup(table, &key);
        if (!flow) {
+               struct flow_table *new_table = NULL;
                struct sw_flow_mask *mask_p;
+
                /* Bail out if we're not allowed to create a new flow. */
                error = -ENOENT;
                if (info->genlhdr->cmd == OVS_FLOW_CMD_SET)
                        goto err_unlock_ovs;
 
                /* Expand table, if necessary, to make room. */
-               if (ovs_flow_tbl_need_to_expand(table)) {
-                       struct flow_table *new_table;
-
+               if (ovs_flow_tbl_need_to_expand(table))
                        new_table = ovs_flow_tbl_expand(table);
-                       if (!IS_ERR(new_table)) {
-                               rcu_assign_pointer(dp->table, new_table);
-                               ovs_flow_tbl_destroy(table, true);
-                               table = ovsl_dereference(dp->table);
-                       }
+               else if (time_after(jiffies, dp->last_rehash + REHASH_FLOW_INTERVAL))
+                       new_table = ovs_flow_tbl_rehash(table);
+
+               if (new_table && !IS_ERR(new_table)) {
+                       rcu_assign_pointer(dp->table, new_table);
+                       ovs_flow_tbl_destroy(table, true);
+                       table = ovsl_dereference(dp->table);
+                       dp->last_rehash = jiffies;
                }
 
                /* Allocate flow. */
@@ -1392,7 +1384,7 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
        if (!IS_ERR(reply))
                ovs_notify(reply, info, &ovs_dp_flow_multicast_group);
        else
-               netlink_set_err(GENL_SOCK(sock_net(skb->sk)), 0,
+               netlink_set_err(sock_net(skb->sk)->genl_sock, 0,
                                ovs_dp_flow_multicast_group.id, PTR_ERR(reply));
        return 0;
 
@@ -1576,9 +1568,7 @@ static struct genl_ops dp_flow_genl_ops[] = {
 };
 
 static const struct nla_policy datapath_policy[OVS_DP_ATTR_MAX + 1] = {
-#ifdef HAVE_NLA_NUL_STRING
        [OVS_DP_ATTR_NAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ - 1 },
-#endif
        [OVS_DP_ATTR_UPCALL_PID] = { .type = NLA_U32 },
 };
 
@@ -1588,7 +1578,8 @@ static struct genl_family dp_datapath_genl_family = {
        .name = OVS_DATAPATH_FAMILY,
        .version = OVS_DATAPATH_VERSION,
        .maxattr = OVS_DP_ATTR_MAX,
-        SET_NETNSOK
+       .netnsok = true,
+        SET_PARALLEL_OPS
 };
 
 static struct genl_multicast_group ovs_dp_datapath_multicast_group = {
@@ -1655,11 +1646,6 @@ static struct sk_buff *ovs_dp_cmd_build_info(struct datapath *dp, u32 portid,
        return skb;
 }
 
-static int ovs_dp_cmd_validate(struct nlattr *a[OVS_DP_ATTR_MAX + 1])
-{
-       return CHECK_NUL_STRING(a[OVS_DP_ATTR_NAME], IFNAMSIZ - 1);
-}
-
 /* Called with ovs_mutex. */
 static struct datapath *lookup_datapath(struct net *net,
                                        struct ovs_header *ovs_header,
@@ -1694,10 +1680,6 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
        if (!a[OVS_DP_ATTR_NAME] || !a[OVS_DP_ATTR_UPCALL_PID])
                goto err;
 
-       err = ovs_dp_cmd_validate(a);
-       if (err)
-               goto err;
-
        ovs_lock();
 
        err = -ENOMEM;
@@ -1807,10 +1789,6 @@ static int ovs_dp_cmd_del(struct sk_buff *skb, struct genl_info *info)
        struct datapath *dp;
        int err;
 
-       err = ovs_dp_cmd_validate(info->attrs);
-       if (err)
-               return err;
-
        ovs_lock();
        dp = lookup_datapath(sock_net(skb->sk), info->userhdr, info->attrs);
        err = PTR_ERR(dp);
@@ -1840,10 +1818,6 @@ static int ovs_dp_cmd_set(struct sk_buff *skb, struct genl_info *info)
        struct datapath *dp;
        int err;
 
-       err = ovs_dp_cmd_validate(info->attrs);
-       if (err)
-               return err;
-
        ovs_lock();
        dp = lookup_datapath(sock_net(skb->sk), info->userhdr, info->attrs);
        err = PTR_ERR(dp);
@@ -1854,7 +1828,7 @@ static int ovs_dp_cmd_set(struct sk_buff *skb, struct genl_info *info)
                                      info->snd_seq, OVS_DP_CMD_NEW);
        if (IS_ERR(reply)) {
                err = PTR_ERR(reply);
-               netlink_set_err(GENL_SOCK(sock_net(skb->sk)), 0,
+               netlink_set_err(sock_net(skb->sk)->genl_sock, 0,
                                ovs_dp_datapath_multicast_group.id, err);
                err = 0;
                goto unlock;
@@ -1875,10 +1849,6 @@ static int ovs_dp_cmd_get(struct sk_buff *skb, struct genl_info *info)
        struct datapath *dp;
        int err;
 
-       err = ovs_dp_cmd_validate(info->attrs);
-       if (err)
-               return err;
-
        ovs_lock();
        dp = lookup_datapath(sock_net(skb->sk), info->userhdr, info->attrs);
        if (IS_ERR(dp)) {
@@ -1949,12 +1919,8 @@ static struct genl_ops dp_datapath_genl_ops[] = {
 };
 
 static const struct nla_policy vport_policy[OVS_VPORT_ATTR_MAX + 1] = {
-#ifdef HAVE_NLA_NUL_STRING
        [OVS_VPORT_ATTR_NAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ - 1 },
        [OVS_VPORT_ATTR_STATS] = { .len = sizeof(struct ovs_vport_stats) },
-#else
-       [OVS_VPORT_ATTR_STATS] = { .minlen = sizeof(struct ovs_vport_stats) },
-#endif
        [OVS_VPORT_ATTR_PORT_NO] = { .type = NLA_U32 },
        [OVS_VPORT_ATTR_TYPE] = { .type = NLA_U32 },
        [OVS_VPORT_ATTR_UPCALL_PID] = { .type = NLA_U32 },
@@ -1967,7 +1933,8 @@ static struct genl_family dp_vport_genl_family = {
        .name = OVS_VPORT_FAMILY,
        .version = OVS_VPORT_VERSION,
        .maxattr = OVS_VPORT_ATTR_MAX,
-        SET_NETNSOK
+       .netnsok = true,
+        SET_PARALLEL_OPS
 };
 
 struct genl_multicast_group ovs_dp_vport_multicast_group = {
@@ -2030,11 +1997,6 @@ struct sk_buff *ovs_vport_cmd_build_info(struct vport *vport, u32 portid,
        return skb;
 }
 
-static int ovs_vport_cmd_validate(struct nlattr *a[OVS_VPORT_ATTR_MAX + 1])
-{
-       return CHECK_NUL_STRING(a[OVS_VPORT_ATTR_NAME], IFNAMSIZ - 1);
-}
-
 /* Called with ovs_mutex or RCU read lock. */
 static struct vport *lookup_vport(struct net *net,
                                  struct ovs_header *ovs_header,
@@ -2085,10 +2047,6 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info)
            !a[OVS_VPORT_ATTR_UPCALL_PID])
                goto exit;
 
-       err = ovs_vport_cmd_validate(a);
-       if (err)
-               goto exit;
-
        ovs_lock();
        dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
        err = -ENODEV;
@@ -2157,10 +2115,6 @@ static int ovs_vport_cmd_set(struct sk_buff *skb, struct genl_info *info)
        struct vport *vport;
        int err;
 
-       err = ovs_vport_cmd_validate(a);
-       if (err)
-               goto exit;
-
        ovs_lock();
        vport = lookup_vport(sock_net(skb->sk), info->userhdr, a);
        err = PTR_ERR(vport);
@@ -2203,7 +2157,6 @@ exit_free:
        kfree_skb(reply);
 exit_unlock:
        ovs_unlock();
-exit:
        return err;
 }
 
@@ -2214,10 +2167,6 @@ static int ovs_vport_cmd_del(struct sk_buff *skb, struct genl_info *info)
        struct vport *vport;
        int err;
 
-       err = ovs_vport_cmd_validate(a);
-       if (err)
-               goto exit;
-
        ovs_lock();
        vport = lookup_vport(sock_net(skb->sk), info->userhdr, a);
        err = PTR_ERR(vport);
@@ -2242,7 +2191,6 @@ static int ovs_vport_cmd_del(struct sk_buff *skb, struct genl_info *info)
 
 exit_unlock:
        ovs_unlock();
-exit:
        return err;
 }
 
@@ -2254,10 +2202,6 @@ static int ovs_vport_cmd_get(struct sk_buff *skb, struct genl_info *info)
        struct vport *vport;
        int err;
 
-       err = ovs_vport_cmd_validate(a);
-       if (err)
-               goto exit;
-
        rcu_read_lock();
        vport = lookup_vport(sock_net(skb->sk), ovs_header, a);
        err = PTR_ERR(vport);
@@ -2276,7 +2220,6 @@ static int ovs_vport_cmd_get(struct sk_buff *skb, struct genl_info *info)
 
 exit_unlock:
        rcu_read_unlock();
-exit:
        return err;
 }
 
@@ -2402,32 +2345,6 @@ error:
        return err;
 }
 
-static void rehash_flow_table(struct work_struct *work)
-{
-       struct datapath *dp;
-       struct net *net;
-
-       ovs_lock();
-       rtnl_lock();
-       for_each_net(net) {
-               struct ovs_net *ovs_net = net_generic(net, ovs_net_id);
-
-               list_for_each_entry(dp, &ovs_net->dps, list_node) {
-                       struct flow_table *old_table = ovsl_dereference(dp->table);
-                       struct flow_table *new_table;
-
-                       new_table = ovs_flow_tbl_rehash(old_table);
-                       if (!IS_ERR(new_table)) {
-                               rcu_assign_pointer(dp->table, new_table);
-                               ovs_flow_tbl_destroy(old_table, true);
-                       }
-               }
-       }
-       rtnl_unlock();
-       ovs_unlock();
-       schedule_delayed_work(&rehash_flow_wq, REHASH_FLOW_INTERVAL);
-}
-
 static int __net_init ovs_init_net(struct net *net)
 {
        struct ovs_net *ovs_net = net_generic(net, ovs_net_id);
@@ -2468,13 +2385,9 @@ static int __init dp_init(void)
        pr_info("Open vSwitch switching datapath %s, built "__DATE__" "__TIME__"\n",
                VERSION);
 
-       err = ovs_workqueues_init();
-       if (err)
-               goto error;
-
        err = ovs_flow_init();
        if (err)
-               goto error_wq;
+               goto error;
 
        err = ovs_vport_init();
        if (err)
@@ -2492,8 +2405,6 @@ static int __init dp_init(void)
        if (err < 0)
                goto error_unreg_notifier;
 
-       schedule_delayed_work(&rehash_flow_wq, REHASH_FLOW_INTERVAL);
-
        return 0;
 
 error_unreg_notifier:
@@ -2504,22 +2415,18 @@ error_vport_exit:
        ovs_vport_exit();
 error_flow_exit:
        ovs_flow_exit();
-error_wq:
-       ovs_workqueues_exit();
 error:
        return err;
 }
 
 static void dp_cleanup(void)
 {
-       cancel_delayed_work_sync(&rehash_flow_wq);
        dp_unregister_genl(ARRAY_SIZE(dp_genl_families));
        unregister_netdevice_notifier(&ovs_dp_device_notifier);
        unregister_pernet_device(&ovs_net_ops);
        rcu_barrier();
        ovs_vport_exit();
        ovs_flow_exit();
-       ovs_workqueues_exit();
 }
 
 module_init(dp_init);