meta-flow: Correctly set destination MAC in mf_set_flow_value().
[sliver-openvswitch.git] / datapath / datapath.c
index c86c20b..8c4ade9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007-2011 Nicira Networks.
+ * Copyright (c) 2007-2012 Nicira Networks.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of version 2 of the GNU General Public
 #include "checksum.h"
 #include "datapath.h"
 #include "flow.h"
+#include "genl_exec.h"
 #include "vlan.h"
 #include "tunnel.h"
 #include "vport-internal_dev.h"
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) || \
-    LINUX_VERSION_CODE > KERNEL_VERSION(3,2,0)
+    LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0)
 #error Kernels before 2.6.18 or after 3.2 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_dp_ioctl_hook)(struct net_device *dev, struct ifreq *rq, int cmd);
 EXPORT_SYMBOL(ovs_dp_ioctl_hook);
 
@@ -1545,9 +1550,8 @@ static int ovs_dp_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
        int i = 0;
 
        list_for_each_entry(dp, &dps, list_node) {
-               if (i < skip)
-                       continue;
-               if (ovs_dp_cmd_fill_info(dp, skb, NETLINK_CB(cb->skb).pid,
+               if (i >= skip &&
+                   ovs_dp_cmd_fill_info(dp, skb, NETLINK_CB(cb->skb).pid,
                                         cb->nlh->nlmsg_seq, NLM_F_MULTI,
                                         OVS_DP_CMD_NEW) < 0)
                        break;
@@ -1685,6 +1689,9 @@ static struct vport *lookup_vport(struct ovs_header *ovs_header,
                vport = ovs_vport_locate(nla_data(a[OVS_VPORT_ATTR_NAME]));
                if (!vport)
                        return ERR_PTR(-ENODEV);
+               if (ovs_header->dp_ifindex &&
+                   ovs_header->dp_ifindex != get_dpifindex(vport->dp))
+                       return ERR_PTR(-ENODEV);
                return vport;
        } else if (a[OVS_VPORT_ATTR_PORT_NO]) {
                u32 port_no = nla_get_u32(a[OVS_VPORT_ATTR_PORT_NO]);
@@ -1829,6 +1836,8 @@ static int ovs_vport_cmd_set(struct sk_buff *skb, struct genl_info *info)
                err = ovs_vport_set_options(vport, a[OVS_VPORT_ATTR_OPTIONS]);
        if (!err)
                err = change_vport(vport, a);
+       else
+               goto exit_unlock;
        if (!err && a[OVS_VPORT_ATTR_UPCALL_PID])
                vport->upcall_pid = nla_get_u32(a[OVS_VPORT_ATTR_UPCALL_PID]);
 
@@ -2039,6 +2048,29 @@ error:
        return err;
 }
 
+static int __rehash_flow_table(void *dummy)
+{
+       struct datapath *dp;
+
+       list_for_each_entry(dp, &dps, list_node) {
+               struct flow_table *old_table = genl_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_deferred_destroy(old_table);
+               }
+       }
+       return 0;
+}
+
+static void rehash_flow_table(struct work_struct *work)
+{
+       genl_exec(__rehash_flow_table, NULL);
+       schedule_delayed_work(&rehash_flow_wq, REHASH_FLOW_INTERVAL);
+}
+
 static int __init dp_init(void)
 {
        struct sk_buff *dummy_skb;
@@ -2049,10 +2081,18 @@ static int __init dp_init(void)
        pr_info("Open vSwitch switching datapath %s, built "__DATE__" "__TIME__"\n",
                VERSION BUILDNR);
 
-       err = ovs_tnl_init();
+       err = genl_exec_init();
        if (err)
                goto error;
 
+       err = ovs_workqueues_init();
+       if (err)
+               goto error_genl_exec;
+
+       err = ovs_tnl_init();
+       if (err)
+               goto error_wq;
+
        err = ovs_flow_init();
        if (err)
                goto error_tnl_exit;
@@ -2069,6 +2109,8 @@ 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:
@@ -2079,18 +2121,25 @@ error_flow_exit:
        ovs_flow_exit();
 error_tnl_exit:
        ovs_tnl_exit();
+error_wq:
+       ovs_workqueues_exit();
+error_genl_exec:
+       genl_exec_exit();
 error:
        return err;
 }
 
 static void dp_cleanup(void)
 {
+       cancel_delayed_work_sync(&rehash_flow_wq);
        rcu_barrier();
        dp_unregister_genl(ARRAY_SIZE(dp_genl_families));
        unregister_netdevice_notifier(&ovs_dp_device_notifier);
        ovs_vport_exit();
        ovs_flow_exit();
        ovs_tnl_exit();
+       ovs_workqueues_exit();
+       genl_exec_exit();
 }
 
 module_init(dp_init);