Use flex array to increase maximum number of vports. Now maximum number of vports are limited by flex-array limit (261K for 64-bit) per bridge.
Signed-off-by: Pravin B Shelar <[email protected]> Bug #2462 --- datapath/actions.c | 2 +- datapath/datapath.c | 44 ++++++++++++++++++++++++++++++++------------ datapath/datapath.h | 24 ++++++++++++++++++++++-- datapath/dp_sysfs_dp.c | 4 ++-- datapath/dp_sysfs_if.c | 2 +- 5 files changed, 58 insertions(+), 18 deletions(-) diff --git a/datapath/actions.c b/datapath/actions.c index 824791d..cc238c4 100644 --- a/datapath/actions.c +++ b/datapath/actions.c @@ -248,7 +248,7 @@ static int do_output(struct datapath *dp, struct sk_buff *skb, int out_port) if (unlikely(!skb)) return -ENOMEM; - vport = rcu_dereference(dp->ports[out_port]); + vport = ovs_vport(dp, out_port); if (unlikely(!vport)) { kfree_skb(skb); return -ENODEV; diff --git a/datapath/datapath.c b/datapath/datapath.c index 220c7dd..dcb034a 100644 --- a/datapath/datapath.c +++ b/datapath/datapath.c @@ -120,7 +120,7 @@ static struct datapath *get_dp(struct net *net, int dp_ifindex) /* Must be called with rcu_read_lock or RTNL lock. */ const char *ovs_dp_name(const struct datapath *dp) { - struct vport *vport = rcu_dereference_rtnl(dp->ports[OVSP_LOCAL]); + struct vport *vport = ovs_vport_check(dp, OVSP_LOCAL); return vport->ops->get_name(vport); } @@ -131,7 +131,7 @@ static int get_dpifindex(struct datapath *dp) rcu_read_lock(); - local = rcu_dereference(dp->ports[OVSP_LOCAL]); + local = ovs_vport(dp, OVSP_LOCAL); if (local) ifindex = local->ops->get_ifindex(local); else @@ -244,9 +244,15 @@ static void destroy_dp_rcu(struct rcu_head *rcu) ovs_flow_tbl_destroy((__force struct flow_table *)dp->table); free_percpu(dp->stats_percpu); release_net(ovs_dp_get_net(dp)); + flex_array_free_parts(&dp->ports); kobject_put(&dp->ifobj); } +static int dp_set_vport(struct datapath *dp, int port_no, struct vport *p) +{ + return flex_array_put(&dp->ports, port_no, &p, GFP_KERNEL|__GFP_ZERO); +} + /* Called with RTNL lock and genl_lock. */ static struct vport *new_vport(const struct vport_parms *parms) { @@ -255,13 +261,20 @@ static struct vport *new_vport(const struct vport_parms *parms) vport = ovs_vport_add(parms); if (!IS_ERR(vport)) { struct datapath *dp = parms->dp; + int err; - rcu_assign_pointer(dp->ports[parms->port_no], vport); + err = dp_set_vport(dp, parms->port_no, vport); + if (err) { + vport = ERR_PTR(err); + goto err; + } list_add(&vport->node, &dp->port_list); dp_ifinfo_notify(RTM_NEWLINK, vport); } - + return vport; +err: + ovs_vport_del(vport); return vport; } @@ -276,7 +289,7 @@ void ovs_dp_detach_port(struct vport *p) /* First drop references to device. */ list_del(&p->node); - rcu_assign_pointer(p->dp->ports[p->port_no], NULL); + dp_set_vport(p->dp, p->port_no, NULL); /* Then destroy it. */ ovs_vport_del(p); @@ -1391,6 +1404,11 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info) } ovs_dp_set_net(dp, hold_net(sock_net(skb->sk))); + err = flex_array_init(&dp->ports, sizeof(struct vport *), + DP_MAX_PORTS, GFP_KERNEL|__GFP_ZERO); + if (err) + goto err_destroy_percpu; + /* Set up our datapath device. */ parms.name = nla_data(a[OVS_DP_ATTR_NAME]); parms.type = OVS_VPORT_TYPE_INTERNAL; @@ -1405,7 +1423,7 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info) if (err == -EBUSY) err = -EEXIST; - goto err_destroy_percpu; + goto err_destroy_ports_array; } reply = ovs_dp_cmd_build_info(dp, info->snd_pid, @@ -1426,7 +1444,9 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info) return 0; err_destroy_local_port: - ovs_dp_detach_port(rtnl_dereference(dp->ports[OVSP_LOCAL])); + ovs_dp_detach_port(ovs_vport_protected(dp, OVSP_LOCAL)); +err_destroy_ports_array: + flex_array_free_parts(&dp->ports); err_destroy_percpu: free_percpu(dp->stats_percpu); err_destroy_table: @@ -1451,7 +1471,7 @@ static void __dp_destroy(struct datapath *dp) ovs_dp_sysfs_del_dp(dp); list_del(&dp->list_node); - ovs_dp_detach_port(rtnl_dereference(dp->ports[OVSP_LOCAL])); + ovs_dp_detach_port(ovs_vport_protected(dp, OVSP_LOCAL)); /* rtnl_unlock() will wait until all the references to devices that * are pending unregistration have been dropped. We do it here to @@ -1705,7 +1725,7 @@ static struct vport *lookup_vport(struct net *net, if (!dp) return ERR_PTR(-ENODEV); - vport = rcu_dereference_rtnl(dp->ports[port_no]); + vport = ovs_vport_check(dp, port_no); if (!vport) return ERR_PTR(-ENOENT); return vport; @@ -1761,7 +1781,7 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info) if (port_no >= DP_MAX_PORTS) goto exit_unlock; - vport = rtnl_dereference(dp->ports[port_no]); + vport = ovs_vport_protected(dp, port_no); err = -EBUSY; if (vport) goto exit_unlock; @@ -1771,7 +1791,7 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info) err = -EFBIG; goto exit_unlock; } - vport = rtnl_dereference(dp->ports[port_no]); + vport = ovs_vport_protected(dp, port_no); if (!vport) break; } @@ -1947,7 +1967,7 @@ static int ovs_vport_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb) for (port_no = cb->args[0]; port_no < DP_MAX_PORTS; port_no++) { struct vport *vport; - vport = rcu_dereference(dp->ports[port_no]); + vport = ovs_vport(dp, port_no); if (!vport) continue; diff --git a/datapath/datapath.h b/datapath/datapath.h index b012a76..05f6de8 100644 --- a/datapath/datapath.h +++ b/datapath/datapath.h @@ -34,7 +34,10 @@ #include "vlan.h" #include "vport.h" -#define DP_MAX_PORTS 1024 +/* Flex array limit. */ +#define DP_MAX_PORTS (FLEX_ARRAY_ELEMENTS_PER_PART(sizeof(struct vport *)) * \ + FLEX_ARRAY_NR_BASE_PTRS) + #define SAMPLE_ACTION_DEPTH 3 /** @@ -82,7 +85,7 @@ struct datapath { struct flow_table __rcu *table; /* Switch ports. */ - struct vport __rcu *ports[DP_MAX_PORTS]; + struct flex_array ports; struct list_head port_list; /* Stats. */ @@ -159,6 +162,23 @@ static inline void ovs_dp_set_net(struct datapath *dp, struct net *net) write_pnet(&dp->net, net); } +static inline struct vport *ovs_vport(const struct datapath *dp, int id) +{ + return flex_array_get_ptr(&dp->ports, id); +} + +static inline struct vport *ovs_vport_check(const struct datapath *dp, int id) +{ + WARN_ON(!rcu_read_lock_held() && !rtnl_is_locked()); + return ovs_vport(dp, id); +} + +static inline struct vport *ovs_vport_protected(const struct datapath *dp, int id) +{ + ASSERT_RTNL(); + return ovs_vport(dp, id); +} + extern struct notifier_block ovs_dp_device_notifier; extern struct genl_multicast_group ovs_dp_vport_multicast_group; extern int (*ovs_dp_ioctl_hook)(struct net_device *dev, struct ifreq *rq, int cmd); diff --git a/datapath/dp_sysfs_dp.c b/datapath/dp_sysfs_dp.c index 2582321..aba1945 100644 --- a/datapath/dp_sysfs_dp.c +++ b/datapath/dp_sysfs_dp.c @@ -362,7 +362,7 @@ static struct attribute_group bridge_group = { */ int ovs_dp_sysfs_add_dp(struct datapath *dp) { - struct vport *vport = rtnl_dereference(dp->ports[OVSP_LOCAL]); + struct vport *vport = ovs_vport_protected(dp, OVSP_LOCAL); struct kobject *kobj = vport->ops->get_kobj(vport); int err; @@ -398,7 +398,7 @@ int ovs_dp_sysfs_add_dp(struct datapath *dp) int ovs_dp_sysfs_del_dp(struct datapath *dp) { - struct vport *vport = rtnl_dereference(dp->ports[OVSP_LOCAL]); + struct vport *vport = ovs_vport_protected(dp, OVSP_LOCAL); struct kobject *kobj = vport->ops->get_kobj(vport); #ifdef CONFIG_NET_NS diff --git a/datapath/dp_sysfs_if.c b/datapath/dp_sysfs_if.c index f564e98..a6cf61e 100644 --- a/datapath/dp_sysfs_if.c +++ b/datapath/dp_sysfs_if.c @@ -209,7 +209,7 @@ struct sysfs_ops ovs_brport_sysfs_ops = { int ovs_dp_sysfs_add_if(struct vport *p) { struct datapath *dp = p->dp; - struct vport *local_port = rtnl_dereference(dp->ports[OVSP_LOCAL]); + struct vport *local_port = ovs_vport_protected(dp, OVSP_LOCAL); struct brport_attribute **a; int err; -- 1.7.1 _______________________________________________ dev mailing list [email protected] http://openvswitch.org/mailman/listinfo/dev
