#include "vport-netdev.h"
#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;
.name = OVS_PACKET_FAMILY,
.version = OVS_PACKET_VERSION,
.maxattr = OVS_PACKET_ATTR_MAX,
- SET_NETNSOK
+ .netnsok = true,
SET_PARALLEL_OPS
};
}
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 },
};
.name = OVS_FLOW_FAMILY,
.version = OVS_FLOW_VERSION,
.maxattr = OVS_FLOW_ATTR_MAX,
- SET_NETNSOK
+ .netnsok = true,
SET_PARALLEL_OPS
};
/* 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. */
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;
};
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 },
};
.name = OVS_DATAPATH_FAMILY,
.version = OVS_DATAPATH_VERSION,
.maxattr = OVS_DP_ATTR_MAX,
- SET_NETNSOK
+ .netnsok = true,
SET_PARALLEL_OPS
};
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,
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;
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);
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);
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;
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)) {
};
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 },
.name = OVS_VPORT_FAMILY,
.version = OVS_VPORT_VERSION,
.maxattr = OVS_VPORT_ATTR_MAX,
- SET_NETNSOK
+ .netnsok = true,
SET_PARALLEL_OPS
};
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,
!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;
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);
kfree_skb(reply);
exit_unlock:
ovs_unlock();
-exit:
return err;
}
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);
exit_unlock:
ovs_unlock();
-exit:
return err;
}
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);
exit_unlock:
rcu_read_unlock();
-exit:
return err;
}
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);
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)
if (err < 0)
goto error_unreg_notifier;
- schedule_delayed_work(&rehash_flow_wq, REHASH_FLOW_INTERVAL);
-
return 0;
error_unreg_notifier:
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);