xlate_normal() held the mac_learning lock while calling
output_normal(). When running with patch ports, this could cause
xlate_actions() to be called again, possibly attempting to take a
write lock on the same learning table causing a deadlock. This patch
solves the problem by holding the lock for a very brief period of
time.
Bug #19423.
Signed-off-by: Ethan Jackson <ethan@nicira.com>
Acked-by: Justin Pettit <jpettit@nicira.com>
struct xbundle *in_xbundle;
struct xport *in_port;
struct mac_entry *mac;
struct xbundle *in_xbundle;
struct xport *in_port;
struct mac_entry *mac;
uint16_t vlan;
uint16_t vid;
uint16_t vlan;
uint16_t vid;
/* Determine output bundle. */
ovs_rwlock_rdlock(&ctx->xbridge->ml->rwlock);
mac = mac_learning_lookup(ctx->xbridge->ml, flow->dl_dst, vlan);
/* Determine output bundle. */
ovs_rwlock_rdlock(&ctx->xbridge->ml->rwlock);
mac = mac_learning_lookup(ctx->xbridge->ml, flow->dl_dst, vlan);
- if (mac) {
- struct xbundle *mac_xbundle = xbundle_lookup(mac->port.p);
+ mac_port = mac ? mac->port.p : NULL;
+ ovs_rwlock_unlock(&ctx->xbridge->ml->rwlock);
+
+ if (mac_port) {
+ struct xbundle *mac_xbundle = xbundle_lookup(mac_port);
if (mac_xbundle && mac_xbundle != in_xbundle) {
xlate_report(ctx, "forwarding to learned port");
output_normal(ctx, mac_xbundle, vlan);
if (mac_xbundle && mac_xbundle != in_xbundle) {
xlate_report(ctx, "forwarding to learned port");
output_normal(ctx, mac_xbundle, vlan);
}
ctx->xout->nf_output_iface = NF_OUT_FLOOD;
}
}
ctx->xout->nf_output_iface = NF_OUT_FLOOD;
}
- ovs_rwlock_unlock(&ctx->xbridge->ml->rwlock);
}
/* Compose SAMPLE action for sFlow or IPFIX. The given probability is
}
/* Compose SAMPLE action for sFlow or IPFIX. The given probability is