Skip to content

Commit

Permalink
Handle case where multiple gratuitous ARP entries exist for a key.
Browse files Browse the repository at this point in the history
When scale out SIs are present in the compute, there could be multiple
gratuitous ARP entries for the same IP. Handle multiple entries.

Change-Id: I83f1ebb5434895cdd35334096e073705abc47ef4
closes-bug: #1668790
(cherry picked from commit aa03791)
  • Loading branch information
haripk committed Apr 11, 2017
1 parent e481bee commit b61eaa1
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 33 deletions.
24 changes: 17 additions & 7 deletions src/vnsw/agent/services/arp_handler.cc
Expand Up @@ -249,15 +249,24 @@ bool ArpHandler::HandleMessage() {

case ArpProto::ARP_SEND_GRATUITOUS: {
bool key_valid = false;
ArpProto::ArpIterator it =
arp_proto->GratiousArpEntryIterator(ipc->key, &key_valid);
ArpProto::GratuitousArpIterator it =
arp_proto->GratuitousArpEntryIterator(ipc->key, &key_valid);
if (key_valid && !ipc->interface->IsDeleted()) {
if (it->second == NULL) {
it->second = new ArpEntry(io_, this, ipc->key, ipc->key.vrf,
ArpEntry::ACTIVE, ipc->interface.get());
ArpEntry *entry = NULL;
ArpProto::ArpEntrySet::iterator sit = it->second.begin();
for (; sit != it->second.end(); sit++) {
entry = *sit;
if (entry->interface() == ipc->interface.get())
break;
}
if (sit == it->second.end()) {
entry = new ArpEntry(io_, this, ipc->key, ipc->key.vrf,
ArpEntry::ACTIVE, ipc->interface.get());
it->second.insert(entry);
ret = false;
}
it->second->SendGratuitousArp();
if (entry)
entry->SendGratuitousArp();
break;
}
}
Expand All @@ -284,7 +293,8 @@ bool ArpHandler::HandleMessage() {
}

case ArpProto::GRATUITOUS_TIMER_EXPIRED: {
ArpEntry *entry = arp_proto->GratiousArpEntry(ipc->key);
ArpEntry *entry =
arp_proto->GratuitousArpEntry(ipc->key, ipc->interface.get());
if (entry && entry->retry_count() <= ArpProto::kGratRetries) {
entry->SendGratuitousArp();
} else {
Expand Down
63 changes: 42 additions & 21 deletions src/vnsw/agent/services/arp_proto.cc
Expand Up @@ -43,13 +43,16 @@ void ArpProto::Shutdown() {
it = DeleteArpEntry(it);
}

for (ArpIterator it = gratuitous_arp_cache_.begin();
it != gratuitous_arp_cache_.end();) {
ArpEntry *entry = it->second;
gratuitous_arp_cache_.erase(it++);
if (entry)
for (GratuitousArpIterator it = gratuitous_arp_cache_.begin();
it != gratuitous_arp_cache_.end(); it++) {
for (ArpEntrySet::iterator sit = it->second.begin();
sit != it->second.end();) {
ArpEntry *entry = *sit;
it->second.erase(sit++);
delete entry;
}
}
gratuitous_arp_cache_.clear();
agent_->vrf_table()->Unregister(vrf_table_listener_id_);
agent_->interface_table()->Unregister(interface_table_listener_id_);
agent_->nexthop_table()->Unregister(nexthop_table_listener_id_);
Expand Down Expand Up @@ -372,8 +375,14 @@ void ArpVrfState::RouteUpdate(DBTablePartBase *part, DBEntryBase *entry) {
ArpDBState *state =
static_cast<ArpDBState *>
(entry->GetState(part->parent(), route_table_listener_id));

const InterfaceNH *intf_nh = dynamic_cast<const InterfaceNH *>(
route->GetActiveNextHop());
const Interface *intf = (intf_nh) ?
static_cast<const Interface *>(intf_nh->GetInterface()) : NULL;

ArpKey key(route->addr().to_v4().to_ulong(), route->vrf());
ArpEntry *arpentry = arp_proto->GratiousArpEntry(key);
ArpEntry *arpentry = arp_proto->GratuitousArpEntry(key, intf);
if (entry->IsDeleted() || deleted) {
if (state) {
arp_proto->DeleteGratuitousArpEntry(arpentry);
Expand All @@ -391,18 +400,15 @@ void ArpVrfState::RouteUpdate(DBTablePartBase *part, DBEntryBase *entry) {
}

if (route->vrf()->GetName() == agent->fabric_vrf_name() &&
route->GetActiveNextHop()->GetType() == NextHop::RECEIVE) {
route->GetActiveNextHop()->GetType() == NextHop::RECEIVE &&
arp_proto->agent()->router_id() == route->addr().to_v4()) {
//Send Grat ARP
arp_proto->AddGratuitousArpEntry(key);
arp_proto->SendArpIpc(ArpProto::ARP_SEND_GRATUITOUS,
route->addr().to_v4().to_ulong(), route->vrf(),
arp_proto->ip_fabric_interface());
} else {
const InterfaceNH *intf_nh = dynamic_cast<const InterfaceNH *>(
route->GetActiveNextHop());
if (intf_nh) {
const Interface *intf =
static_cast<const Interface *>(intf_nh->GetInterface());
if (!intf->IsDeleted() && intf->type() == Interface::VM_INTERFACE) {
ArpKey intf_key(route->addr().to_v4().to_ulong(), route->vrf());
arp_proto->AddGratuitousArpEntry(intf_key);
Expand Down Expand Up @@ -612,37 +618,52 @@ void ArpProto::NextHopNotify(DBEntryBase *entry) {

bool ArpProto::TimerExpiry(ArpKey &key, uint32_t timer_type,
const Interface* itf) {
if (arp_cache_.find(key) != arp_cache_.end())
if (arp_cache_.find(key) != arp_cache_.end()) {
SendArpIpc((ArpProto::ArpMsgType)timer_type, key, itf);
}
return false;
}

void ArpProto::AddGratuitousArpEntry(ArpKey &key) {
gratuitous_arp_cache_.insert(ArpCachePair(key, NULL));
ArpEntrySet empty_set;
gratuitous_arp_cache_.insert(GratuitousArpCachePair(key, empty_set));
}

void ArpProto::DeleteGratuitousArpEntry(ArpEntry *entry) {
if (!entry)
return ;

ArpProto::ArpIterator iter = gratuitous_arp_cache_.find(entry->key());
ArpProto::GratuitousArpIterator iter = gratuitous_arp_cache_.find(entry->key());
if (iter == gratuitous_arp_cache_.end()) {
return;
}
gratuitous_arp_cache_.erase(iter);

iter->second.erase(entry);
delete entry;
if (iter->second.empty()) {
gratuitous_arp_cache_.erase(iter);
}
}

ArpEntry *
ArpProto::GratiousArpEntry(const ArpKey &key) {
ArpProto::ArpIterator it = gratuitous_arp_cache_.find(key);
ArpProto::GratuitousArpEntry(const ArpKey &key, const Interface *intf) {
ArpProto::GratuitousArpIterator it = gratuitous_arp_cache_.find(key);
if (it == gratuitous_arp_cache_.end())
return NULL;
return it->second;

for (ArpEntrySet::iterator sit = it->second.begin();
sit != it->second.end(); sit++) {
ArpEntry *entry = *sit;
if (entry->interface() == intf)
return *sit;
}

return NULL;
}
ArpProto::ArpIterator
ArpProto::GratiousArpEntryIterator(const ArpKey &key, bool *key_valid) {
ArpProto::ArpIterator it = gratuitous_arp_cache_.find(key);

ArpProto::GratuitousArpIterator
ArpProto::GratuitousArpEntryIterator(const ArpKey &key, bool *key_valid) {
ArpProto::GratuitousArpIterator it = gratuitous_arp_cache_.find(key);
if (it == gratuitous_arp_cache_.end())
return it;
const VrfEntry *vrf = key.vrf;
Expand Down
13 changes: 9 additions & 4 deletions src/vnsw/agent/services/arp_proto.h
Expand Up @@ -28,6 +28,10 @@ class ArpProto : public Proto {
typedef std::pair<ArpKey, ArpEntry *> ArpCachePair;
typedef std::map<ArpKey, ArpEntry *>::iterator ArpIterator;
typedef std::set<ArpKey> ArpKeySet;
typedef std::set<ArpEntry *> ArpEntrySet;
typedef std::map<ArpKey, ArpEntrySet> GratuitousArpCache;
typedef std::pair<ArpKey, ArpEntrySet> GratuitousArpCachePair;
typedef std::map<ArpKey, ArpEntrySet>::iterator GratuitousArpIterator;

enum ArpMsgType {
ARP_RESOLVE,
Expand Down Expand Up @@ -92,6 +96,7 @@ class ArpProto : public Proto {
ArpEntry *FindArpEntry(const ArpKey &key);
std::size_t GetArpCacheSize() { return arp_cache_.size(); }
const ArpCache& arp_cache() { return arp_cache_; }
const GratuitousArpCache& gratuitous_arp_cache() { return gratuitous_arp_cache_; }
const InterfaceArpMap& interface_arp_map() { return interface_arp_map_; }

Interface *ip_fabric_interface() const { return ip_fabric_interface_; }
Expand All @@ -111,9 +116,9 @@ class ArpProto : public Proto {

void AddGratuitousArpEntry(ArpKey &key);
void DeleteGratuitousArpEntry(ArpEntry *entry);
ArpEntry* GratiousArpEntry (const ArpKey &key);
ArpProto::ArpIterator GratiousArpEntryIterator(const ArpKey & key,
bool *key_valid);
ArpEntry* GratuitousArpEntry (const ArpKey &key, const Interface *intf);
ArpProto::GratuitousArpIterator
GratuitousArpEntryIterator(const ArpKey &key, bool *key_valid);
void IncrementStatsArpReq() { arp_stats_.arp_req++; }
void IncrementStatsArpReplies() { arp_stats_.arp_replies++; }
void IncrementStatsGratuitous() { arp_stats_.arp_gratuitous++; }
Expand Down Expand Up @@ -174,7 +179,7 @@ class ArpProto : public Proto {

ArpCache arp_cache_;
ArpStats arp_stats_;
ArpCache gratuitous_arp_cache_;
GratuitousArpCache gratuitous_arp_cache_;
bool run_with_vrouter_;
uint32_t ip_fabric_interface_index_;
MacAddress ip_fabric_interface_mac_;
Expand Down
9 changes: 8 additions & 1 deletion src/vnsw/agent/services/services.sandesh
Expand Up @@ -674,14 +674,21 @@ struct ArpSandeshData {
2: string vrf; // VRF name
3: string mac; // MAC Address
4: string state; // Active / Static / Permanent / Resolving
5: string interface_name; // interface
}

/**
* Request message to show cached arp
* Request message to show arp cache
*/
request sandesh ShowArpCache {
}

/**
* Request message to show gratuitous arp cache
*/
request sandesh ShowGratuitousArpCache {
}

/**
* Response message for cached arp
*/
Expand Down
20 changes: 20 additions & 0 deletions src/vnsw/agent/services/services_sandesh.cc
Expand Up @@ -1092,12 +1092,32 @@ void ShowArpCache::HandleRequest() const {
delete arp_sandesh;
}

void ShowGratuitousArpCache::HandleRequest() const {
ArpCacheResp *resp = new ArpCacheResp();
resp->set_context(context());
ArpSandesh *arp_sandesh = new ArpSandesh(resp);
const ArpProto::GratuitousArpCache &cache =
(Agent::GetInstance()->GetArpProto()->gratuitous_arp_cache());
for (ArpProto::GratuitousArpCache::const_iterator it = cache.begin();
it != cache.end(); it++) {
for (ArpProto::ArpEntrySet::iterator sit = it->second.begin();
sit != it->second.end(); sit++) {
arp_sandesh->SetArpEntry(it->first, *sit);
}
}

arp_sandesh->Response();
delete arp_sandesh;
}

bool ArpSandesh::SetArpEntry(const ArpKey &key, const ArpEntry *entry) {
ArpCacheResp *vresp = static_cast<ArpCacheResp *>(resp_);
ArpSandeshData data;
boost::asio::ip::address_v4 ip(key.ip);
data.set_ip(ip.to_string());
data.set_vrf(key.vrf->GetName());
if (entry->interface())
data.set_interface_name(entry->interface()->name());
std::string mac_str;
ServicesSandesh::MacToString(entry->mac_address(), mac_str);
data.set_mac(mac_str);
Expand Down

0 comments on commit b61eaa1

Please sign in to comment.