- find_buckets(table, target, buckets);
- for (i = 0; i < 2; i++) {
- struct sw_flow *f = rcu_dereference(*buckets[i]);
- if (f) {
- if (!memcmp(&f->key, target, sizeof(struct odp_flow_key)))
- return buckets[i];
- } else if (!empty_bucket)
- empty_bucket = buckets[i];
- }
- return empty_bucket;
+/**
+ * dp_table_insert - insert flow into table
+ * @table: table in which to insert flow
+ * @target: flow to insert
+ *
+ * The caller must ensure that no flow with key identical to @target->key
+ * already exists in @table. Returns 0 or a negative error (currently just
+ * -ENOMEM).
+ *
+ * The caller is responsible for updating &struct datapath's n_flows member.
+ */
+int dp_table_insert(struct dp_table *table, struct sw_flow *target)
+{
+ u32 hash = flow_hash(table, &target->key);
+ struct dp_bucket **oldp = find_bucket(table, hash);
+ struct dp_bucket *old = *rcu_dereference(oldp);
+ unsigned int n = old ? old->n_flows : 0;
+ struct dp_bucket *new = dp_bucket_alloc(n + 1);
+
+ if (!new)
+ return -ENOMEM;
+
+ new->n_flows = n + 1;
+ if (old)
+ memcpy(new->flows, old->flows, n * sizeof(struct sw_flow*));
+ new->flows[n] = target;
+
+ rcu_assign_pointer(*oldp, new);
+ if (old)
+ call_rcu(&old->rcu, dp_free_bucket_rcu);
+
+ return 0;