/*
- * 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);
break;
if (skb == segs && skb_shinfo(skb)->gso_type & SKB_GSO_UDP) {
- /* The initial flow key extracted by flow_extract() in
- * this case is for a first fragment, so we need to
+ /* The initial flow key extracted by ovs_flow_extract()
+ * in this case is for a first fragment, so we need to
* properly mark later fragments.
*/
later_key = *upcall_info->key;
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;
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]);
genl_notify(reply, genl_info_net(info), info->snd_pid,
ovs_dp_vport_multicast_group.id, info->nlhdr, GFP_KERNEL);
-
exit_unlock:
rtnl_unlock();
exit:
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;
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;
if (err < 0)
goto error_unreg_notifier;
+ schedule_delayed_work(&rehash_flow_wq, REHASH_FLOW_INTERVAL);
+
return 0;
error_unreg_notifier:
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);