During the upcall thread bond output translation, bond_may_recirc()
is currently called outside the lock. In case the main thread executes
bond_reconfigure() at the same time, the upcall thread may find bond
state to be inconsistent when calling bond_update_post_recirc_rules().
This patch fixes the race condition by acquiring the write lock
before calling bond_may_recirc(). The APIs are refactored slightly.
The race condition can result in the following stack trace. Copied
from 'Reported-at':
Thread 23 handler69:
Invalid write of size 8
update_recirc_rules (bond.c:385)
bond_update_post_recirc_rules__ (bond.c:952)
bond_update_post_recirc_rules (bond.c:960)
output_normal (ofproto-dpif-xlate.c:2102)
xlate_normal (ofproto-dpif-xlate.c:2858)
xlate_output_action (ofproto-dpif-xlate.c:4407)
do_xlate_actions (ofproto-dpif-xlate.c:5335)
xlate_actions (ofproto-dpif-xlate.c:6198)
upcall_xlate (ofproto-dpif-upcall.c:1129)
process_upcall (ofproto-dpif-upcall.c:1271)
recv_upcalls (ofproto-dpif-upcall.c:822)
udpif_upcall_handler (ofproto-dpif-upcall.c:740)
Address 0x18630490 is 1,904 bytes inside a block of size 12,288 free'd
free (vg_replace_malloc.c:529)
bond_entry_reset (bond.c:1635)
bond_reconfigure (bond.c:457)
bundle_set (ofproto-dpif.c:2896)
ofproto_bundle_register (ofproto.c:1343)
port_configure (bridge.c:1159)
bridge_reconfigure (bridge.c:785)
bridge_run (bridge.c:3099)
main (ovs-vswitchd.c:111)
Block was alloc'd at
malloc (vg_replace_malloc.c:298)
xmalloc (util.c:110)
bond_entry_reset (bond.c:1629)
bond_reconfigure (bond.c:457)
bond_create (bond.c:245)
bundle_set (ofproto-dpif.c:2900)
ofproto_bundle_register (ofproto.c:1343)
port_configure (bridge.c:1159)
bridge_reconfigure (bridge.c:785)
bridge_run (bridge.c:3099)
main (ovs-vswitchd.c:111)
Reported-by: Huanle Han <[email protected]>
Reported-at:
https://mail.openvswitch.org/pipermail/ovs-dev/2017-February/328969.html
CC: Huanle Han <[email protected]>
Signed-off-by: Andy Zhou <[email protected]>
---
ofproto/bond.c | 27 +++++++++++++++------------
ofproto/bond.h | 3 ++-
ofproto/ofproto-dpif-xlate.c | 24 ++++++++++++++++--------
3 files changed, 33 insertions(+), 21 deletions(-)
diff --git a/ofproto/bond.c b/ofproto/bond.c
index 260023e4bb64..6e10c5143c0e 100644
--- a/ofproto/bond.c
+++ b/ofproto/bond.c
@@ -916,17 +916,16 @@ bool
bond_may_recirc(const struct bond *bond, uint32_t *recirc_id,
uint32_t *hash_bias)
{
- if (bond->balance == BM_TCP && bond->recirc_id) {
- if (recirc_id) {
- *recirc_id = bond->recirc_id;
- }
- if (hash_bias) {
- *hash_bias = bond->basis;
- }
- return true;
- } else {
- return false;
+ bool may_recirc = bond->balance == BM_TCP && bond->recirc_id;
+
+ if (recirc_id) {
+ *recirc_id = may_recirc ? bond->recirc_id : 0;
}
+ if (hash_bias) {
+ *hash_bias = may_recirc ? bond->basis : 0;
+ }
+
+ return may_recirc;
}
static void
@@ -954,12 +953,16 @@ bond_update_post_recirc_rules__(struct bond* bond, const
bool force)
}
void
-bond_update_post_recirc_rules(struct bond* bond, const bool force)
+bond_update_post_recirc_rules(struct bond *bond, uint32_t *recirc_id,
+ uint32_t *hash_basis)
{
ovs_rwlock_wrlock(&rwlock);
- bond_update_post_recirc_rules__(bond, force);
+ if (bond_may_recirc(bond, recirc_id, hash_basis)) {
+ bond_update_post_recirc_rules__(bond, false);
+ }
ovs_rwlock_unlock(&rwlock);
}
+
/* Rebalancing. */
diff --git a/ofproto/bond.h b/ofproto/bond.h
index 9a5ea9e21040..6e1221d2381b 100644
--- a/ofproto/bond.h
+++ b/ofproto/bond.h
@@ -120,7 +120,8 @@ void bond_rebalance(struct bond *);
* Bond module pulls stats from those post recirculation rules. If rebalancing
* is needed, those rules are updated with new output actions.
*/
-void bond_update_post_recirc_rules(struct bond *, const bool force);
+void bond_update_post_recirc_rules(struct bond *, uint32_t *recirc_id,
+ uint32_t *hash_basis);
bool bond_may_recirc(const struct bond *, uint32_t *recirc_id,
uint32_t *hash_bias);
#endif /* bond.h */
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index 503a347fc98f..89fc3a44a0d1 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -1987,15 +1987,23 @@ output_normal(struct xlate_ctx *ctx, const struct
xbundle *out_xbundle,
struct flow_wildcards *wc = ctx->wc;
struct ofport_dpif *ofport;
- if (ctx->xbridge->support.odp.recirc) {
- use_recirc = bond_may_recirc(
- out_xbundle->bond, &xr.recirc_id, &xr.hash_basis);
-
- if (use_recirc) {
- /* Only TCP mode uses recirculation. */
+ if (ctx->xbridge->support.odp.recirc
+ && bond_may_recirc(out_xbundle->bond, NULL, NULL)) {
+ /* To avoid unnecessary locking, bond_may_recirc() is first
+ * called outside of the 'rwlock'. After acquiring the lock,
+ * bond_update_post_recirc_rules() will check again to make
+ * sure bond configuration has not been changed.
+ *
+ * In case recirculation is not actually in use, 'xr.recirc_id'
+ * will be set to '0', Since a valid 'recirc_id' can
+ * not be zero. */
+ bond_update_post_recirc_rules(out_xbundle->bond,
+ &xr.recirc_id,
+ &xr.hash_basis);
+ if (xr.recirc_id) {
+ /* Use recirculation instead of output. */
+ use_recirc = true;
xr.hash_alg = OVS_HASH_ALG_L4;
- bond_update_post_recirc_rules(out_xbundle->bond, false);
-
/* Recirculation does not require unmasking hash fields. */
wc = NULL;
}
--
1.9.1
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev