diff options
Diffstat (limited to 'net/openvswitch')
| -rw-r--r-- | net/openvswitch/actions.c | 12 | ||||
| -rw-r--r-- | net/openvswitch/meter.c | 33 |
2 files changed, 29 insertions, 16 deletions
diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c index 513fca6a8e8a..dc5ff859f114 100644 --- a/net/openvswitch/actions.c +++ b/net/openvswitch/actions.c @@ -1108,6 +1108,10 @@ static int execute_masked_set_action(struct sk_buff *skb, return err; } +/* When 'last' is true, recirc() should always consume the 'skb'. + * Otherwise, recirc() should keep 'skb' intact regardless what + * actions are executed on recirculation. + */ static int execute_recirc(struct datapath *dp, struct sk_buff *skb, struct sw_flow_key *key, const struct nlattr *a, bool last) @@ -1118,8 +1122,12 @@ static int execute_recirc(struct datapath *dp, struct sk_buff *skb, int err; err = ovs_flow_key_update(skb, key); - if (err) + if (err) { + if (last) + ovs_kfree_skb_reason(skb, + OVS_DROP_ACTION_ERROR); return err; + } } BUG_ON(!is_flow_key_valid(key)); @@ -1372,7 +1380,7 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, if (!is_flow_key_valid(key)) { err = ovs_flow_key_update(skb, key); if (err) - return err; + break; } err = ovs_ct_execute(ovs_dp_get_net(dp), skb, key, diff --git a/net/openvswitch/meter.c b/net/openvswitch/meter.c index a02c47277337..4aaeeae3af5b 100644 --- a/net/openvswitch/meter.c +++ b/net/openvswitch/meter.c @@ -133,18 +133,10 @@ static void dp_meter_instance_remove(struct dp_meter_instance *ti, static int attach_meter(struct dp_meter_table *tbl, struct dp_meter *meter) { - struct dp_meter_instance *ti = rcu_dereference_ovsl(tbl->ti); - u32 hash = meter_hash(ti, meter->id); + struct dp_meter_instance *ti; + u32 hash; int err; - /* In generally, slots selected should be empty, because - * OvS uses id-pool to fetch a available id. - */ - if (unlikely(rcu_dereference_ovsl(ti->dp_meters[hash]))) - return -EBUSY; - - dp_meter_instance_insert(ti, meter); - /* That function is thread-safe. */ tbl->count++; if (tbl->count >= tbl->max_meters_allowed) { @@ -152,16 +144,29 @@ static int attach_meter(struct dp_meter_table *tbl, struct dp_meter *meter) goto attach_err; } - if (tbl->count >= ti->n_meters && - dp_meter_instance_realloc(tbl, ti->n_meters * 2)) { - err = -ENOMEM; + ti = rcu_dereference_ovsl(tbl->ti); + if (tbl->count >= ti->n_meters) { + err = dp_meter_instance_realloc(tbl, ti->n_meters * 2); + if (err) + goto attach_err; + + ti = rcu_dereference_ovsl(tbl->ti); + } + + hash = meter_hash(ti, meter->id); + + /* In general, selected slots should be empty, because + * OvS uses id-pool to fetch available ids. + */ + if (unlikely(rcu_dereference_ovsl(ti->dp_meters[hash]))) { + err = -EBUSY; goto attach_err; } + dp_meter_instance_insert(ti, meter); return 0; attach_err: - dp_meter_instance_remove(ti, meter); tbl->count--; return err; } |
