Skip to content

Commit

Permalink
Fix Agent crash because of parallel access between kTaskFlowStatsColl…
Browse files Browse the repository at this point in the history
…ector and

kTaskDBExclude

When kTaskFlowStatsCollector was updating stats in VnUveEntry, kTaskDBExclude
went ahead and deleted the VnUveEntry. There are other such structures for which
parallel access between kTaskFlowStatsCollector and kTaskDBExclude can cause
issues

Fixed all parallel access between kTaskFlowStatsCollector and kTaskDBExclude by
acquiring required locks. Also added task exclusion between kTaskDBExclude and
Agent::Uve to prevent simultaneous access of UVE data-structures between
kTaskDBExclude and Agent::Uve. The code executed under kTaskDBExclude was
earlier executed in db::DBTable which had exclusion with Agent::Uve.

Also added locks to prevent simultaneous access between kTaskFlowStatsCollector
and Agent::Uve.
Closes-Bug: #1569645

(cherry picked from commit 7fbb3ce)

Change-Id: I744691ffe29c8121289bae91f53009f3acc36786
  • Loading branch information
ashoksr committed Apr 17, 2016
1 parent 5a4a553 commit 4de3a4e
Show file tree
Hide file tree
Showing 16 changed files with 68 additions and 9 deletions.
9 changes: 9 additions & 0 deletions src/vnsw/agent/cmn/agent.cc
Expand Up @@ -271,6 +271,15 @@ void Agent::SetAgentTaskPolicy() {
TaskScheduler *scheduler = TaskScheduler::GetInstance();
scheduler->RegisterLog(boost::bind(&Agent::TaskTrace, this,
_1, _2, _3, _4, _5));

const char *db_exclude_task_exclude_list[] = {
"Agent::Uve",
AGENT_SHUTDOWN_TASKNAME,
AGENT_INIT_TASKNAME
};
SetTaskPolicyOne(kTaskDBExclude, db_exclude_task_exclude_list,
sizeof(db_exclude_task_exclude_list) / sizeof(char *));

}

