diff --git a/src/vnsw/agent/services/arp_handler.cc b/src/vnsw/agent/services/arp_handler.cc index 414f4254ba4..754f0ff8dba 100644 --- a/src/vnsw/agent/services/arp_handler.cc +++ b/src/vnsw/agent/services/arp_handler.cc @@ -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; } } @@ -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 { diff --git a/src/vnsw/agent/services/arp_proto.cc b/src/vnsw/agent/services/arp_proto.cc index f41f51c9b72..0d5a3a12d9e 100644 --- a/src/vnsw/agent/services/arp_proto.cc +++ b/src/vnsw/agent/services/arp_proto.cc @@ -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_); @@ -372,8 +375,14 @@ void ArpVrfState::RouteUpdate(DBTablePartBase *part, DBEntryBase *entry) { ArpDBState *state = static_cast (entry->GetState(part->parent(), route_table_listener_id)); + + const InterfaceNH *intf_nh = dynamic_cast( + route->GetActiveNextHop()); + const Interface *intf = (intf_nh) ? + static_cast(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); @@ -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( - route->GetActiveNextHop()); if (intf_nh) { - const Interface *intf = - static_cast(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); @@ -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; diff --git a/src/vnsw/agent/services/arp_proto.h b/src/vnsw/agent/services/arp_proto.h index 1b840282fff..bd1322cf130 100644 --- a/src/vnsw/agent/services/arp_proto.h +++ b/src/vnsw/agent/services/arp_proto.h @@ -28,6 +28,10 @@ class ArpProto : public Proto { typedef std::pair ArpCachePair; typedef std::map::iterator ArpIterator; typedef std::set ArpKeySet; + typedef std::set ArpEntrySet; + typedef std::map GratuitousArpCache; + typedef std::pair GratuitousArpCachePair; + typedef std::map::iterator GratuitousArpIterator; enum ArpMsgType { ARP_RESOLVE, @@ -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_; } @@ -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++; } @@ -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_; diff --git a/src/vnsw/agent/services/services.sandesh b/src/vnsw/agent/services/services.sandesh index 5078201518a..04cdc7d37cf 100644 --- a/src/vnsw/agent/services/services.sandesh +++ b/src/vnsw/agent/services/services.sandesh @@ -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 */ diff --git a/src/vnsw/agent/services/services_sandesh.cc b/src/vnsw/agent/services/services_sandesh.cc index 20b0a65c48a..1eea872b5df 100644 --- a/src/vnsw/agent/services/services_sandesh.cc +++ b/src/vnsw/agent/services/services_sandesh.cc @@ -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(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);