aboutsummaryrefslogtreecommitdiffstats
path: root/net/openvswitch
diff options
context:
space:
mode:
authorPravin B Shelar <pshelar@nicira.com>2013-10-04 03:14:23 -0400
committerJesse Gross <jesse@nicira.com>2013-10-04 03:18:26 -0400
commitb637e4988c2d689bb43f943a5af0e684a4981159 (patch)
tree36fbf2ee83323b2441861de650c6dabe6d5cc663 /net/openvswitch
parente64457191a259537bbbfaebeba9a8043786af96f (diff)
openvswitch: Move mega-flow list out of rehashing struct.
ovs-flow rehash does not touch mega flow list. Following patch moves it dp struct datapath. Avoid one extra indirection for accessing mega-flow list head on every packet receive. Signed-off-by: Pravin B Shelar <pshelar@nicira.com> Signed-off-by: Jesse Gross <jesse@nicira.com>
Diffstat (limited to 'net/openvswitch')
-rw-r--r--net/openvswitch/datapath.c77
-rw-r--r--net/openvswitch/datapath.h6
-rw-r--r--net/openvswitch/flow_table.c205
-rw-r--r--net/openvswitch/flow_table.h32
4 files changed, 155 insertions, 165 deletions
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
index 72e68743c643..60b9be3b9477 100644
--- a/net/openvswitch/datapath.c
+++ b/net/openvswitch/datapath.c
@@ -59,8 +59,6 @@
59#include "vport-internal_dev.h" 59#include "vport-internal_dev.h"
60#include "vport-netdev.h" 60#include "vport-netdev.h"
61 61
62#define REHASH_FLOW_INTERVAL (10 * 60 * HZ)
63
64int ovs_net_id __read_mostly; 62int ovs_net_id __read_mostly;
65 63
66static void ovs_notify(struct sk_buff *skb, struct genl_info *info, 64static void ovs_notify(struct sk_buff *skb, struct genl_info *info,
@@ -163,7 +161,7 @@ static void destroy_dp_rcu(struct rcu_head *rcu)
163{ 161{
164 struct datapath *dp = container_of(rcu, struct datapath, rcu); 162 struct datapath *dp = container_of(rcu, struct datapath, rcu);
165 163
166 ovs_flow_tbl_destroy((__force struct flow_table *)dp->table, false); 164 ovs_flow_tbl_destroy(&dp->table, false);
167 free_percpu(dp->stats_percpu); 165 free_percpu(dp->stats_percpu);
168 release_net(ovs_dp_get_net(dp)); 166 release_net(ovs_dp_get_net(dp));
169 kfree(dp->ports); 167 kfree(dp->ports);
@@ -235,7 +233,7 @@ void ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb)
235 } 233 }
236 234
237 /* Look up flow. */ 235 /* Look up flow. */
238 flow = ovs_flow_tbl_lookup(rcu_dereference(dp->table), &key); 236 flow = ovs_flow_tbl_lookup(&dp->table, &key);
239 if (unlikely(!flow)) { 237 if (unlikely(!flow)) {
240 struct dp_upcall_info upcall; 238 struct dp_upcall_info upcall;
241 239
@@ -453,23 +451,6 @@ out:
453 return err; 451 return err;
454} 452}
455 453
456/* Called with ovs_mutex. */
457static int flush_flows(struct datapath *dp)
458{
459 struct flow_table *old_table;
460 struct flow_table *new_table;
461
462 old_table = ovsl_dereference(dp->table);
463 new_table = ovs_flow_tbl_alloc(TBL_MIN_BUCKETS);
464 if (!new_table)
465 return -ENOMEM;
466
467 rcu_assign_pointer(dp->table, new_table);
468
469 ovs_flow_tbl_destroy(old_table, true);
470 return 0;
471}
472
473static void clear_stats(struct sw_flow *flow) 454static void clear_stats(struct sw_flow *flow)
474{ 455{
475 flow->used = 0; 456 flow->used = 0;
@@ -584,11 +565,9 @@ static struct genl_ops dp_packet_genl_ops[] = {
584 565
585static void get_dp_stats(struct datapath *dp, struct ovs_dp_stats *stats) 566static void get_dp_stats(struct datapath *dp, struct ovs_dp_stats *stats)
586{ 567{
587 struct flow_table *table;
588 int i; 568 int i;
589 569
590 table = rcu_dereference_check(dp->table, lockdep_ovsl_is_held()); 570 stats->n_flows = ovs_flow_tbl_count(&dp->table);
591 stats->n_flows = ovs_flow_tbl_count(table);
592 571
593 stats->n_hit = stats->n_missed = stats->n_lost = 0; 572 stats->n_hit = stats->n_missed = stats->n_lost = 0;
594 for_each_possible_cpu(i) { 573 for_each_possible_cpu(i) {
@@ -773,7 +752,6 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
773 struct sw_flow_mask mask; 752 struct sw_flow_mask mask;
774 struct sk_buff *reply; 753 struct sk_buff *reply;
775 struct datapath *dp; 754 struct datapath *dp;
776 struct flow_table *table;
777 struct sw_flow_actions *acts = NULL; 755 struct sw_flow_actions *acts = NULL;
778 struct sw_flow_match match; 756 struct sw_flow_match match;
779 int error; 757 int error;
@@ -814,12 +792,9 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
814 if (!dp) 792 if (!dp)
815 goto err_unlock_ovs; 793 goto err_unlock_ovs;
816 794
817 table = ovsl_dereference(dp->table);
818
819 /* Check if this is a duplicate flow */ 795 /* Check if this is a duplicate flow */
820 flow = ovs_flow_tbl_lookup(table, &key); 796 flow = ovs_flow_tbl_lookup(&dp->table, &key);
821 if (!flow) { 797 if (!flow) {
822 struct flow_table *new_table = NULL;
823 struct sw_flow_mask *mask_p; 798 struct sw_flow_mask *mask_p;
824 799
825 /* Bail out if we're not allowed to create a new flow. */ 800 /* Bail out if we're not allowed to create a new flow. */
@@ -827,19 +802,6 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
827 if (info->genlhdr->cmd == OVS_FLOW_CMD_SET) 802 if (info->genlhdr->cmd == OVS_FLOW_CMD_SET)
828 goto err_unlock_ovs; 803 goto err_unlock_ovs;
829 804
830 /* Expand table, if necessary, to make room. */
831 if (ovs_flow_tbl_need_to_expand(table))
832 new_table = ovs_flow_tbl_expand(table);
833 else if (time_after(jiffies, dp->last_rehash + REHASH_FLOW_INTERVAL))
834 new_table = ovs_flow_tbl_rehash(table);
835
836 if (new_table && !IS_ERR(new_table)) {
837 rcu_assign_pointer(dp->table, new_table);
838 ovs_flow_tbl_destroy(table, true);
839 table = ovsl_dereference(dp->table);
840 dp->last_rehash = jiffies;
841 }
842
843 /* Allocate flow. */ 805 /* Allocate flow. */
844 flow = ovs_flow_alloc(); 806 flow = ovs_flow_alloc();
845 if (IS_ERR(flow)) { 807 if (IS_ERR(flow)) {
@@ -852,7 +814,7 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
852 flow->unmasked_key = key; 814 flow->unmasked_key = key;
853 815
854 /* Make sure mask is unique in the system */ 816 /* Make sure mask is unique in the system */
855 mask_p = ovs_sw_flow_mask_find(table, &mask); 817 mask_p = ovs_sw_flow_mask_find(&dp->table, &mask);
856 if (!mask_p) { 818 if (!mask_p) {
857 /* Allocate a new mask if none exsits. */ 819 /* Allocate a new mask if none exsits. */
858 mask_p = ovs_sw_flow_mask_alloc(); 820 mask_p = ovs_sw_flow_mask_alloc();
@@ -860,7 +822,7 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
860 goto err_flow_free; 822 goto err_flow_free;
861 mask_p->key = mask.key; 823 mask_p->key = mask.key;
862 mask_p->range = mask.range; 824 mask_p->range = mask.range;
863 ovs_sw_flow_mask_insert(table, mask_p); 825 ovs_sw_flow_mask_insert(&dp->table, mask_p);
864 } 826 }
865 827
866 ovs_sw_flow_mask_add_ref(mask_p); 828 ovs_sw_flow_mask_add_ref(mask_p);
@@ -868,7 +830,7 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
868 rcu_assign_pointer(flow->sf_acts, acts); 830 rcu_assign_pointer(flow->sf_acts, acts);
869 831
870 /* Put flow in bucket. */ 832 /* Put flow in bucket. */
871 ovs_flow_tbl_insert(table, flow); 833 ovs_flow_tbl_insert(&dp->table, flow);
872 834
873 reply = ovs_flow_cmd_build_info(flow, dp, info->snd_portid, 835 reply = ovs_flow_cmd_build_info(flow, dp, info->snd_portid,
874 info->snd_seq, OVS_FLOW_CMD_NEW); 836 info->snd_seq, OVS_FLOW_CMD_NEW);
@@ -936,7 +898,6 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info)
936 struct sk_buff *reply; 898 struct sk_buff *reply;
937 struct sw_flow *flow; 899 struct sw_flow *flow;
938 struct datapath *dp; 900 struct datapath *dp;
939 struct flow_table *table;
940 struct sw_flow_match match; 901 struct sw_flow_match match;
941 int err; 902 int err;
942 903
@@ -957,8 +918,7 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info)
957 goto unlock; 918 goto unlock;
958 } 919 }
959 920
960 table = ovsl_dereference(dp->table); 921 flow = ovs_flow_tbl_lookup(&dp->table, &key);
961 flow = ovs_flow_tbl_lookup(table, &key);
962 if (!flow || !ovs_flow_cmp_unmasked_key(flow, &match)) { 922 if (!flow || !ovs_flow_cmp_unmasked_key(flow, &match)) {
963 err = -ENOENT; 923 err = -ENOENT;
964 goto unlock; 924 goto unlock;
@@ -986,7 +946,6 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info)
986 struct sk_buff *reply; 946 struct sk_buff *reply;
987 struct sw_flow *flow; 947 struct sw_flow *flow;
988 struct datapath *dp; 948 struct datapath *dp;
989 struct flow_table *table;
990 struct sw_flow_match match; 949 struct sw_flow_match match;
991 int err; 950 int err;
992 951
@@ -998,7 +957,7 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info)
998 } 957 }
999 958
1000 if (!a[OVS_FLOW_ATTR_KEY]) { 959 if (!a[OVS_FLOW_ATTR_KEY]) {
1001 err = flush_flows(dp); 960 err = ovs_flow_tbl_flush(&dp->table);
1002 goto unlock; 961 goto unlock;
1003 } 962 }
1004 963
@@ -1007,8 +966,7 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info)
1007 if (err) 966 if (err)
1008 goto unlock; 967 goto unlock;
1009 968
1010 table = ovsl_dereference(dp->table); 969 flow = ovs_flow_tbl_lookup(&dp->table, &key);
1011 flow = ovs_flow_tbl_lookup(table, &key);
1012 if (!flow || !ovs_flow_cmp_unmasked_key(flow, &match)) { 970 if (!flow || !ovs_flow_cmp_unmasked_key(flow, &match)) {
1013 err = -ENOENT; 971 err = -ENOENT;
1014 goto unlock; 972 goto unlock;
@@ -1020,7 +978,7 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info)
1020 goto unlock; 978 goto unlock;
1021 } 979 }
1022 980
1023 ovs_flow_tbl_remove(table, flow); 981 ovs_flow_tbl_remove(&dp->table, flow);
1024 982
1025 err = ovs_flow_cmd_fill_info(flow, dp, reply, info->snd_portid, 983 err = ovs_flow_cmd_fill_info(flow, dp, reply, info->snd_portid,
1026 info->snd_seq, 0, OVS_FLOW_CMD_DEL); 984 info->snd_seq, 0, OVS_FLOW_CMD_DEL);
@@ -1039,8 +997,8 @@ unlock:
1039static int ovs_flow_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb) 997static int ovs_flow_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
1040{ 998{
1041 struct ovs_header *ovs_header = genlmsg_data(nlmsg_data(cb->nlh)); 999 struct ovs_header *ovs_header = genlmsg_data(nlmsg_data(cb->nlh));
1000 struct table_instance *ti;
1042 struct datapath *dp; 1001 struct datapath *dp;
1043 struct flow_table *table;
1044 1002
1045 rcu_read_lock(); 1003 rcu_read_lock();
1046 dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex); 1004 dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
@@ -1049,14 +1007,14 @@ static int ovs_flow_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
1049 return -ENODEV; 1007 return -ENODEV;
1050 } 1008 }
1051 1009
1052 table = rcu_dereference(dp->table); 1010 ti = rcu_dereference(dp->table.ti);
1053 for (;;) { 1011 for (;;) {
1054 struct sw_flow *flow; 1012 struct sw_flow *flow;
1055 u32 bucket, obj; 1013 u32 bucket, obj;
1056 1014
1057 bucket = cb->args[0]; 1015 bucket = cb->args[0];
1058 obj = cb->args[1]; 1016 obj = cb->args[1];
1059 flow = ovs_flow_tbl_dump_next(table, &bucket, &obj); 1017 flow = ovs_flow_tbl_dump_next(ti, &bucket, &obj);
1060 if (!flow) 1018 if (!flow)
1061 break; 1019 break;
1062 1020
@@ -1220,9 +1178,8 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
1220 ovs_dp_set_net(dp, hold_net(sock_net(skb->sk))); 1178 ovs_dp_set_net(dp, hold_net(sock_net(skb->sk)));
1221 1179
1222 /* Allocate table. */ 1180 /* Allocate table. */
1223 err = -ENOMEM; 1181 err = ovs_flow_tbl_init(&dp->table);
1224 rcu_assign_pointer(dp->table, ovs_flow_tbl_alloc(TBL_MIN_BUCKETS)); 1182 if (err)
1225 if (!dp->table)
1226 goto err_free_dp; 1183 goto err_free_dp;
1227 1184
1228 dp->stats_percpu = alloc_percpu(struct dp_stats_percpu); 1185 dp->stats_percpu = alloc_percpu(struct dp_stats_percpu);
@@ -1279,7 +1236,7 @@ err_destroy_ports_array:
1279err_destroy_percpu: 1236err_destroy_percpu:
1280 free_percpu(dp->stats_percpu); 1237 free_percpu(dp->stats_percpu);
1281err_destroy_table: 1238err_destroy_table:
1282 ovs_flow_tbl_destroy(ovsl_dereference(dp->table), false); 1239 ovs_flow_tbl_destroy(&dp->table, false);
1283err_free_dp: 1240err_free_dp:
1284 release_net(ovs_dp_get_net(dp)); 1241 release_net(ovs_dp_get_net(dp));
1285 kfree(dp); 1242 kfree(dp);
diff --git a/net/openvswitch/datapath.h b/net/openvswitch/datapath.h
index a6982ef84f20..acfd4af8ca3a 100644
--- a/net/openvswitch/datapath.h
+++ b/net/openvswitch/datapath.h
@@ -58,12 +58,11 @@ struct dp_stats_percpu {
58 * struct datapath - datapath for flow-based packet switching 58 * struct datapath - datapath for flow-based packet switching
59 * @rcu: RCU callback head for deferred destruction. 59 * @rcu: RCU callback head for deferred destruction.
60 * @list_node: Element in global 'dps' list. 60 * @list_node: Element in global 'dps' list.
61 * @table: Current flow table. Protected by ovs_mutex and RCU. 61 * @table: flow table.
62 * @ports: Hash table for ports. %OVSP_LOCAL port always exists. Protected by 62 * @ports: Hash table for ports. %OVSP_LOCAL port always exists. Protected by
63 * ovs_mutex and RCU. 63 * ovs_mutex and RCU.
64 * @stats_percpu: Per-CPU datapath statistics. 64 * @stats_percpu: Per-CPU datapath statistics.
65 * @net: Reference to net namespace. 65 * @net: Reference to net namespace.
66 * @last_rehash: Timestamp of last rehash.
67 * 66 *
68 * Context: See the comment on locking at the top of datapath.c for additional 67 * Context: See the comment on locking at the top of datapath.c for additional
69 * locking information. 68 * locking information.
@@ -73,7 +72,7 @@ struct datapath {
73 struct list_head list_node; 72 struct list_head list_node;
74 73
75 /* Flow table. */ 74 /* Flow table. */
76 struct flow_table __rcu *table; 75 struct flow_table table;
77 76
78 /* Switch ports. */ 77 /* Switch ports. */
79 struct hlist_head *ports; 78 struct hlist_head *ports;
@@ -85,7 +84,6 @@ struct datapath {
85 /* Network namespace ref. */ 84 /* Network namespace ref. */
86 struct net *net; 85 struct net *net;
87#endif 86#endif
88 unsigned long last_rehash;
89}; 87};
90 88
91/** 89/**
diff --git a/net/openvswitch/flow_table.c b/net/openvswitch/flow_table.c
index dcadb75bb173..1c7e7732ed4c 100644
--- a/net/openvswitch/flow_table.c
+++ b/net/openvswitch/flow_table.c
@@ -44,6 +44,11 @@
44#include <net/ipv6.h> 44#include <net/ipv6.h>
45#include <net/ndisc.h> 45#include <net/ndisc.h>
46 46
47#include "datapath.h"
48
49#define TBL_MIN_BUCKETS 1024
50#define REHASH_INTERVAL (10 * 60 * HZ)
51
47static struct kmem_cache *flow_cache; 52static struct kmem_cache *flow_cache;
48 53
49static u16 range_n_bytes(const struct sw_flow_key_range *range) 54static u16 range_n_bytes(const struct sw_flow_key_range *range)
@@ -82,6 +87,11 @@ struct sw_flow *ovs_flow_alloc(void)
82 return flow; 87 return flow;
83} 88}
84 89
90int ovs_flow_tbl_count(struct flow_table *table)
91{
92 return table->count;
93}
94
85static struct flex_array *alloc_buckets(unsigned int n_buckets) 95static struct flex_array *alloc_buckets(unsigned int n_buckets)
86{ 96{
87 struct flex_array *buckets; 97 struct flex_array *buckets;
@@ -136,18 +146,18 @@ static void free_buckets(struct flex_array *buckets)
136 flex_array_free(buckets); 146 flex_array_free(buckets);
137} 147}
138 148
139static void __flow_tbl_destroy(struct flow_table *table) 149static void __table_instance_destroy(struct table_instance *ti)
140{ 150{
141 int i; 151 int i;
142 152
143 if (table->keep_flows) 153 if (ti->keep_flows)
144 goto skip_flows; 154 goto skip_flows;
145 155
146 for (i = 0; i < table->n_buckets; i++) { 156 for (i = 0; i < ti->n_buckets; i++) {
147 struct sw_flow *flow; 157 struct sw_flow *flow;
148 struct hlist_head *head = flex_array_get(table->buckets, i); 158 struct hlist_head *head = flex_array_get(ti->buckets, i);
149 struct hlist_node *n; 159 struct hlist_node *n;
150 int ver = table->node_ver; 160 int ver = ti->node_ver;
151 161
152 hlist_for_each_entry_safe(flow, n, head, hash_node[ver]) { 162 hlist_for_each_entry_safe(flow, n, head, hash_node[ver]) {
153 hlist_del(&flow->hash_node[ver]); 163 hlist_del(&flow->hash_node[ver]);
@@ -155,74 +165,74 @@ static void __flow_tbl_destroy(struct flow_table *table)
155 } 165 }
156 } 166 }
157 167
158 BUG_ON(!list_empty(table->mask_list));
159 kfree(table->mask_list);
160
161skip_flows: 168skip_flows:
162 free_buckets(table->buckets); 169 free_buckets(ti->buckets);
163 kfree(table); 170 kfree(ti);
164} 171}
165 172
166static struct flow_table *__flow_tbl_alloc(int new_size) 173static struct table_instance *table_instance_alloc(int new_size)
167{ 174{
168 struct flow_table *table = kmalloc(sizeof(*table), GFP_KERNEL); 175 struct table_instance *ti = kmalloc(sizeof(*ti), GFP_KERNEL);
169 176
170 if (!table) 177 if (!ti)
171 return NULL; 178 return NULL;
172 179
173 table->buckets = alloc_buckets(new_size); 180 ti->buckets = alloc_buckets(new_size);
174 181
175 if (!table->buckets) { 182 if (!ti->buckets) {
176 kfree(table); 183 kfree(ti);
177 return NULL; 184 return NULL;
178 } 185 }
179 table->n_buckets = new_size; 186 ti->n_buckets = new_size;
180 table->count = 0; 187 ti->node_ver = 0;
181 table->node_ver = 0; 188 ti->keep_flows = false;
182 table->keep_flows = false; 189 get_random_bytes(&ti->hash_seed, sizeof(u32));
183 get_random_bytes(&table->hash_seed, sizeof(u32));
184 table->mask_list = NULL;
185 190
186 return table; 191 return ti;
187} 192}
188 193
189struct flow_table *ovs_flow_tbl_alloc(int new_size) 194int ovs_flow_tbl_init(struct flow_table *table)
190{ 195{
191 struct flow_table *table = __flow_tbl_alloc(new_size); 196 struct table_instance *ti;
192 197
193 if (!table) 198 ti = table_instance_alloc(TBL_MIN_BUCKETS);
194 return NULL;
195 199
196 table->mask_list = kmalloc(sizeof(struct list_head), GFP_KERNEL); 200 if (!ti)
197 if (!table->mask_list) { 201 return -ENOMEM;
198 table->keep_flows = true;
199 __flow_tbl_destroy(table);
200 return NULL;
201 }
202 INIT_LIST_HEAD(table->mask_list);
203 202
204 return table; 203 rcu_assign_pointer(table->ti, ti);
204 INIT_LIST_HEAD(&table->mask_list);
205 table->last_rehash = jiffies;
206 table->count = 0;
207 return 0;
205} 208}
206 209
207static void flow_tbl_destroy_rcu_cb(struct rcu_head *rcu) 210static void flow_tbl_destroy_rcu_cb(struct rcu_head *rcu)
208{ 211{
209 struct flow_table *table = container_of(rcu, struct flow_table, rcu); 212 struct table_instance *ti = container_of(rcu, struct table_instance, rcu);
210 213
211 __flow_tbl_destroy(table); 214 __table_instance_destroy(ti);
212} 215}
213 216
214void ovs_flow_tbl_destroy(struct flow_table *table, bool deferred) 217static void table_instance_destroy(struct table_instance *ti, bool deferred)
215{ 218{
216 if (!table) 219 if (!ti)
217 return; 220 return;
218 221
219 if (deferred) 222 if (deferred)
220 call_rcu(&table->rcu, flow_tbl_destroy_rcu_cb); 223 call_rcu(&ti->rcu, flow_tbl_destroy_rcu_cb);
221 else 224 else
222 __flow_tbl_destroy(table); 225 __table_instance_destroy(ti);
226}
227
228void ovs_flow_tbl_destroy(struct flow_table *table, bool deferred)
229{
230 struct table_instance *ti = ovsl_dereference(table->ti);
231
232 table_instance_destroy(ti, deferred);
223} 233}
224 234
225struct sw_flow *ovs_flow_tbl_dump_next(struct flow_table *table, 235struct sw_flow *ovs_flow_tbl_dump_next(struct table_instance *ti,
226 u32 *bucket, u32 *last) 236 u32 *bucket, u32 *last)
227{ 237{
228 struct sw_flow *flow; 238 struct sw_flow *flow;
@@ -230,10 +240,10 @@ struct sw_flow *ovs_flow_tbl_dump_next(struct flow_table *table,
230 int ver; 240 int ver;
231 int i; 241 int i;
232 242
233 ver = table->node_ver; 243 ver = ti->node_ver;
234 while (*bucket < table->n_buckets) { 244 while (*bucket < ti->n_buckets) {
235 i = 0; 245 i = 0;
236 head = flex_array_get(table->buckets, *bucket); 246 head = flex_array_get(ti->buckets, *bucket);
237 hlist_for_each_entry_rcu(flow, head, hash_node[ver]) { 247 hlist_for_each_entry_rcu(flow, head, hash_node[ver]) {
238 if (i < *last) { 248 if (i < *last) {
239 i++; 249 i++;
@@ -249,25 +259,23 @@ struct sw_flow *ovs_flow_tbl_dump_next(struct flow_table *table,
249 return NULL; 259 return NULL;
250} 260}
251 261
252static struct hlist_head *find_bucket(struct flow_table *table, u32 hash) 262static struct hlist_head *find_bucket(struct table_instance *ti, u32 hash)
253{ 263{
254 hash = jhash_1word(hash, table->hash_seed); 264 hash = jhash_1word(hash, ti->hash_seed);
255 return flex_array_get(table->buckets, 265 return flex_array_get(ti->buckets,
256 (hash & (table->n_buckets - 1))); 266 (hash & (ti->n_buckets - 1)));
257} 267}
258 268
259static void __tbl_insert(struct flow_table *table, struct sw_flow *flow) 269static void table_instance_insert(struct table_instance *ti, struct sw_flow *flow)
260{ 270{
261 struct hlist_head *head; 271 struct hlist_head *head;
262 272
263 head = find_bucket(table, flow->hash); 273 head = find_bucket(ti, flow->hash);
264 hlist_add_head_rcu(&flow->hash_node[table->node_ver], head); 274 hlist_add_head_rcu(&flow->hash_node[ti->node_ver], head);
265
266 table->count++;
267} 275}
268 276
269static void flow_table_copy_flows(struct flow_table *old, 277static void flow_table_copy_flows(struct table_instance *old,
270 struct flow_table *new) 278 struct table_instance *new)
271{ 279{
272 int old_ver; 280 int old_ver;
273 int i; 281 int i;
@@ -283,35 +291,42 @@ static void flow_table_copy_flows(struct flow_table *old,
283 head = flex_array_get(old->buckets, i); 291 head = flex_array_get(old->buckets, i);
284 292
285 hlist_for_each_entry(flow, head, hash_node[old_ver]) 293 hlist_for_each_entry(flow, head, hash_node[old_ver])
286 __tbl_insert(new, flow); 294 table_instance_insert(new, flow);
287 } 295 }
288 296
289 new->mask_list = old->mask_list;
290 old->keep_flows = true; 297 old->keep_flows = true;
291} 298}
292 299
293static struct flow_table *__flow_tbl_rehash(struct flow_table *table, 300static struct table_instance *table_instance_rehash(struct table_instance *ti,
294 int n_buckets) 301 int n_buckets)
295{ 302{
296 struct flow_table *new_table; 303 struct table_instance *new_ti;
297 304
298 new_table = __flow_tbl_alloc(n_buckets); 305 new_ti = table_instance_alloc(n_buckets);
299 if (!new_table) 306 if (!new_ti)
300 return ERR_PTR(-ENOMEM); 307 return ERR_PTR(-ENOMEM);
301 308
302 flow_table_copy_flows(table, new_table); 309 flow_table_copy_flows(ti, new_ti);
303 310
304 return new_table; 311 return new_ti;
305} 312}
306 313
307struct flow_table *ovs_flow_tbl_rehash(struct flow_table *table) 314int ovs_flow_tbl_flush(struct flow_table *flow_table)
308{ 315{
309 return __flow_tbl_rehash(table, table->n_buckets); 316 struct table_instance *old_ti;
310} 317 struct table_instance *new_ti;
311 318
312struct flow_table *ovs_flow_tbl_expand(struct flow_table *table) 319 old_ti = ovsl_dereference(flow_table->ti);
313{ 320 new_ti = table_instance_alloc(TBL_MIN_BUCKETS);
314 return __flow_tbl_rehash(table, table->n_buckets * 2); 321 if (!new_ti)
322 return -ENOMEM;
323
324 rcu_assign_pointer(flow_table->ti, new_ti);
325 flow_table->last_rehash = jiffies;
326 flow_table->count = 0;
327
328 table_instance_destroy(old_ti, true);
329 return 0;
315} 330}
316 331
317static u32 flow_hash(const struct sw_flow_key *key, int key_start, 332static u32 flow_hash(const struct sw_flow_key *key, int key_start,
@@ -367,7 +382,7 @@ bool ovs_flow_cmp_unmasked_key(const struct sw_flow *flow,
367 return cmp_key(&flow->unmasked_key, key, key_start, key_end); 382 return cmp_key(&flow->unmasked_key, key, key_start, key_end);
368} 383}
369 384
370static struct sw_flow *masked_flow_lookup(struct flow_table *table, 385static struct sw_flow *masked_flow_lookup(struct table_instance *ti,
371 const struct sw_flow_key *unmasked, 386 const struct sw_flow_key *unmasked,
372 struct sw_flow_mask *mask) 387 struct sw_flow_mask *mask)
373{ 388{
@@ -380,8 +395,8 @@ static struct sw_flow *masked_flow_lookup(struct flow_table *table,
380 395
381 ovs_flow_mask_key(&masked_key, unmasked, mask); 396 ovs_flow_mask_key(&masked_key, unmasked, mask);
382 hash = flow_hash(&masked_key, key_start, key_end); 397 hash = flow_hash(&masked_key, key_start, key_end);
383 head = find_bucket(table, hash); 398 head = find_bucket(ti, hash);
384 hlist_for_each_entry_rcu(flow, head, hash_node[table->node_ver]) { 399 hlist_for_each_entry_rcu(flow, head, hash_node[ti->node_ver]) {
385 if (flow->mask == mask && 400 if (flow->mask == mask &&
386 flow_cmp_masked_key(flow, &masked_key, 401 flow_cmp_masked_key(flow, &masked_key,
387 key_start, key_end)) 402 key_start, key_end))
@@ -393,29 +408,55 @@ static struct sw_flow *masked_flow_lookup(struct flow_table *table,
393struct sw_flow *ovs_flow_tbl_lookup(struct flow_table *tbl, 408struct sw_flow *ovs_flow_tbl_lookup(struct flow_table *tbl,
394 const struct sw_flow_key *key) 409 const struct sw_flow_key *key)
395{ 410{
396 struct sw_flow *flow = NULL; 411 struct table_instance *ti = rcu_dereference(tbl->ti);
397 struct sw_flow_mask *mask; 412 struct sw_flow_mask *mask;
413 struct sw_flow *flow;
398 414
399 list_for_each_entry_rcu(mask, tbl->mask_list, list) { 415 list_for_each_entry_rcu(mask, &tbl->mask_list, list) {
400 flow = masked_flow_lookup(tbl, key, mask); 416 flow = masked_flow_lookup(ti, key, mask);
401 if (flow) /* Found */ 417 if (flow) /* Found */
402 break; 418 return flow;
403 } 419 }
420 return NULL;
421}
404 422
405 return flow; 423static struct table_instance *table_instance_expand(struct table_instance *ti)
424{
425 return table_instance_rehash(ti, ti->n_buckets * 2);
406} 426}
407 427
408void ovs_flow_tbl_insert(struct flow_table *table, struct sw_flow *flow) 428void ovs_flow_tbl_insert(struct flow_table *table, struct sw_flow *flow)
409{ 429{
430 struct table_instance *ti = NULL;
431 struct table_instance *new_ti = NULL;
432
433 ti = ovsl_dereference(table->ti);
434
435 /* Expand table, if necessary, to make room. */
436 if (table->count > ti->n_buckets)
437 new_ti = table_instance_expand(ti);
438 else if (time_after(jiffies, table->last_rehash + REHASH_INTERVAL))
439 new_ti = table_instance_rehash(ti, ti->n_buckets);
440
441 if (new_ti && !IS_ERR(new_ti)) {
442 rcu_assign_pointer(table->ti, new_ti);
443 ovs_flow_tbl_destroy(table, true);
444 ti = ovsl_dereference(table->ti);
445 table->last_rehash = jiffies;
446 }
447
410 flow->hash = flow_hash(&flow->key, flow->mask->range.start, 448 flow->hash = flow_hash(&flow->key, flow->mask->range.start,
411 flow->mask->range.end); 449 flow->mask->range.end);
412 __tbl_insert(table, flow); 450 table_instance_insert(ti, flow);
451 table->count++;
413} 452}
414 453
415void ovs_flow_tbl_remove(struct flow_table *table, struct sw_flow *flow) 454void ovs_flow_tbl_remove(struct flow_table *table, struct sw_flow *flow)
416{ 455{
456 struct table_instance *ti = ovsl_dereference(table->ti);
457
417 BUG_ON(table->count == 0); 458 BUG_ON(table->count == 0);
418 hlist_del_rcu(&flow->hash_node[table->node_ver]); 459 hlist_del_rcu(&flow->hash_node[ti->node_ver]);
419 table->count--; 460 table->count--;
420} 461}
421 462
@@ -475,7 +516,7 @@ struct sw_flow_mask *ovs_sw_flow_mask_find(const struct flow_table *tbl,
475{ 516{
476 struct list_head *ml; 517 struct list_head *ml;
477 518
478 list_for_each(ml, tbl->mask_list) { 519 list_for_each(ml, &tbl->mask_list) {
479 struct sw_flow_mask *m; 520 struct sw_flow_mask *m;
480 m = container_of(ml, struct sw_flow_mask, list); 521 m = container_of(ml, struct sw_flow_mask, list);
481 if (mask_equal(mask, m)) 522 if (mask_equal(mask, m))
@@ -492,7 +533,7 @@ struct sw_flow_mask *ovs_sw_flow_mask_find(const struct flow_table *tbl,
492 */ 533 */
493void ovs_sw_flow_mask_insert(struct flow_table *tbl, struct sw_flow_mask *mask) 534void ovs_sw_flow_mask_insert(struct flow_table *tbl, struct sw_flow_mask *mask)
494{ 535{
495 list_add_rcu(&mask->list, tbl->mask_list); 536 list_add_rcu(&mask->list, &tbl->mask_list);
496} 537}
497 538
498/* Initializes the flow module. 539/* Initializes the flow module.
diff --git a/net/openvswitch/flow_table.h b/net/openvswitch/flow_table.h
index d7a114457cde..5d1abe566c46 100644
--- a/net/openvswitch/flow_table.h
+++ b/net/openvswitch/flow_table.h
@@ -36,42 +36,36 @@
36 36
37#include "flow.h" 37#include "flow.h"
38 38
39#define TBL_MIN_BUCKETS 1024 39struct table_instance {
40
41struct flow_table {
42 struct flex_array *buckets; 40 struct flex_array *buckets;
43 unsigned int count, n_buckets; 41 unsigned int n_buckets;
44 struct rcu_head rcu; 42 struct rcu_head rcu;
45 struct list_head *mask_list;
46 int node_ver; 43 int node_ver;
47 u32 hash_seed; 44 u32 hash_seed;
48 bool keep_flows; 45 bool keep_flows;
49}; 46};
50 47
48struct flow_table {
49 struct table_instance __rcu *ti;
50 struct list_head mask_list;
51 unsigned long last_rehash;
52 unsigned int count;
53};
54
51int ovs_flow_init(void); 55int ovs_flow_init(void);
52void ovs_flow_exit(void); 56void ovs_flow_exit(void);
53 57
54struct sw_flow *ovs_flow_alloc(void); 58struct sw_flow *ovs_flow_alloc(void);
55void ovs_flow_free(struct sw_flow *, bool deferred); 59void ovs_flow_free(struct sw_flow *, bool deferred);
56 60
57static inline int ovs_flow_tbl_count(struct flow_table *table) 61int ovs_flow_tbl_init(struct flow_table *);
58{ 62int ovs_flow_tbl_count(struct flow_table *table);
59 return table->count;
60}
61
62static inline int ovs_flow_tbl_need_to_expand(struct flow_table *table)
63{
64 return (table->count > table->n_buckets);
65}
66
67struct flow_table *ovs_flow_tbl_alloc(int new_size);
68struct flow_table *ovs_flow_tbl_expand(struct flow_table *table);
69struct flow_table *ovs_flow_tbl_rehash(struct flow_table *table);
70void ovs_flow_tbl_destroy(struct flow_table *table, bool deferred); 63void ovs_flow_tbl_destroy(struct flow_table *table, bool deferred);
64int ovs_flow_tbl_flush(struct flow_table *flow_table);
71 65
72void ovs_flow_tbl_insert(struct flow_table *table, struct sw_flow *flow); 66void ovs_flow_tbl_insert(struct flow_table *table, struct sw_flow *flow);
73void ovs_flow_tbl_remove(struct flow_table *table, struct sw_flow *flow); 67void ovs_flow_tbl_remove(struct flow_table *table, struct sw_flow *flow);
74struct sw_flow *ovs_flow_tbl_dump_next(struct flow_table *table, 68struct sw_flow *ovs_flow_tbl_dump_next(struct table_instance *table,
75 u32 *bucket, u32 *idx); 69 u32 *bucket, u32 *idx);
76struct sw_flow *ovs_flow_tbl_lookup(struct flow_table *, 70struct sw_flow *ovs_flow_tbl_lookup(struct flow_table *,
77 const struct sw_flow_key *); 71 const struct sw_flow_key *);