void Agent::CreateLifetimeManager() {
Expand Down
4 changes: 3 additions & 1 deletion src/vnsw/agent/uve/interface_uve_stats_table.cc
Expand Up @@ -146,6 +146,7 @@ void InterfaceUveStatsTable::UpdateFloatingIpStats(const FipInfo &fip_info) {
if (intf == NULL) {
return;
}
tbb::mutex::scoped_lock lock(interface_tree_mutex_);
VmInterface *vmi = static_cast<VmInterface *>(intf);
InterfaceMap::iterator intf_it = interface_tree_.find(vmi->cfg_name());

Expand Down Expand Up @@ -185,11 +186,12 @@ bool InterfaceUveStatsTable::FrameFipStatsMsg(const VmInterface *itf,

void InterfaceUveStatsTable::UpdatePortBitmap
(const string &name, uint8_t proto, uint16_t sport, uint16_t dport) {
tbb::mutex::scoped_lock lock(interface_tree_mutex_);
InterfaceMap::const_iterator it = interface_tree_.find(name);

if (it != interface_tree_.end()) {
UveInterfaceEntry *entry = it->second.get();
entry->port_bitmap_.AddPort(proto, sport, dport);
entry->UpdatePortBitmap(proto, sport, dport);
}
}

Expand Down
21 changes: 18 additions & 3 deletions src/vnsw/agent/uve/interface_uve_table.cc
Expand Up @@ -8,7 +8,7 @@
#include <uve/agent_uve_base.h>

InterfaceUveTable::InterfaceUveTable(Agent *agent, uint32_t default_intvl)
: agent_(agent), interface_tree_(),
: agent_(agent), interface_tree_(), interface_tree_mutex_(),
intf_listener_id_(DBTableBase::kInvalidId),
timer_last_visited_(""),
timer_(TimerManager::CreateTimer
Expand Down Expand Up @@ -42,6 +42,7 @@ bool InterfaceUveTable::TimerExpiry() {
if (entry->deleted_) {
SendInterfaceDeleteMsg(cfg_name);
if (!entry->renewed_) {
tbb::mutex::scoped_lock lock(interface_tree_mutex_);
interface_tree_.erase(prev);
} else {
entry->deleted_ = false;
Expand Down Expand Up @@ -184,6 +185,17 @@ void InterfaceUveTable::UveInterfaceEntry::Reset() {
renewed_ = false;
}

void InterfaceUveTable::UveInterfaceEntry::UpdatePortBitmap
(uint8_t proto, uint16_t sport, uint16_t dport) {
tbb::mutex::scoped_lock lock(mutex_);
/* No need to update stats if the entry is marked for delete and not
* renewed */
if (deleted_ && !renewed_) {
return;
}
port_bitmap_.AddPort(proto, sport, dport);
}

bool InterfaceUveTable::UveInterfaceEntry::FipAggStatsChanged
(const vector<VmFloatingIPStats> &list) const {
if (list != uve_info_.get_fip_agg_stats()) {
Expand Down Expand Up @@ -393,6 +405,11 @@ bool InterfaceUveTable::UveInterfaceEntry::OutBandChanged(uint64_t out_band)
void InterfaceUveTable::UveInterfaceEntry::UpdateFloatingIpStats
(const FipInfo &fip_info) {
tbb::mutex::scoped_lock lock(mutex_);
/* No need to update stats if the entry is marked for delete and not
* renewed */
if (deleted_ && !renewed_) {
return;
}
FloatingIp *entry = FipEntry(fip_info.fip_, fip_info.vn_);
/* Ignore stats update request if it comes after entry is removed */
if (entry == NULL) {
Expand Down Expand Up @@ -546,7 +563,6 @@ void InterfaceUveTable::UveInterfaceEntry::SetStats

void InterfaceUveTable::UveInterfaceEntry::AddFloatingIp
(const VmInterface::FloatingIp &fip) {
tbb::mutex::scoped_lock lock(mutex_);
FloatingIpPtr key(new FloatingIp(fip.floating_ip_,
fip.vn_.get()->GetName()));
FloatingIpSet::iterator it = fip_tree_.find(key);
Expand All @@ -558,7 +574,6 @@ void InterfaceUveTable::UveInterfaceEntry::AddFloatingIp

void InterfaceUveTable::UveInterfaceEntry::RemoveFloatingIp
(const VmInterface::FloatingIp &fip) {
tbb::mutex::scoped_lock lock(mutex_);
FloatingIpPtr key(new FloatingIp(fip.floating_ip_, fip.vn_.get()->GetName()));
FloatingIpSet::iterator it = fip_tree_.find(key);
if (it != fip_tree_.end()) {
Expand Down
5 changes: 4 additions & 1 deletion src/vnsw/agent/uve/interface_uve_table.h
Expand Up @@ -115,7 +115,7 @@ class InterfaceUveTable {
bool ace_stats_changed_;
UveVMInterfaceAgent uve_info_;
AceStatsSet ace_set_;
/* For exclusion between Agent::StatsCollector and Agent::Uve tasks */
/* For exclusion between kTaskFlowStatsCollector and Agent::Uve */
tbb::mutex mutex_;

UveInterfaceEntry(const VmInterface *i) : intf_(i),
Expand Down Expand Up @@ -149,6 +149,7 @@ class InterfaceUveTable {
void SetVnVmInfo(UveVMInterfaceAgent *uve) const;
void UpdateInterfaceAceStats(const std::string &ace_uuid);
void Reset();
void UpdatePortBitmap(uint8_t proto, uint16_t sport, uint16_t dport);
};
typedef boost::shared_ptr<UveInterfaceEntry> UveInterfaceEntryPtr;

Expand All @@ -170,6 +171,8 @@ class InterfaceUveTable {

Agent *agent_;
InterfaceMap interface_tree_;
/* For exclusion between kTaskFlowStatsCollector and kTaskDBExclude */
tbb::mutex interface_tree_mutex_;
private:
virtual UveInterfaceEntryPtr Allocate(const VmInterface *vm);
void InterfaceNotify(DBTablePartBase *partition, DBEntryBase *e);
Expand Down
6 changes: 6 additions & 0 deletions src/vnsw/agent/uve/vm_uve_entry.cc
Expand Up @@ -17,6 +17,11 @@ VmUveEntry::~VmUveEntry() {

void VmUveEntry::UpdatePortBitmap(uint8_t proto, uint16_t sport,
uint16_t dport) {
tbb::mutex::scoped_lock lock(mutex_);
if (deleted_ && !renewed_) {
/* Skip updates on VmUveEntry if it is marked for delete */
return;
}
//Update VM bitmap
port_bitmap_.AddPort(proto, sport, dport);

Expand All @@ -32,6 +37,7 @@ void VmUveEntry::UpdatePortBitmap(uint8_t proto, uint16_t sport,

bool VmUveEntry::SetVmPortBitmap(UveVirtualMachineAgent *uve) {
bool changed = false;
tbb::mutex::scoped_lock lock(mutex_);

vector<uint32_t> tcp_sport;
if (port_bitmap_.tcp_sport_.Sync(tcp_sport)) {
Expand Down
2 changes: 1 addition & 1 deletion src/vnsw/agent/uve/vm_uve_entry_base.cc
Expand Up @@ -9,7 +9,7 @@ using namespace std;

VmUveEntryBase::VmUveEntryBase(Agent *agent, const string &vm_name)
: agent_(agent), interface_tree_(), uve_info_(), changed_(true),
deleted_(false), renewed_(false), add_by_vm_notify_(false),
deleted_(false), renewed_(false), mutex_(), add_by_vm_notify_(false),
vm_config_name_(vm_name), vm_name_() {
}

Expand Down
3 changes: 3 additions & 0 deletions src/vnsw/agent/uve/vm_uve_entry_base.h
Expand Up @@ -9,6 +9,7 @@
#include <vector>
#include <set>
#include <map>
#include <tbb/mutex.h>
#include <sandesh/sandesh_types.h>
#include <sandesh/sandesh_constants.h>
#include <sandesh/sandesh.h>
Expand Down Expand Up @@ -54,6 +55,8 @@ class VmUveEntryBase {
bool changed_;
bool deleted_;
bool renewed_;
/* For exclusion between kTaskFlowStatsCollector and Agent::Uve */
tbb::mutex mutex_;
private:
bool UveVmInterfaceListChanged
(const std::vector<std::string> &new_l) const;
Expand Down
1 change: 1 addition & 0 deletions src/vnsw/agent/uve/vm_uve_table.cc
Expand Up @@ -22,6 +22,7 @@ VmUveTable::~VmUveTable() {

void VmUveTable::UpdateBitmap(const VmEntry* vm, uint8_t proto,
uint16_t sport, uint16_t dport) {
tbb::mutex::scoped_lock lock(uve_vm_map_mutex_);
UveVmMap::iterator it = uve_vm_map_.find(vm->GetUuid());
if (it != uve_vm_map_.end()) {
VmUveEntry *entry = static_cast<VmUveEntry *>(it->second.get());
Expand Down
3 changes: 2 additions & 1 deletion src/vnsw/agent/uve/vm_uve_table_base.cc
Expand Up @@ -7,7 +7,7 @@
#include <uve/agent_uve_base.h>

VmUveTableBase::VmUveTableBase(Agent *agent, uint32_t default_intvl)
: uve_vm_map_(), agent_(agent),
: uve_vm_map_(), agent_(agent), uve_vm_map_mutex_(),
intf_listener_id_(DBTableBase::kInvalidId),
vm_listener_id_(DBTableBase::kInvalidId), timer_last_visited_(nil_uuid()),
timer_(TimerManager::CreateTimer
Expand Down Expand Up @@ -40,6 +40,7 @@ bool VmUveTableBase::TimerExpiry() {
if (entry->deleted()) {
SendVmDeleteMsg(entry->vm_config_name());
if (!entry->renewed()) {
tbb::mutex::scoped_lock lock(uve_vm_map_mutex_);
uve_vm_map_.erase(prev);
} else {
entry->set_deleted(false);
Expand Down
2 changes: 2 additions & 0 deletions src/vnsw/agent/uve/vm_uve_table_base.h
Expand Up @@ -61,6 +61,8 @@ class VmUveTableBase {

UveVmMap uve_vm_map_;
Agent *agent_;
/* For exclusion between kTaskFlowStatsCollector and kTaskDBExclude */
tbb::mutex uve_vm_map_mutex_;
private:
virtual VmUveEntryPtr Allocate(const VmEntry *vm);
void InterfaceNotify(DBTablePartBase *partition, DBEntryBase *e);
Expand Down
10 changes: 10 additions & 0 deletions src/vnsw/agent/uve/vn_uve_entry.cc
Expand Up @@ -22,12 +22,21 @@ VnUveEntry::~VnUveEntry() {

void VnUveEntry::UpdatePortBitmap(uint8_t proto, uint16_t sport,
uint16_t dport) {
tbb::mutex::scoped_lock lock(mutex_);
if (deleted_ && !renewed_) {
/* Skip updates on VnUveEntry if it is marked for delete */
return;
}
port_bitmap_.AddPort(proto, sport, dport);
}

void VnUveEntry::UpdateInterVnStats(const string &dst_vn, uint64_t bytes,
uint64_t pkts, bool outgoing) {
tbb::mutex::scoped_lock lock(mutex_);
if (deleted_ && !renewed_) {
/* Skip updates on VnUveEntry if it is marked for delete */
return;
}
VnStatsPtr key(new VnStats(dst_vn, 0, 0, false));
VnStatsSet::iterator stats_it = inter_vn_stats_.find(key);
if (stats_it == inter_vn_stats_.end()) {
Expand Down Expand Up @@ -64,6 +73,7 @@ void VnUveEntry::ClearInterVnStats() {

bool VnUveEntry::SetVnPortBitmap(UveVirtualNetworkAgent &uve) {
bool changed = false;
tbb::mutex::scoped_lock lock(mutex_);

vector<uint32_t> tcp_sport;
if (port_bitmap_.tcp_sport_.Sync(tcp_sport)) {
Expand Down
1 change: 1 addition & 0 deletions src/vnsw/agent/uve/vn_uve_entry.h
Expand Up @@ -113,6 +113,7 @@ class VnUveEntry : public VnUveEntryBase {
void BuildArpStats(const StatsManager::VrfStats *s,
UveVrfStats &vrf_stats) const;

/* For exclusion between kTaskFlowStatsCollector and Agent::Uve */
tbb::mutex mutex_;
uint64_t in_bytes_;
uint64_t out_bytes_;
Expand Down
2 changes: 2 additions & 0 deletions src/vnsw/agent/uve/vn_uve_table.cc
Expand Up @@ -86,6 +86,7 @@ void VnUveTable::SendVnStatsMsg(const VnEntry *vn, bool only_vrf_stats) {

void VnUveTable::UpdateBitmap(const string &vn, uint8_t proto, uint16_t sport,
uint16_t dport) {
tbb::mutex::scoped_lock lock(uve_vn_map_mutex_);
UveVnMap::iterator it = uve_vn_map_.find(vn);
if (it == uve_vn_map_.end()) {
return;
Expand All @@ -98,6 +99,7 @@ void VnUveTable::UpdateBitmap(const string &vn, uint8_t proto, uint16_t sport,
void VnUveTable::UpdateInterVnStats(const string &src, const string &dst,
uint64_t bytes, uint64_t pkts,
bool outgoing) {
tbb::mutex::scoped_lock lock(uve_vn_map_mutex_);
UveVnMap::iterator it = uve_vn_map_.find(src);
if (it == uve_vn_map_.end()) {
return;
Expand Down
3 changes: 2 additions & 1 deletion src/vnsw/agent/uve/vn_uve_table_base.cc
Expand Up @@ -6,7 +6,7 @@
#include <uve/agent_uve_base.h>

VnUveTableBase::VnUveTableBase(Agent *agent, uint32_t default_intvl)
: uve_vn_map_(), agent_(agent),
: uve_vn_map_(), agent_(agent), uve_vn_map_mutex_(),
vn_listener_id_(DBTableBase::kInvalidId),
intf_listener_id_(DBTableBase::kInvalidId),
timer_last_visited_(""),
Expand Down Expand Up @@ -148,6 +148,7 @@ void VnUveTableBase::SendDeleteVnMsg(const string &vn) {
void VnUveTableBase::Delete(const std::string &name) {
UveVnMap::iterator it = uve_vn_map_.find(name);
if (it != uve_vn_map_.end()) {
tbb::mutex::scoped_lock lock(uve_vn_map_mutex_);
uve_vn_map_.erase(it);
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/vnsw/agent/uve/vn_uve_table_base.h
Expand Up @@ -39,6 +39,7 @@ class VnUveTableBase {
void Shutdown(void);
void SendVnAclRuleCount();
bool TimerExpiry();
void DeleteVnEntry(const UveVnMap::iterator &it);

protected:
void Delete(const std::string &name);
Expand All @@ -51,6 +52,8 @@ class VnUveTableBase {

UveVnMap uve_vn_map_;
Agent *agent_;
/* For exclusion between kTaskFlowStatsCollector and kTaskDBExclude */
tbb::mutex uve_vn_map_mutex_;
private:
VnUveEntryBase* Add(const VnEntry *vn);
void Add(const std::string &vn);
Expand Down
2 changes: 1 addition & 1 deletion src/vnsw/agent/vrouter/flow_stats/flow_stats_collector.h
Expand Up @@ -27,7 +27,7 @@ class FlowStatsManager;
//Defines the functionality to periodically read flow stats from
//shared memory (between agent and Kernel) and export this stats info to
//collector. Also responsible for aging of flow entries. Runs in the context
//of "Agent::StatsCollector" which has exclusion with "db::DBTable",
//of kTaskFlowStatsCollector which has exclusion with "db::DBTable",
class FlowStatsCollector : public StatsCollector {
public:
static const uint64_t FlowAgeTime = 1000000 * 180;
Expand Down

0 comments on commit 4de3a4e

Please sign in to comment.