From 9d44b8f521cf02f70ecb7cd628754c64b8de3b9a Mon Sep 17 00:00:00 2001 From: Hari Date: Tue, 3 Mar 2015 21:29:48 -0800 Subject: [PATCH] Merge the following commits from R2.1 branch (final). Perf improvements for Logical Interface delete handling Follow up on commit b4af4d67cef56ac85da5bb0d50bb55f882c70538 for delete handling When a link delete is notified to config listener, the IFMapNode in link can be NULL. We used to ignore links with left/right node deleted. Modified the link handler to pass the node-type when left/right node is deleted. This way, the IFLinkToReq handler can take action based on the type of node being deleted (cherry picked from commit f1d7816dbdc886859caec5152d2b436ad4fb2a96) Conflicts: src/vnsw/agent/test-xml/test_xml_oper.cc Holding the UUID from ID_PERMS in config DBState in DB Add and using it for Config Delete closes-bug: #1420209 (cherry picked from commit 6a9b4be6a0dcfb3980bd072a57f92761a548eb9c) * Send ARP request packet on VMI interface instead of parent interface such that vlan gets added, based on transmit vlan id * If vlan-id is 0, then its treated as untagged interface, in agent while framing the packet we were setting the tag in packet 0 avoiding the same same setting vlan id as invalid and programming it as vlan-id 0 only in vrouter Closes-bug:#1423122 (cherry picked from commit 38f1405b27e05e5d31a2ae6297ca42d915b368bd) * If arp route is deleted twice, then we arp nexthop was not getting deleted, since upon each arp route delete we enqueue a request to modify nexthop to invalid and this might result in arp entry creation, hence use operation RESYNC instead of add/change * Check for vrf while parsing on subnet address change, since we might modify next vrf subnet routes if prefixx matches Test case for same Closes-bug:#1423502 (cherry picked from commit a65d557c27d15de5d7d0bf30fdc5a20fa93acf42) Conflicts: src/vnsw/agent/test/test_route.cc reverting the unwated checkin of modifying the notify_count_ to bool (cherry picked from commit 975f507d81ce89106814f4fced1d14b454dcdd5a) * Whenever ICMP error packet is trapped for flow setup, parse the inner payload and frame the flow key Closes-bug:#1423848 (cherry picked from commit 81ee64728201b1d8234d790772ab3035874c1f5d) * ARP route behind gateway should have proxy flag set such that arp request on VM would be proxied by vrouter Closes-bug:#1423122 (cherry picked from commit e72443e1a73d3372944981f15941e97a5a9f439f) Remove unused UVEs Remove UVE generated on add/delete of a link Remove UVE generated on change of physical-device-vn entry. Added a UT for physical-device-vn to validate add/delete of VMI to VN link (cherry picked from commit 452b9341668f0a89455cc5e1847c0c7d70f0d3b2) Holding the metadata of link while storing it in defer list. While adding the link to Graph from defer list, the metadata also added back to graph which makes the dependency tracker to work correctly (cherry picked from commit 43d7a71e1c486a3c326d16e16134c25312b4953f) Optimize config handling for SG and ACL Follow up to commit https://github.com/Juniper/contrail-controller/commit/b4af4d67cef56ac85da5bb0d50bb55f882c70538 On any change or link add/delete to a SG, we are invoking IFNodeToReq for all connected VMI. Fix this by registering link handler for SG and invoke IFNodeToReq only for peer VMI On any change or link add/delete to a ACL, we are invoking IFNodeToReq for all connected SG and VN. Fix this by registering link handler for ACL and invoke IFNodeToReq only for peer SG / VN (cherry picked from commit 0d33ec13e576165f68ff172a62b6dfb8cc73774f) * In a scenario where there are 2 vgw exporting same subnet route, and traffic session gets initiated from external domain to VM, then for setting reverse flow agent was trying to get policy enabled interface nexthop for vgw, and for vgw we would only create policy disabled nh. Fixing the same to pick policy disabled nexthop for vgw destination Closes-bug:#1425856 (cherry picked from commit f000a7fcd9c99fff809c87d3f30ed7e162ace1a8) Fix Tor-Agent assert for KSyncEntry GetReference Issue: ------ On connection close delete is triggered for all the KSync Objects, creation of entry after this deletion in not allowed. Here Logical Switch Object is deleted and Unicast Remote Entry Table is yet to receive a delete, in the meanwhile a route table entry get notified and tries to take create a temp entry for reference in Logical Switch Entry which is already deleted Fix: ---- Since delete trigger for Unicast Remote Entry Table happens in context of VRF table walk, which will have a yeild in between. during this time if a notification for route table happens, it needs to be ignored. Also fixing a memory leak in idl deletion path Closes-Bug: 1424531 (cherry picked from commit d4ba9892ae816dc0b4d59d6dd7e3350d3b3a1745) DHCP enable/disable bug fixes 1) Fix bug where dhcp enable flag toggling was not reflected in route - Toggling of DHCP enable in interface results in route rebake. Also flag for handle_dhcp is now moved from path to route. 2) Remove mac VM binding, instead add a route with DHCP peer path which can be used to get binding. This path is having discard NH. Closes-bug: #1417131 Conflicts: src/vnsw/agent/oper/operdb_init.h src/vnsw/agent/test-xml/test_xml_oper.cc src/vnsw/agent/test/test_route.cc Rename Dhcp path/peer to MacVmBinding. Change-Id: I0643612ca907b85c548d4132502e00ca1498fdc1 --- src/ifmap/ifmap_agent.sandesh | 1 + src/ifmap/ifmap_agent_sandesh.cc | 13 +- src/ifmap/ifmap_agent_table.cc | 83 ++++--- src/ifmap/ifmap_agent_table.h | 10 +- src/ifmap/ifmap_link_table.cc | 2 - src/vnsw/agent/cfg/cfg_filter.cc | 35 ++- src/vnsw/agent/cfg/cfg_init.cc | 31 ++- src/vnsw/agent/cfg/cfg_init.h | 20 ++ src/vnsw/agent/cfg/cfg_listener.cc | 60 +++-- src/vnsw/agent/cfg/cfg_listener.h | 10 +- src/vnsw/agent/cmn/agent.cc | 2 + src/vnsw/agent/cmn/agent.h | 2 + src/vnsw/agent/cmn/agent_db.cc | 4 + src/vnsw/agent/cmn/agent_db.h | 5 +- src/vnsw/agent/filter/acl.cc | 30 ++- src/vnsw/agent/filter/acl.h | 4 + src/vnsw/agent/kstate/test/test_kstate.cc | 2 - src/vnsw/agent/oper/SConscript | 1 - src/vnsw/agent/oper/agent.sandesh | 1 + src/vnsw/agent/oper/agent_path.cc | 57 ++++- src/vnsw/agent/oper/agent_path.h | 49 ++++ src/vnsw/agent/oper/bridge_route.cc | 130 +++++++---- src/vnsw/agent/oper/bridge_route.h | 18 +- src/vnsw/agent/oper/evpn_route.cc | 36 --- src/vnsw/agent/oper/evpn_route.h | 5 - .../agent/oper/ifmap_dependency_manager.cc | 88 +++----- .../agent/oper/ifmap_dependency_manager.h | 51 ++++- src/vnsw/agent/oper/inet_unicast_route.cc | 10 +- src/vnsw/agent/oper/interface.cc | 12 + src/vnsw/agent/oper/interface.h | 6 +- src/vnsw/agent/oper/loadbalancer.cc | 27 ++- src/vnsw/agent/oper/loadbalancer.h | 8 +- src/vnsw/agent/oper/logical_interface.cc | 23 +- src/vnsw/agent/oper/mac_vm_binding.cc | 83 ------- src/vnsw/agent/oper/mac_vm_binding.h | 45 ---- src/vnsw/agent/oper/multicast.cc | 6 +- src/vnsw/agent/oper/oper_db.h | 77 +++++-- src/vnsw/agent/oper/operdb_init.cc | 2 + src/vnsw/agent/oper/operdb_init.h | 1 - src/vnsw/agent/oper/peer.h | 4 +- src/vnsw/agent/oper/physical_device.cc | 21 +- src/vnsw/agent/oper/physical_device.h | 1 + src/vnsw/agent/oper/physical_device_vn.cc | 2 - src/vnsw/agent/oper/service_instance.cc | 22 +- src/vnsw/agent/oper/service_instance.h | 7 + src/vnsw/agent/oper/sg.cc | 36 ++- src/vnsw/agent/oper/sg.h | 4 + .../test/ifmap_dependency_manager_test.cc | 2 +- src/vnsw/agent/oper/test/loadbalancer_test.cc | 5 +- .../agent/oper/test/physical-device-vn.xml | 117 +++++++++- src/vnsw/agent/oper/test/test_intf.cc | 23 ++ src/vnsw/agent/oper/vm.cc | 15 +- src/vnsw/agent/oper/vm.h | 1 + src/vnsw/agent/oper/vm_interface.cc | 141 ++++++------ src/vnsw/agent/oper/vm_interface.h | 12 +- src/vnsw/agent/oper/vn.cc | 59 +++-- src/vnsw/agent/oper/vn.h | 12 +- src/vnsw/agent/oper/vrf.cc | 36 +-- src/vnsw/agent/oper/vrf.h | 3 +- .../ovsdb_client/ovsdb_client_idl.cc | 8 +- .../ovsdb_client/ovsdb_client_idl.h | 1 + .../ovsdb_client/ovsdb_route_peer.cc | 6 +- .../ovsdb_client/unicast_mac_remote_ovsdb.cc | 11 + .../ovsdb_client/unicast_mac_remote_ovsdb.h | 3 + .../agent/ovs_tor_agent/tor_agent_init.cc | 3 +- src/vnsw/agent/pkt/flow_table.cc | 2 +- src/vnsw/agent/pkt/pkt_flow_info.cc | 15 +- src/vnsw/agent/pkt/pkt_handler.cc | 31 ++- src/vnsw/agent/pkt/pkt_handler.h | 16 -- src/vnsw/agent/pkt/test/test_ecmp.cc | 61 +++++ src/vnsw/agent/services/arp_entry.cc | 2 +- src/vnsw/agent/services/arp_proto.cc | 16 +- src/vnsw/agent/services/test/arp_test.cc | 132 +++++++++++ src/vnsw/agent/test-xml/test_xml_oper.cc | 6 +- src/vnsw/agent/test/test_cfg.cc | 211 +++++++++++++++++- src/vnsw/agent/test/test_route.cc | 174 ++++++++++++++- src/vnsw/agent/test/test_util.cc | 25 ++- src/vnsw/agent/test/test_vn.cc | 127 +++++++++++ src/vnsw/agent/uve/agent_uve.cc | 2 +- src/vnsw/agent/uve/agent_uve_base.cc | 11 +- src/vnsw/agent/uve/agent_uve_base.h | 2 +- src/vnsw/agent/uve/prouter_uve_table.cc | 7 +- src/vnsw/agent/uve/test/agent_uve_test.cc | 12 + src/vnsw/agent/uve/vm_uve_table_base.cc | 6 +- src/vnsw/agent/uve/vn_uve_table_base.cc | 6 +- src/vnsw/agent/uve/vrouter_uve_entry_base.cc | 135 ++++++++--- src/vnsw/agent/uve/vrouter_uve_entry_base.h | 19 +- .../agent/vrouter/ksync/interface_ksync.cc | 22 +- src/vnsw/agent/vrouter/ksync/route_ksync.cc | 34 ++- .../linux/linux_vxlan_agent_init.cc | 3 +- 90 files changed, 2022 insertions(+), 660 deletions(-) delete mode 100644 src/vnsw/agent/oper/mac_vm_binding.cc delete mode 100644 src/vnsw/agent/oper/mac_vm_binding.h diff --git a/src/ifmap/ifmap_agent.sandesh b/src/ifmap/ifmap_agent.sandesh index 2aeffe4f36b..6ba45381255 100644 --- a/src/ifmap/ifmap_agent.sandesh +++ b/src/ifmap/ifmap_agent.sandesh @@ -19,6 +19,7 @@ struct IFMapAgentDefLink { 1: i64 seq_num; 2: string left_node; 3: string right_node; + 4: string metadata; } response sandesh ShowIFMapAgentDefLinkResp { diff --git a/src/ifmap/ifmap_agent_sandesh.cc b/src/ifmap/ifmap_agent_sandesh.cc index 8c6ef05f488..7d24f439878 100644 --- a/src/ifmap/ifmap_agent_sandesh.cc +++ b/src/ifmap/ifmap_agent_sandesh.cc @@ -288,8 +288,8 @@ void ShowIFMapAgentDefLinkReq::HandleRequest() const { ShowIFMapAgentTable::db_->FindTable(IFMAP_AGENT_LINK_DB_NAME)); IFMapAgentLinkTable::LinkDefMap::const_iterator dlist_it; - std::list *ent; - std::list::iterator it; + std::list *ent; + std::list::iterator it; //Get linktables's deferred list const IFMapAgentLinkTable::LinkDefMap &def_list = link_table->GetLinkDefMap(); @@ -306,9 +306,12 @@ void ShowIFMapAgentDefLinkReq::HandleRequest() const { //Iterate the right nodes corresponding to above left node for(it = ent->begin(); it != ent->end(); it++) { IFMapAgentDefLink data; - data.set_seq_num((*it).id_seq_num); - data.set_left_node(temp.id_type + ":" + temp.id_name); - data.set_right_node((*it).id_type + ":" + (*it).id_name); + data.set_seq_num((*it).node_key.id_seq_num); + data.set_left_node(temp.id_type + ":" + + temp.id_name); + data.set_metadata((*it).link_metadata); + data.set_right_node((*it).node_key.id_type + ":" + + (*it).node_key.id_name); list.push_back(data); } } diff --git a/src/ifmap/ifmap_agent_table.cc b/src/ifmap/ifmap_agent_table.cc index 1899191b403..3585f993d49 100644 --- a/src/ifmap/ifmap_agent_table.cc +++ b/src/ifmap/ifmap_agent_table.cc @@ -109,6 +109,7 @@ void IFMapAgentTable::HandlePendingLinks(IFMapNode *node) { iter++; edge = graph_->GetEdge(node, right); assert(edge); + IFMapLink *l = static_cast(edge); // Create both the request keys auto_ptr req_key (new IFMapAgentLinkTable::RequestKey); @@ -119,6 +120,7 @@ void IFMapAgentTable::HandlePendingLinks(IFMapNode *node) { req_key->right_key.id_name = right->name(); req_key->right_key.id_type = right->table()->Typename(); req_key->right_key.id_seq_num = right->GetObject()->sequence_number(); + req_key->metadata = l->metadata(); DBRequest req; req.oper = DBRequest::DB_ENTRY_ADD_CHANGE; @@ -159,14 +161,14 @@ void IFMapAgentTable::NotifyNode(IFMapNode *node) { void IFMapAgentLinkTable::LinkDefAdd(DBRequest *request) { RequestKey *key = static_cast(request->key.get()); - std::list::iterator it; + std::list::iterator it; - std::list *left = NULL; + std::list *left = NULL; LinkDefMap::iterator left_it = link_def_map_.find(key->left_key); if (link_def_map_.end() != left_it) left = left_it->second; - std::list *right = NULL; + std::list *right = NULL; LinkDefMap::iterator right_it = link_def_map_.find(key->right_key); if (link_def_map_.end() != right_it) right = right_it->second; @@ -175,8 +177,8 @@ void IFMapAgentLinkTable::LinkDefAdd(DBRequest *request) { // remove left->right entry if (left) { for(it = left->begin(); it != left->end(); it++) { - if (((*it).id_type == key->right_key.id_type) && - ((*it).id_name == key->right_key.id_name)) { + if (((*it).node_key.id_type == key->right_key.id_type) && + ((*it).node_key.id_name == key->right_key.id_name)) { left->erase(it); break; } @@ -187,8 +189,8 @@ void IFMapAgentLinkTable::LinkDefAdd(DBRequest *request) { // remove right->left entry if (right) { for(it = right->begin(); it != right->end(); it++) { - if (((*it).id_type == key->left_key.id_type) && - ((*it).id_name == key->left_key.id_name)) { + if (((*it).node_key.id_type == key->left_key.id_type) && + ((*it).node_key.id_name == key->left_key.id_name)) { right->erase(it); break; } @@ -205,15 +207,16 @@ void IFMapAgentLinkTable::LinkDefAdd(DBRequest *request) { if (left) { // If list already contains, just update the seq number for(it = left->begin(); it != left->end(); it++) { - if (((*it).id_type == key->right_key.id_type) && - ((*it).id_name == key->right_key.id_name)) { - (*it).id_seq_num = key->right_key.id_seq_num; + if (((*it).node_key.id_type == key->right_key.id_type) && + ((*it).node_key.id_name == key->right_key.id_name)) { + (*it).node_key.id_seq_num = key->right_key.id_seq_num; + (*it).link_metadata = key->metadata; push_left = false; break; } } } else { - left = new std::list(); + left = new std::list(); link_def_map_[key->left_key] = left; } @@ -222,23 +225,30 @@ void IFMapAgentLinkTable::LinkDefAdd(DBRequest *request) { if (right) { // If list already contains, just update the seq number for(it = right->begin(); it != right->end(); it++) { - if (((*it).id_type == key->left_key.id_type) && - ((*it).id_name == key->left_key.id_name)) { - (*it).id_seq_num = key->left_key.id_seq_num; + if (((*it).node_key.id_type == key->left_key.id_type) && + ((*it).node_key.id_name == key->left_key.id_name)) { + (*it).node_key.id_seq_num = key->left_key.id_seq_num; + (*it).link_metadata = key->metadata; push_right = false; break; } } } else { - right = new std::list(); + right = new std::list(); link_def_map_[key->right_key] = right; } // Add it to the end of the list - if (push_left) - left->push_back(key->right_key); - if (push_right) - right->push_back(key->left_key); + struct DeferredNode dn; + dn.link_metadata = key->metadata; + if (push_left) { + dn.node_key = key->right_key; + left->push_back(dn); + } + if (push_right) { + dn.node_key = key->left_key; + right->push_back(dn); + } return; } @@ -449,9 +459,9 @@ void IFMapAgentLinkTable::Input(DBTablePartition *partition, DBClient *client, bool IFMapAgentLinkTable::RemoveDefListEntry (LinkDefMap *map, LinkDefMap::iterator &map_it, - std::list::iterator *list_it) { + std::list::iterator *list_it) { - std::list *list = map_it->second; + std::list *list = map_it->second; if (list_it) { list->erase(*list_it); } @@ -475,36 +485,38 @@ void IFMapAgentLinkTable::EvalDefLink(IFMapTable::RequestKey *key) { if (link_def_map_.end() == link_defmap_it) return; - std::list *left_list = link_defmap_it->second; - std::list::iterator left_it, left_list_entry; + std::list *left_list = link_defmap_it->second; + std::list::iterator left_it, left_list_entry; for(left_it = left_list->begin(); left_it != left_list->end();) { left_list_entry = left_it++; // If link seq is older, dont consider the link. - if ((*left_list_entry).id_seq_num < key->id_seq_num) + if ((*left_list_entry).node_key.id_seq_num < key->id_seq_num) continue; // Skip if right-node is not yet present - if (IFMapAgentTable::TableEntryLookup(database(), &(*left_list_entry)) + if (IFMapAgentTable::TableEntryLookup(database(), + &((*left_list_entry).node_key)) == NULL) { continue; } // left->right entry found defer-list. Find the right->left entry - LinkDefMap::iterator right_defmap_it = link_def_map_.find(*left_list_entry); + LinkDefMap::iterator right_defmap_it = + link_def_map_.find((*left_list_entry).node_key); assert(link_def_map_.end() != right_defmap_it); - std::list *right_list = right_defmap_it->second; - std::list::iterator right_it, right_list_entry; + std::list *right_list = right_defmap_it->second; + std::list::iterator right_it, right_list_entry; for(right_it = right_list->begin(); right_it != right_list->end();) { right_list_entry = right_it++; // If link seq is older, dont consider the link. - if ((*right_list_entry).id_seq_num < key->id_seq_num) + if ((*right_list_entry).node_key.id_seq_num < key->id_seq_num) continue; - if ((*right_list_entry).id_type == key->id_type && - (*right_list_entry).id_name == key->id_name) { + if ((*right_list_entry).node_key.id_type == key->id_type && + (*right_list_entry).node_key.id_name == key->id_name) { RemoveDefListEntry(&link_def_map_, right_defmap_it, &right_list_entry); break; @@ -514,7 +526,8 @@ void IFMapAgentLinkTable::EvalDefLink(IFMapTable::RequestKey *key) { //Remove from deferred list before enqueing auto_ptr req_key (new RequestKey); req_key->left_key = *key; - req_key->right_key = *left_list_entry; + req_key->right_key = (*left_list_entry).node_key; + req_key->metadata = (*left_list_entry).link_metadata; // Dont delete left_list_entry. Its passed in req structure left_list->erase(left_list_entry); @@ -529,8 +542,8 @@ void IFMapAgentLinkTable::EvalDefLink(IFMapTable::RequestKey *key) { } void IFMapAgentLinkTable::DestroyDefLink(uint64_t seq) { - std::list *ent; - std::list::iterator it, list_entry; + std::list *ent; + std::list::iterator it, list_entry; IFMapAgentLinkTable::LinkDefMap::iterator dlist_it, temp; for(dlist_it = link_def_map_.begin(); dlist_it != link_def_map_.end(); ) { @@ -540,7 +553,7 @@ void IFMapAgentLinkTable::DestroyDefLink(uint64_t seq) { list_entry = it++; //Delete the deferred link if it is old seq - if ((*list_entry).id_seq_num < seq) { + if ((*list_entry).node_key.id_seq_num < seq) { if (RemoveDefListEntry(&link_def_map_, temp, &list_entry) == true) { //The list has been deleted. Move to the next map diff --git a/src/ifmap/ifmap_agent_table.h b/src/ifmap/ifmap_agent_table.h index 4752ea7d379..03c9716dbc0 100644 --- a/src/ifmap/ifmap_agent_table.h +++ b/src/ifmap/ifmap_agent_table.h @@ -29,6 +29,7 @@ class IFMapNode; class IFMapAgentTable : public IFMapTable { public: + struct IFMapAgentData : DBRequestData { std::auto_ptrcontent; }; @@ -66,6 +67,11 @@ class IFMapAgentLinkTable : public IFMapLinkTable { std::string metadata; }; + struct DeferredNode { + IFMapTable::RequestKey node_key; + std::string link_metadata; + }; + class comp { public: bool operator()(const IFMapTable::RequestKey &left, @@ -78,7 +84,7 @@ class IFMapAgentLinkTable : public IFMapLinkTable { }; IFMapAgentLinkTable(DB *db, const std::string &name, DBGraph *graph); - typedef std::map *, comp> LinkDefMap; + typedef std::map *, comp> LinkDefMap; virtual void Input(DBTablePartition *partition, DBClient *client, DBRequest *req); void IFMapAgentLinkTable_Init(DB *db, DBGraph *graph); @@ -86,7 +92,7 @@ class IFMapAgentLinkTable : public IFMapLinkTable { DBGraph *graph); void EvalDefLink(IFMapTable::RequestKey *key); bool RemoveDefListEntry(LinkDefMap *map, LinkDefMap::iterator &map_it, - std::list::iterator *list_it); + std::list::iterator *list_it); void DestroyDefLink(uint64_t); const LinkDefMap &GetLinkDefMap() const { return link_def_map_; diff --git a/src/ifmap/ifmap_link_table.cc b/src/ifmap/ifmap_link_table.cc index 0a38098cb46..7ac059511d1 100644 --- a/src/ifmap/ifmap_link_table.cc +++ b/src/ifmap/ifmap_link_table.cc @@ -66,7 +66,6 @@ void IFMapLinkTable::AddLink(DBGraphBase::edge_descriptor edge, } link->SetProperties(edge, left, right, metadata, sequence_number, origin); graph_->SetEdgeProperty(link); - IFMAP_DEBUG(IFMapLinkOperation, "Creating", link->ToString()); } IFMapLink *IFMapLinkTable::FindLink(const string &name) { @@ -80,7 +79,6 @@ IFMapLink *IFMapLinkTable::FindLink(const string &name) { void IFMapLinkTable::DeleteLink(DBGraphEdge *edge) { IFMapLink *link = static_cast(edge); - IFMAP_DEBUG(IFMapLinkOperation, "Deleting", link->ToString()); link->set_last_change_at_to_now(); link->ClearNodes(); DBTablePartition *partition = diff --git a/src/vnsw/agent/cfg/cfg_filter.cc b/src/vnsw/agent/cfg/cfg_filter.cc index 0189db3b9cf..7f2cc0a9354 100644 --- a/src/vnsw/agent/cfg/cfg_filter.cc +++ b/src/vnsw/agent/cfg/cfg_filter.cc @@ -66,23 +66,50 @@ bool CfgFilter::CheckProperty(DBTable *table, IFMapNode *node, DBRequest *req, void CfgFilter::Init() { agent_cfg_->cfg_vm_table()->RegisterPreFilter - (boost::bind(&CfgFilter::CheckProperty, this, _1, _2, _3, + (boost::bind(&CfgFilter::CheckProperty, this, _1, _2, _3, VirtualMachine::ID_PERMS)); agent_cfg_->cfg_vn_table()->RegisterPreFilter - (boost::bind(&CfgFilter::CheckProperty, this, _1, _2, _3, + (boost::bind(&CfgFilter::CheckProperty, this, _1, _2, _3, VirtualNetwork::ID_PERMS)); agent_cfg_->cfg_vm_interface_table()->RegisterPreFilter - (boost::bind(&CfgFilter::CheckProperty, this, _1, _2, _3, + (boost::bind(&CfgFilter::CheckProperty, this, _1, _2, _3, VirtualMachineInterface::ID_PERMS)); agent_cfg_->cfg_acl_table()->RegisterPreFilter - (boost::bind(&CfgFilter::CheckProperty, this, _1, _2, _3, + (boost::bind(&CfgFilter::CheckProperty, this, _1, _2, _3, AccessControlList::ID_PERMS)); + + agent_cfg_->cfg_loadbalancer_table()->RegisterPreFilter + (boost::bind(&CfgFilter::CheckProperty, this, _1, _2, _3, + LoadbalancerPool::ID_PERMS)); + + agent_cfg_->cfg_service_instance_table()->RegisterPreFilter + (boost::bind(&CfgFilter::CheckProperty, this, _1, _2, _3, + ServiceInstance::ID_PERMS)); + + agent_cfg_->cfg_security_group_table()->RegisterPreFilter + (boost::bind(&CfgFilter::CheckProperty, this, _1, _2, _3, + SecurityGroup::ID_PERMS)); + + agent_cfg_->cfg_logical_port_table()->RegisterPreFilter + (boost::bind(&CfgFilter::CheckProperty, this, _1, _2, _3, + LogicalInterface::ID_PERMS)); + + agent_cfg_->cfg_physical_device_table()->RegisterPreFilter + (boost::bind(&CfgFilter::CheckProperty, this, _1, _2, _3, + PhysicalRouter::ID_PERMS)); } void CfgFilter::Shutdown() { agent_cfg_->cfg_vm_table()->RegisterPreFilter(NULL); agent_cfg_->cfg_vn_table()->RegisterPreFilter(NULL); + agent_cfg_->cfg_vm_interface_table()->RegisterPreFilter(NULL); + agent_cfg_->cfg_acl_table()->RegisterPreFilter(NULL); + agent_cfg_->cfg_loadbalancer_table()->RegisterPreFilter(NULL); + agent_cfg_->cfg_service_instance_table()->RegisterPreFilter(NULL); + agent_cfg_->cfg_security_group_table()->RegisterPreFilter(NULL); + agent_cfg_->cfg_logical_port_table()->RegisterPreFilter(NULL); + agent_cfg_->cfg_physical_device_table()->RegisterPreFilter(NULL); } diff --git a/src/vnsw/agent/cfg/cfg_init.cc b/src/vnsw/agent/cfg/cfg_init.cc index c74f11982c5..3cb5ebe3920 100644 --- a/src/vnsw/agent/cfg/cfg_init.cc +++ b/src/vnsw/agent/cfg/cfg_init.cc @@ -128,9 +128,9 @@ void AgentConfig::RegisterDBClients(DB *db) { cfg_listener_->Register("virtual-network-network-ipam", boost::bind(&VnTable::IpamVnSync, _1), -1); cfg_listener_->Register("network-ipam", boost::bind(&DomainConfig::IpamSync, - agent_->domain_config_table(), _1), NetworkIpam::ID_PERMS); + agent_->domain_config_table(), _1), -1); cfg_listener_->Register("virtual-DNS", boost::bind(&DomainConfig::VDnsSync, - agent_->domain_config_table(), _1), VirtualDns::ID_PERMS); + agent_->domain_config_table(), _1), -1); cfg_listener_->Register ("virtual-machine-interface-routing-instance", boost::bind(&InterfaceTable::VmInterfaceVrfSync, @@ -162,6 +162,10 @@ void AgentConfig::RegisterDBClients(DB *db) { ("virtual-network", agent_->vn_table()); cfg_listener_->LinkRegister ("routing-instance", agent_->vrf_table()); + cfg_listener_->LinkRegister + ("security-group", agent_->sg_table()); + cfg_listener_->LinkRegister + ("access-control-list", agent_->acl_table()); cfg_vm_interface_table_ = (static_cast (IFMapTable::FindTable(agent_->db(), "virtual-machine-interface"))); @@ -214,10 +218,25 @@ void AgentConfig::RegisterDBClients(DB *db) { assert(cfg_vm_port_vrf_table_); cfg_route_table_ = (static_cast - (IFMapTable::FindTable(agent_->db(), + (IFMapTable::FindTable(agent_->db(), "interface-route-table"))); assert(cfg_route_table_); + cfg_loadbalancer_table_ = (static_cast + (IFMapTable::FindTable(agent_->db(), + "loadbalancer_pool"))); + assert(cfg_loadbalancer_table_); + + cfg_service_instance_table_ = (static_cast + (IFMapTable::FindTable(agent_->db(), + "service_instance"))); + assert(cfg_service_instance_table_); + + cfg_security_group_table_ = (static_cast + (IFMapTable::FindTable(agent_->db(), + "security_group"))); + assert(cfg_security_group_table_); + cfg_subnet_table_ = (static_cast (IFMapTable::FindTable(agent_->db(), "subnet"))); @@ -228,6 +247,12 @@ void AgentConfig::RegisterDBClients(DB *db) { "logical-interface"))); assert(cfg_logical_port_table_); + cfg_physical_device_table_ = (static_cast + (IFMapTable::FindTable(agent_->db(), + "physical-router"))); + assert(cfg_physical_device_table_); + + cfg_interface_client_->Init(); } diff --git a/src/vnsw/agent/cfg/cfg_init.h b/src/vnsw/agent/cfg/cfg_init.h index d099027623d..91ab06f944d 100644 --- a/src/vnsw/agent/cfg/cfg_init.h +++ b/src/vnsw/agent/cfg/cfg_init.h @@ -65,6 +65,22 @@ class AgentConfig { return cfg_logical_port_table_; } + IFMapAgentTable *cfg_loadbalancer_table() const { + return cfg_loadbalancer_table_; + } + + IFMapAgentTable *cfg_service_instance_table() const { + return cfg_service_instance_table_; + } + + IFMapAgentTable *cfg_security_group_table() const { + return cfg_security_group_table_; + } + + IFMapAgentTable *cfg_physical_device_table() const { + return cfg_physical_device_table_; + } + Agent *agent() const { return agent_; } CfgFilter *cfg_filter() const { return cfg_filter_.get(); } CfgListener *cfg_listener() const { return cfg_listener_.get(); } @@ -118,6 +134,10 @@ class AgentConfig { IFMapAgentTable *cfg_service_template_table_; IFMapAgentTable *cfg_subnet_table_; IFMapAgentTable *cfg_logical_port_table_; + IFMapAgentTable *cfg_loadbalancer_table_; + IFMapAgentTable *cfg_service_instance_table_; + IFMapAgentTable *cfg_security_group_table_; + IFMapAgentTable *cfg_physical_device_table_; DISALLOW_COPY_AND_ASSIGN(AgentConfig); }; diff --git a/src/vnsw/agent/cfg/cfg_listener.cc b/src/vnsw/agent/cfg/cfg_listener.cc index 3b79efa9128..92f1d1440c6 100644 --- a/src/vnsw/agent/cfg/cfg_listener.cc +++ b/src/vnsw/agent/cfg/cfg_listener.cc @@ -66,6 +66,7 @@ void CfgListener::Shutdown() { cfg_listener_id_map_.clear(); } + // Get CfgDBState set for an IFNode CfgDBState *CfgListener::GetCfgDBState(IFMapTable *table, DBEntryBase *dbe, DBTableBase::ListenerId &id) { @@ -78,6 +79,19 @@ CfgDBState *CfgListener::GetCfgDBState(IFMapTable *table, DBEntryBase *dbe, return static_cast(dbe->GetState(table, id)); } + +bool CfgListener::GetCfgDBStateUuid(IFMapNode *node, boost::uuids::uuid &id) { + + DBEntryBase *dbe = static_cast (node); + DBTableBase::ListenerId lid = 0; + CfgDBState *state = GetCfgDBState(node->table(), dbe, lid); + if (!state || (state->uuid_ == boost::uuids::nil_uuid())) + return false; + + id = state->uuid_; + return true; +} + // When traversing graph, check if an IFMapNode can be used. Conditions are, // - The node is not in deleted state // - The node was notified earlier @@ -144,6 +158,11 @@ AgentDBTable* CfgListener::GetOperDBTable(IFMapNode *node) { return NULL; } const CfgTableListenerInfo *info = &loc->second; + + // IF delete operation lets not bother about mandatory fields + if (node->IsDeleted()) + return info->table_; + // Check for presence of ID_PERMS if configured if (info->need_property_id_ >= 0) { const IFMapObject *obj = node->GetObject(); @@ -210,8 +229,8 @@ CfgListener::NodeListenerCb CfgListener::GetCallback(IFMapNode *node) { return info->cb_; } -void CfgListener::LinkNotify(IFMapLink *link, IFMapNode *node, - IFMapNode *peer, CfgDBState *state, +void CfgListener::LinkNotify(IFMapLink *link, IFMapNode *node, IFMapNode *peer, + const string &peer_type, CfgDBState *state, DBTableBase::ListenerId id) { if (node == NULL) { return; @@ -224,23 +243,22 @@ void CfgListener::LinkNotify(IFMapLink *link, IFMapNode *node, // Check if link notifier is registered. If there is no callback // registered for links, use IFNodeToReq iteself AgentDBTable *oper_table = NULL; - // Invoke link notifier only if peer node is known - if (peer) { - oper_table = GetLinkOperDBTable(node); - // Link callback registered - if (oper_table) { - // Skip link notification if node was not notified earlier - if (state == NULL || oper_table->CanNotify(node) == false) - return; + oper_table = GetLinkOperDBTable(node); + // Invoke IFLinkToReq under following conditions, + // - Link notification registered for the object + // - Object is already notified (state is set) + if (oper_table && state != NULL) { + // Skip link notification if node cannot be notified + if (oper_table->CanNotify(node)) { // Link can only result in update to existing entry. So, ADD_CHANGE // is the only operation needed DBRequest req(DBRequest::DB_ENTRY_ADD_CHANGE); - if (oper_table->IFLinkToReq(link, node, peer, req)) { + if (oper_table->IFLinkToReq(link, node, peer_type, peer, req)) { oper_table->Enqueue(&req); } - return; } + return; } oper_table = GetOperDBTable(node); @@ -267,11 +285,13 @@ void CfgListener::LinkListener(DBTablePartBase *partition, DBEntryBase *dbe) { CfgDBState *lstate = NULL; CfgDBState *rstate = NULL; + const IFMapNode::Descriptor &ldescriptor = link->left_id(); IFMapNode *lnode = link->LeftNode(database_); if (lnode) { lstate = GetCfgDBState(lnode->table(), lnode, lid); } + const IFMapNode::Descriptor &rdescriptor = link->right_id(); IFMapNode *rnode = link->RightNode(database_); if (rnode) { rstate = GetCfgDBState(rnode->table(), rnode, rid); @@ -291,14 +311,14 @@ void CfgListener::LinkListener(DBTablePartBase *partition, DBEntryBase *dbe) { // If right node is not notified, notify right followed by left. // Else, notify left followed by right if (lstate != NULL && rstate != NULL) { - LinkNotify(link, lnode, rnode, lstate, lid); - LinkNotify(link, rnode, lnode, rstate, rid); + LinkNotify(link, lnode, rnode, rdescriptor.first, lstate, lid); + LinkNotify(link, rnode, lnode, ldescriptor.first, rstate, rid); } else if (lstate == NULL) { - LinkNotify(link, lnode, rnode, lstate, lid); - LinkNotify(link, rnode, lnode, rstate, rid); + LinkNotify(link, lnode, rnode, rdescriptor.first, lstate, lid); + LinkNotify(link, rnode, lnode, ldescriptor.first, rstate, rid); } else if (rstate == NULL) { - LinkNotify(link, rnode, lnode, rstate, rid); - LinkNotify(link, lnode, rnode, lstate, lid); + LinkNotify(link, rnode, lnode, ldescriptor.first, rstate, rid); + LinkNotify(link, lnode, rnode, rdescriptor.first, lstate, lid); } } @@ -307,6 +327,10 @@ void CfgListener::NodeNotify(AgentDBTable *oper_table, IFMapNode *node) { if (node->IsDeleted()) { req.oper = DBRequest::DB_ENTRY_DELETE; } else { + DBEntryBase *dbe = static_cast (node); + DBTableBase::ListenerId lid = 0; + CfgDBState *state = GetCfgDBState(node->table(), dbe, lid); + oper_table->IFNodeToUuid(node, state->uuid_); req.oper = DBRequest::DB_ENTRY_ADD_CHANGE; } diff --git a/src/vnsw/agent/cfg/cfg_listener.h b/src/vnsw/agent/cfg/cfg_listener.h index 28323b51616..e216b900f4f 100644 --- a/src/vnsw/agent/cfg/cfg_listener.h +++ b/src/vnsw/agent/cfg/cfg_listener.h @@ -13,8 +13,9 @@ class DB; class CfgDBState : public DBState { public: - CfgDBState() : notify_count_(0) { }; - bool notify_count_; + CfgDBState() : notify_count_(0), uuid_(boost::uuids::nil_uuid()) { }; + uint32_t notify_count_; + boost::uuids::uuid uuid_; }; class CfgListener { @@ -67,6 +68,8 @@ class CfgListener { bool SkipNode(IFMapNode *node); bool SkipNode(IFMapNode *node, IFMapAgentTable *table); + bool GetCfgDBStateUuid(IFMapNode *node, boost::uuids::uuid &id); + // Callback invoked for each IFMap neighbor node typedef boost::function multicast_peer_; std::auto_ptr multicast_tor_peer_; std::auto_ptr multicast_tree_builder_peer_; + std::auto_ptr mac_vm_binding_peer_; std::auto_ptr agent_signal_; diff --git a/src/vnsw/agent/cmn/agent_db.cc b/src/vnsw/agent/cmn/agent_db.cc index 8bc345f4546..9222d9fcdb4 100644 --- a/src/vnsw/agent/cmn/agent_db.cc +++ b/src/vnsw/agent/cmn/agent_db.cc @@ -93,6 +93,10 @@ void AgentDBTablePartition::Remove(DBEntryBase *entry) { DBTablePartition::Remove(entry); } +bool AgentDBTable::IFNodeToUuid(IFMapNode *node, boost::uuids::uuid &id) { + return false; +} + void AgentDBTable::Input(DBTablePartition *partition, DBClient *client, DBRequest *req) { AgentKey *key = static_cast(req->key.get()); diff --git a/src/vnsw/agent/cmn/agent_db.h b/src/vnsw/agent/cmn/agent_db.h index 02364b9322b..000f2f20225 100644 --- a/src/vnsw/agent/cmn/agent_db.h +++ b/src/vnsw/agent/cmn/agent_db.h @@ -150,11 +150,14 @@ class AgentDBTable : public DBTable { assert(0); return false; } - virtual bool IFLinkToReq(IFMapLink *link, IFMapNode *node, IFMapNode *peer, + virtual bool IFLinkToReq(IFMapLink *link, IFMapNode *node, + const std::string &peer_name, IFMapNode *peer, DBRequest &req) { assert(0); return false; } + virtual bool IFNodeToUuid(IFMapNode *node, boost::uuids::uuid &id); + virtual DBTablePartition *AllocPartition(int index) { return new AgentDBTablePartition(this, index); }; diff --git a/src/vnsw/agent/filter/acl.cc b/src/vnsw/agent/filter/acl.cc index 72cc52d5a7b..52be7239f01 100644 --- a/src/vnsw/agent/filter/acl.cc +++ b/src/vnsw/agent/filter/acl.cc @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -313,11 +314,19 @@ static void AclObjectTrace(AgentLogEvent::type event, AclSpec &acl_spec) } } -bool AclTable::IFNodeToReq(IFMapNode *node, DBRequest &req) { +bool AclTable::IFNodeToUuid(IFMapNode *node, boost::uuids::uuid &u) { AccessControlList *cfg_acl = static_cast (node->GetObject()); autogen::IdPermsType id_perms = cfg_acl->id_perms(); - boost::uuids::uuid u; CfgUuidSet(id_perms.uuid.uuid_mslong, id_perms.uuid.uuid_lslong, u); + return true; +} + +bool AclTable::IFNodeToReq(IFMapNode *node, DBRequest &req) { + + AccessControlList *cfg_acl = static_cast (node->GetObject()); + uuid u; + if (agent()->cfg_listener()->GetCfgDBStateUuid(node, u) == false) + return false; // Delete ACL if (req.oper == DBRequest::DB_ENTRY_DELETE) { @@ -406,6 +415,23 @@ bool AclTable::IFNodeToReq(IFMapNode *node, DBRequest &req) { return false; } +bool AclTable::IFLinkToReq(IFMapLink *link, IFMapNode *node, + const std::string &peer_type, IFMapNode *peer, + DBRequest &req) { + if (peer && peer->table() == agent()->cfg()->cfg_vn_table()) { + DBRequest vn_req; + req.oper = DBRequest::DB_ENTRY_ADD_CHANGE; + agent()->vn_table()->IFNodeToReq(peer, vn_req); + } + + if (peer && peer->table() == agent()->cfg()->cfg_sg_table()) { + DBRequest sg_req; + req.oper = DBRequest::DB_ENTRY_ADD_CHANGE; + agent()->sg_table()->IFNodeToReq(peer, sg_req); + } + return false; +} + // ACL methods void AclDBEntry::SetAclEntries(AclEntries &entries) { diff --git a/src/vnsw/agent/filter/acl.h b/src/vnsw/agent/filter/acl.h index 4e946298b27..553cb1dc739 100644 --- a/src/vnsw/agent/filter/acl.h +++ b/src/vnsw/agent/filter/acl.h @@ -145,6 +145,10 @@ class AclTable : public AgentDBTable { virtual bool Delete(DBEntry *entry, const DBRequest *req); virtual bool IFNodeToReq(IFMapNode *node, DBRequest &req); + virtual bool IFNodeToUuid(IFMapNode *node, boost::uuids::uuid &u); + virtual bool IFLinkToReq(IFMapLink *link, IFMapNode *node, + const std::string &peer_type, IFMapNode *peer, + DBRequest &req); static DBTableBase *CreateTable(DB *db, const std::string &name); TrafficAction::Action ConvertActionString(std::string action) const; diff --git a/src/vnsw/agent/kstate/test/test_kstate.cc b/src/vnsw/agent/kstate/test/test_kstate.cc index b42af42e72e..3b921639a3b 100644 --- a/src/vnsw/agent/kstate/test/test_kstate.cc +++ b/src/vnsw/agent/kstate/test/test_kstate.cc @@ -214,7 +214,6 @@ class KStateTest : public ::testing::Test { }; bool KStateTest::ksync_init_; - TEST_F(KStateTest, IfDumpTest) { int if_count = 0; TestIfKState::Init(); @@ -267,7 +266,6 @@ TEST_F(KStateTest, NHDumpTest) { DeletePorts(max_ports); } - TEST_F(KStateTest, NHGetTest) { int nh_count = 0; TestNHKState::Init(); diff --git a/src/vnsw/agent/oper/SConscript b/src/vnsw/agent/oper/SConscript index df003207019..03a1b117544 100644 --- a/src/vnsw/agent/oper/SConscript +++ b/src/vnsw/agent/oper/SConscript @@ -37,7 +37,6 @@ vnswoperdb = env.Library('vnswoperdb', 'loadbalancer_haproxy.cc', 'loadbalancer_properties.cc', 'logical_interface.cc', - 'mac_vm_binding.cc', 'mirror_table.cc', 'mpls.cc', 'multicast.cc', diff --git a/src/vnsw/agent/oper/agent.sandesh b/src/vnsw/agent/oper/agent.sandesh index c21cd4b268e..da594100849 100644 --- a/src/vnsw/agent/oper/agent.sandesh +++ b/src/vnsw/agent/oper/agent.sandesh @@ -233,6 +233,7 @@ struct PathSandeshData { 15: optional string info; 16: optional i32 active_label; 17: optional string flood_dhcp; + 18: optional string vm_name; } struct RouteUcSandeshData { diff --git a/src/vnsw/agent/oper/agent_path.cc b/src/vnsw/agent/oper/agent_path.cc index cb6379e1acc..1316abc8b4a 100644 --- a/src/vnsw/agent/oper/agent_path.cc +++ b/src/vnsw/agent/oper/agent_path.cc @@ -402,12 +402,6 @@ bool EvpnDerivedPathData::AddChangePath(Agent *agent, AgentPath *path, ret = true; } - bool flood_dhcp = reference_path_->flood_dhcp(); - if (evpn_path->flood_dhcp() != flood_dhcp) { - evpn_path->set_flood_dhcp(flood_dhcp); - ret = true; - } - return ret; } @@ -1096,7 +1090,12 @@ void AgentPath::SetSandeshData(PathSandeshData &pdata) const { path_preference_.wait_for_traffic()); pdata.set_path_preference_data(path_preference_data); pdata.set_active_label(GetActiveLabel()); - pdata.set_flood_dhcp(flood_dhcp() ? "true" : "false"); + if (peer()->GetType() == Peer::MAC_VM_BINDING_PEER) { + const MacVmBindingPath *dhcp_path = + static_cast(this); + pdata.set_flood_dhcp(dhcp_path->flood_dhcp() ? "true" : "false"); + pdata.set_vm_name(dhcp_path->vm_interface()->ToString()); + } } void AgentPath::set_local_ecmp_mpls_label(MplsLabel *mpls) { @@ -1170,3 +1169,47 @@ const Ip4Address *AgentPath::NexthopIp(Agent *agent) const { return peer_->NexthopIp(agent, this); } + +MacVmBindingPath::MacVmBindingPath(const Peer *peer) : + AgentPath(peer, NULL) { +} + +bool MacVmBindingPath::IsLess(const AgentPath &r_path) const { + return peer()->IsLess(r_path.peer()); +} + +const NextHop *MacVmBindingPath::ComputeNextHop(Agent *agent) const { + return nexthop(); +} + +AgentPath *MacVmBindingPathData::CreateAgentPath(const Peer *peer, + AgentRoute *rt) const { + const Peer *mac_vm_binding_peer = + dynamic_cast(peer); + assert(mac_vm_binding_peer != NULL); + return (new MacVmBindingPath(mac_vm_binding_peer)); +} + +bool MacVmBindingPathData::AddChangePath(Agent *agent, AgentPath *path, + const AgentRoute *rt) { + bool ret = false; + MacVmBindingPath *dhcp_path = + dynamic_cast(path); + + NextHop *nh = agent->nexthop_table()->discard_nh(); + if (path->ChangeNH(agent, nh) == true) + ret = true; + + bool flood_dhcp = !(vm_intf_->dhcp_enable_config()); + if (dhcp_path->flood_dhcp() != flood_dhcp) { + dhcp_path->set_flood_dhcp(flood_dhcp); + ret = true; + } + + if (dhcp_path->vm_interface() != vm_intf_) { + dhcp_path->set_vm_interface(vm_intf_); + ret = true; + } + + return ret; +} diff --git a/src/vnsw/agent/oper/agent_path.h b/src/vnsw/agent/oper/agent_path.h index 338c1f8b757..1809fbc65a8 100644 --- a/src/vnsw/agent/oper/agent_path.h +++ b/src/vnsw/agent/oper/agent_path.h @@ -628,4 +628,53 @@ class Inet4UnicastInterfaceRoute : public AgentRouteData { DISALLOW_COPY_AND_ASSIGN(Inet4UnicastInterfaceRoute); }; +//MacVmBindingPath is used to store VM interface from which +//this route was added. This helps in retrieving the +//VM using MAC in a VRF. Also it stores the flood dhcp +//flag which is used to decide if DHCP request are to +//be answered by agent or external DHCP server. +class MacVmBindingPath : public AgentPath { +public: + MacVmBindingPath(const Peer *peer); + virtual ~MacVmBindingPath() { } + + virtual const NextHop *ComputeNextHop(Agent *agent) const; + virtual bool IsLess(const AgentPath &right) const; + + //Data get/set + const VmInterface *vm_interface() const { + return dynamic_cast(vm_interface_.get()); + } + void set_vm_interface(const VmInterface *vm_interface) { + vm_interface_ = vm_interface; + } + bool flood_dhcp() const {return flood_dhcp_;} + void set_flood_dhcp(bool flood_dhcp) {flood_dhcp_ = flood_dhcp;} + +private: + //Key parameters for comparision + InterfaceConstRef vm_interface_; + bool flood_dhcp_; + DISALLOW_COPY_AND_ASSIGN(MacVmBindingPath); +}; + +//MacVmBindingPathData is expected to be used only in +//inline calls as it is carrying interface pointer. +//In case request is required key will have to be +//provided. +class MacVmBindingPathData : public AgentRouteData { +public: + MacVmBindingPathData(const VmInterface *vm_intf) : + AgentRouteData(false), vm_intf_(vm_intf) { } + virtual ~MacVmBindingPathData() { } + virtual AgentPath *CreateAgentPath(const Peer *peer, AgentRoute *rt) const; + virtual bool AddChangePath(Agent *agent, AgentPath *path, + const AgentRoute *rt); + virtual std::string ToString() const {return "MacVmBindingPathData";} + +private: + const VmInterface *vm_intf_; + DISALLOW_COPY_AND_ASSIGN(MacVmBindingPathData); +}; + #endif // vnsw_agent_path_hpp diff --git a/src/vnsw/agent/oper/bridge_route.cc b/src/vnsw/agent/oper/bridge_route.cc index dd816e15b84..20a807ea53b 100644 --- a/src/vnsw/agent/oper/bridge_route.cc +++ b/src/vnsw/agent/oper/bridge_route.cc @@ -68,18 +68,10 @@ DBTableBase *BridgeAgentRouteTable::CreateTable(DB *db, return table; } -BridgeRouteEntry *BridgeAgentRouteTable::FindRoute(const Agent *agent, - const string &vrf_name, - const MacAddress &mac) { - VrfEntry *vrf = agent->vrf_table()->FindVrfFromName(vrf_name); - if (vrf == NULL) - return NULL; - - BridgeRouteKey key(agent->local_vm_peer(), vrf_name, mac, 0); - BridgeAgentRouteTable *table = static_cast - (vrf->GetBridgeRouteTable()); +BridgeRouteEntry *BridgeAgentRouteTable::FindRoute(const MacAddress &mac) { + BridgeRouteKey key(agent()->local_vm_peer(), vrf_name(), mac, 0); BridgeRouteEntry *route = - static_cast(table->FindActiveEntry(&key)); + static_cast(FindActiveEntry(&key)); return route; } @@ -135,6 +127,26 @@ void BridgeAgentRouteTable::AddBridgeRoute(const AgentRoute *rt) { BridgeTableProcess(agent(), vrf_name(), req); } +void BridgeAgentRouteTable::AddMacVmBindingRoute(const Peer *peer, + const std::string &vrf_name, + const MacAddress &mac, + const VmInterface *vm_intf) { + DBRequest req(DBRequest::DB_ENTRY_ADD_CHANGE); + req.key.reset(new BridgeRouteKey(peer, vrf_name, mac, 0)); + req.data.reset(new MacVmBindingPathData(vm_intf)); + BridgeTableProcess(agent(), vrf_name, req); +} + +void BridgeAgentRouteTable::DeleteMacVmBindingRoute(const Peer *peer, + const std::string &vrf_name, + const MacAddress &mac, + const VmInterface *vm_intf) { + DBRequest req(DBRequest::DB_ENTRY_DELETE); + req.key.reset(new BridgeRouteKey(peer, vrf_name, mac, 0)); + req.data.reset(new MacVmBindingPathData(vm_intf)); + BridgeTableProcess(agent(), vrf_name, req); +} + void BridgeAgentRouteTable::DeleteBridgeRoute(const AgentRoute *rt) { const EvpnRouteEntry *evpn_rt = static_cast(rt); @@ -203,6 +215,19 @@ void BridgeAgentRouteTable::DeleteBroadcastReq(const Peer *peer, BridgeTableEnqueue(Agent::GetInstance(), &req); } +const VmInterface *BridgeAgentRouteTable::FindVmFromDhcpBinding +(const MacAddress &mac) { + const BridgeRouteEntry *l2_rt = FindRoute(mac); + if (l2_rt == NULL) + return NULL; + + const MacVmBindingPath *dhcp_path = dynamic_cast + (l2_rt->FindMacVmBindingPath()); + if (dhcp_path == NULL) + return NULL; + return dhcp_path->vm_interface(); +} + ///////////////////////////////////////////////////////////////////////////// // BridgeRouteEntry methods ///////////////////////////////////////////////////////////////////////////// @@ -248,12 +273,19 @@ uint32_t BridgeRouteEntry::GetActiveLabel() const { AgentPath *BridgeRouteEntry::FindPathUsingKeyData (const AgentRouteKey *key, const AgentRouteData *data) const { const Peer *peer = key->peer(); - const EvpnPeer * evpn_peer = dynamic_cast(peer); + const EvpnPeer *evpn_peer = dynamic_cast(peer); + if (is_multicast()) + return FindMulticastPathUsingKeyData(key, data); + + if (evpn_peer != NULL) + return FindEvpnPathUsingKeyData(key, data); - //For non multicast route not programmed via EVPN route table, - //use Findpath. - if ((is_multicast() == false) && (evpn_peer == NULL)) - return FindPath(key->peer()); + return FindPath(peer); +} + +AgentPath *BridgeRouteEntry::FindMulticastPathUsingKeyData +(const AgentRouteKey *key, const AgentRouteData *data) const { + assert(is_multicast()); Route::PathList::const_iterator it; for (it = GetPathList().begin(); it != GetPathList().end(); @@ -262,30 +294,45 @@ AgentPath *BridgeRouteEntry::FindPathUsingKeyData if (path->peer() != key->peer()) continue; - if (is_multicast()) { - //Handle multicast peer matching, - //In case of BGP peer also match VXLAN id. - if (path->peer()->GetType() != Peer::BGP_PEER) - return const_cast(path); + //Handle multicast peer matching, + //In case of BGP peer also match VXLAN id. + if (path->peer()->GetType() != Peer::BGP_PEER) + return const_cast(path); - const MulticastRoute *multicast_data = - dynamic_cast(data); - assert(multicast_data != NULL); - if (multicast_data->vxlan_id() != path->vxlan_id()) - continue; - } else { - //Handle mac route added via evpn route. - const EvpnDerivedPath *evpn_path = - dynamic_cast(path); - const EvpnDerivedPathData *evpn_data = - dynamic_cast(data); - assert(evpn_path != NULL); - assert(evpn_data != NULL); - if (evpn_path->ethernet_tag() != evpn_data->ethernet_tag()) - continue; - if (evpn_path->ip_addr() != evpn_data->ip_addr()) - continue; - } + const MulticastRoute *multicast_data = + dynamic_cast(data); + assert(multicast_data != NULL); + if (multicast_data->vxlan_id() != path->vxlan_id()) + continue; + + return const_cast(path); + } + return NULL; +} + +AgentPath *BridgeRouteEntry::FindEvpnPathUsingKeyData +(const AgentRouteKey *key, const AgentRouteData *data) const { + const Peer *peer = key->peer(); + const EvpnPeer *evpn_peer = dynamic_cast(peer); + assert(evpn_peer != NULL); + + Route::PathList::const_iterator it; + for (it = GetPathList().begin(); it != GetPathList().end(); it++) { + const AgentPath *path = static_cast(it.operator->()); + if (path->peer() != key->peer()) + continue; + + //Handle mac route added via evpn route. + const EvpnDerivedPath *evpn_path = + dynamic_cast(path); + const EvpnDerivedPathData *evpn_data = + dynamic_cast(data); + assert(evpn_path != NULL); + assert(evpn_data != NULL); + if (evpn_path->ethernet_tag() != evpn_data->ethernet_tag()) + continue; + if (evpn_path->ip_addr() != evpn_data->ip_addr()) + continue; return const_cast(path); } return NULL; @@ -346,6 +393,11 @@ void BridgeRouteEntry::DeletePathUsingKeyData(const AgentRouteKey *key, } } +const AgentPath *BridgeRouteEntry::FindMacVmBindingPath() const { + Agent *agent = (static_cast (get_table()))->agent(); + return FindPath(agent->mac_vm_binding_peer()); +} + bool BridgeRouteEntry::ReComputePathAdd(AgentPath *path) { if (is_multicast()) { //evaluate add of path diff --git a/src/vnsw/agent/oper/bridge_route.h b/src/vnsw/agent/oper/bridge_route.h index 6ed0425de4e..8b497a60d10 100644 --- a/src/vnsw/agent/oper/bridge_route.h +++ b/src/vnsw/agent/oper/bridge_route.h @@ -22,6 +22,10 @@ class BridgeAgentRouteTable : public AgentRouteTable { static DBTableBase *CreateTable(DB *db, const std::string &name); + void AddMacVmBindingRoute(const Peer *peer, + const std::string &vrf_name, + const MacAddress &mac, + const VmInterface *vm_intf); void AddBridgeRoute(const AgentRoute *rt); static void AddBridgeBroadcastRoute(const Peer *peer, const std::string &vrf_name, @@ -53,9 +57,12 @@ class BridgeAgentRouteTable : public AgentRouteTable { const std::string &vrf_name, uint32_t ethernet_tag); void DeleteBridgeRoute(const AgentRoute *rt); - static BridgeRouteEntry *FindRoute(const Agent *agent, - const std::string &vrf_name, - const MacAddress &mac); + void DeleteMacVmBindingRoute(const Peer *peer, + const std::string &vrf_name, + const MacAddress &mac, + const VmInterface *vm_intf); + const VmInterface *FindVmFromDhcpBinding(const MacAddress &mac); + BridgeRouteEntry *FindRoute(const MacAddress &mac); private: DBTableWalker::WalkId walkid_; @@ -96,9 +103,14 @@ class BridgeRouteEntry : public AgentRoute { bool force_delete); const MacAddress &mac() const {return mac_;} + const AgentPath *FindMacVmBindingPath() const; private: bool ReComputeMulticastPaths(AgentPath *path, bool del); + AgentPath *FindEvpnPathUsingKeyData(const AgentRouteKey *key, + const AgentRouteData *data) const; + AgentPath *FindMulticastPathUsingKeyData(const AgentRouteKey *key, + const AgentRouteData *data) const; MacAddress mac_; DISALLOW_COPY_AND_ASSIGN(BridgeRouteEntry); diff --git a/src/vnsw/agent/oper/evpn_route.cc b/src/vnsw/agent/oper/evpn_route.cc index bc22b6f8ad1..55eac26f392 100644 --- a/src/vnsw/agent/oper/evpn_route.cc +++ b/src/vnsw/agent/oper/evpn_route.cc @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -347,41 +346,6 @@ uint32_t EvpnRouteEntry::GetActiveLabel() const { return GetActivePath()->GetActiveLabel(); } -bool EvpnRouteEntry::FloodDhcpRequired() const { - VnEntry *vn = vrf()->vn(); - if (vn) { - IpAddress ip = ip_addr_; - if (ip.is_unspecified()) { - Agent *agent = - (static_cast (get_table()))->agent(); - const Interface *interface = agent->interface_table()-> - mac_vm_binding().FindMacVmBinding(mac_, - GetActivePath()->vxlan_id()); - if (!interface) - return true; - const VmInterface *vm_interface = - static_cast(interface); - return !(vm_interface->dhcp_enable_config()); - } - //VM is TAP VM. - const VnIpam *vn_ipam = vn->GetIpam(ip_addr_); - if (vn_ipam) - return !(vn_ipam->dhcp_enable); - } - return false; -} - -bool EvpnRouteEntry::RecomputeRoutePath(Agent *agent, DBTablePartition *part, - AgentPath *path, AgentRouteData *data) { - bool ret = false; - bool flood_dhcp_required = FloodDhcpRequired(); - - if (path->flood_dhcp() != flood_dhcp_required) { - path->set_flood_dhcp(flood_dhcp_required); - ret = true; - } - return ret; -} ///////////////////////////////////////////////////////////////////////////// // Sandesh related methods ///////////////////////////////////////////////////////////////////////////// diff --git a/src/vnsw/agent/oper/evpn_route.h b/src/vnsw/agent/oper/evpn_route.h index b510b2f5e33..3d2b602568d 100644 --- a/src/vnsw/agent/oper/evpn_route.h +++ b/src/vnsw/agent/oper/evpn_route.h @@ -110,10 +110,6 @@ class EvpnRouteEntry : public AgentRoute { } virtual bool DBEntrySandesh(Sandesh *sresp, bool stale) const; virtual uint32_t GetActiveLabel() const; - virtual bool RecomputeRoutePath(Agent *agent, - DBTablePartition *part, - AgentPath *path, - AgentRouteData *data); const MacAddress &mac() const {return mac_;} const IpAddress &ip_addr() const {return ip_addr_;} @@ -121,7 +117,6 @@ class EvpnRouteEntry : public AgentRoute { uint32_t ethernet_tag() const {return ethernet_tag_;} private: - bool FloodDhcpRequired() const; MacAddress mac_; IpAddress ip_addr_; diff --git a/src/vnsw/agent/oper/ifmap_dependency_manager.cc b/src/vnsw/agent/oper/ifmap_dependency_manager.cc index 6bc20ba61f9..ffe4f23b5c4 100644 --- a/src/vnsw/agent/oper/ifmap_dependency_manager.cc +++ b/src/vnsw/agent/oper/ifmap_dependency_manager.cc @@ -21,39 +21,13 @@ using namespace boost::assign; using namespace std; -class IFMapDependencyManager::IFMapNodeState : public DBState { - public: - IFMapNodeState(IFMapDependencyManager *manager, IFMapNode *node) - : manager_(manager), node_(node), object_(NULL), refcount_(0) { - } - - IFMapNode *node() { return node_; } - DBEntry *object() { return object_; } - void set_object(DBEntry *object) { - object_ = object; - ++refcount_; - } - // Caller decrements refcount. - void clear_object() { - object_ = NULL; - } - - private: - friend void intrusive_ptr_add_ref(IFMapNodeState *state); - friend void intrusive_ptr_release(IFMapNodeState *state); - - IFMapDependencyManager *manager_; - IFMapNode *node_; - DBEntry *object_; - int refcount_; -}; - -void intrusive_ptr_add_ref(IFMapDependencyManager::IFMapNodeState *state) { +void intrusive_ptr_add_ref(IFMapNodeState *state) { ++state->refcount_; } -void intrusive_ptr_release(IFMapDependencyManager::IFMapNodeState *state) { +void intrusive_ptr_release(IFMapNodeState *state) { if (--state->refcount_ == 0) { + assert(state->object_ == NULL); state->manager_->IFMapNodeReset(state->node_); delete state; } @@ -199,7 +173,6 @@ void IFMapDependencyManager::Terminate() { iter != table_map_.end(); ++iter) { DBTable *table = static_cast( database_->FindTable(iter->first)); - DBTable::DBStateClear(table, iter->second); table->Unregister(iter->second); } } @@ -250,7 +223,7 @@ void IFMapDependencyManager::ChangeListAdd(IFMapNode *node) { change_list_.push_back(IFMapNodePtr(state)); } -IFMapDependencyManager::IFMapNodeState * +IFMapNodeState * IFMapDependencyManager::IFMapNodeGet(IFMapNode *node) { IFMapTable *table = node->table(); TableMap::const_iterator loc = table_map_.find(table->name()); @@ -262,15 +235,6 @@ IFMapDependencyManager::IFMapNodeGet(IFMapNode *node) { return state; } -void IFMapDependencyManager::IFMapNodeSet(IFMapNode *node, DBEntry *entry) { - IFMapTable *table = node->table(); - TableMap::const_iterator loc = table_map_.find(table->name()); - assert(loc != table_map_.end()); - IFMapNodeState *state = new IFMapNodeState(this, node); - state->set_object(entry); - node->SetState(table, loc->second, state); -} - void IFMapDependencyManager::IFMapNodeReset(IFMapNode *node) { IFMapTable *table = node->table(); TableMap::const_iterator loc = table_map_.find(table->name()); @@ -286,35 +250,37 @@ void IFMapDependencyManager::IFMapNodeReset(IFMapNode *node) { * responsibility to create a new mapping to IFMapNodeSet (private). */ void IFMapDependencyManager::SetObject(IFMapNode *node, DBEntry *entry) { + IFMapNodeState *state = IFMapNodeGet(node); - assert(entry); - if (state == NULL) { - IFMapNodeSet(node, entry); - } else { + assert(state); + + DBEntry *old_entry = state->object(); + + if (old_entry) + state->clear_object(); + + if (entry) state->set_object(entry); - } + tracker_->NodeEvent(node); trigger_->Set(); } -void IFMapDependencyManager::SetState(IFMapNode *node) { - IFMapNodeState *state = IFMapNodeGet(node); - if (state == NULL) { - IFMapNodeSet(node, NULL); - } -} +IFMapDependencyManager::IFMapNodePtr +IFMapDependencyManager::SetState(IFMapNode *node) { + IFMapTable *table = node->table(); + TableMap::const_iterator loc = table_map_.find(table->name()); + if (loc == table_map_.end()) + return NULL; -/* - * Reset the association between the IFMapNode and the operation DB - * entry. - */ -void IFMapDependencyManager::ResetObject(IFMapNode *node) { - IFMapNodeState *state = IFMapNodeGet(node); - if (state == NULL) { - return; + IFMapNodeState *state = + static_cast(node->GetState(table, loc->second)); + + if (!state) { + state = new IFMapNodeState(this, node); + node->SetState(table, loc->second, state); } - state->clear_object(); - intrusive_ptr_release(state); + return IFMapNodePtr(state); } /* diff --git a/src/vnsw/agent/oper/ifmap_dependency_manager.h b/src/vnsw/agent/oper/ifmap_dependency_manager.h index 724e649f7ec..eb6e6b94af0 100644 --- a/src/vnsw/agent/oper/ifmap_dependency_manager.h +++ b/src/vnsw/agent/oper/ifmap_dependency_manager.h @@ -18,9 +18,48 @@ class DBGraph; class IFMapDependencyTracker; class IFMapNode; class TaskTrigger; +class IFMapDependencyManager; + +//IFMapNodeState is a DBState for IFMapNode with listener ID +// of IFMapDependency Manager. DBState is created when the first +// time SetState is invoked. The caller of SetState gets intrusive +// pointer to IFMapNodeState enabling the caller hold IFMapNode +// till reference is removed. Caller does not need to invoke +// clear state as it gets automatically cleared when references are +// removed. Optionally a DBEntry can be added to this IFMapNodeState +// to trigger the IFMapDependency tracker. +// IFMapDependency tracker also uses the same state, to ensure that +// across the traversal, IFMapNode is not removed. +class IFMapNodeState : public DBState { + public: + IFMapNodeState(IFMapDependencyManager *manager, IFMapNode *node) + : manager_(manager), node_(node), object_(NULL), refcount_(0) { + } + + IFMapNode *node() { return node_; } + DBEntry *object() { return object_; } + void set_object(DBEntry *object) { + object_ = object; + } + + void clear_object() { + object_ = NULL; + } + + private: + friend void intrusive_ptr_add_ref(IFMapNodeState *state); + friend void intrusive_ptr_release(IFMapNodeState *state); + + IFMapDependencyManager *manager_; + IFMapNode *node_; + DBEntry *object_; + int refcount_; +}; + class IFMapDependencyManager { public: + typedef boost::intrusive_ptr IFMapNodePtr; typedef boost::function ChangeEventHandler; IFMapDependencyManager(DB *database, DBGraph *graph); virtual ~IFMapDependencyManager(); @@ -46,16 +85,10 @@ class IFMapDependencyManager { */ void SetObject(IFMapNode *node, DBEntry *entry); - /* - * Reset the association between the IFMapNode and the operation DB - * entry. - */ - void ResetObject(IFMapNode *node); - /* * Add DBState to an IFMapNode */ - void SetState(IFMapNode *node); + IFMapNodePtr SetState(IFMapNode *node); /* * Register a notification callback. */ @@ -66,17 +99,16 @@ class IFMapDependencyManager { */ void Unregister(const std::string &type); + private: /* * IFMapNodeState (DBState) should exist: * a) if the object is set * b) if the entry is on the change list. */ - class IFMapNodeState; friend void intrusive_ptr_add_ref(IFMapNodeState *state); friend void intrusive_ptr_release(IFMapNodeState *state); - typedef boost::intrusive_ptr IFMapNodePtr; typedef std::vector ChangeList; typedef std::map TableMap; typedef std::map EventMap; @@ -87,7 +119,6 @@ class IFMapDependencyManager { void LinkObserver(DBTablePartBase *root, DBEntryBase *db_entry); void ChangeListAdd(IFMapNode *node); - void IFMapNodeSet(IFMapNode *node, DBEntry *object); void IFMapNodeReset(IFMapNode *node); IFMapNodeState *IFMapNodeGet(IFMapNode *node); diff --git a/src/vnsw/agent/oper/inet_unicast_route.cc b/src/vnsw/agent/oper/inet_unicast_route.cc index 86bd892db94..57b3e2d2189 100644 --- a/src/vnsw/agent/oper/inet_unicast_route.cc +++ b/src/vnsw/agent/oper/inet_unicast_route.cc @@ -1170,7 +1170,15 @@ InetUnicastAgentRouteTable::ArpRoute(DBRequest::DBOperation op, const SecurityGroupList &sg) { Agent *agent = Agent::GetInstance(); DBRequest nh_req(DBRequest::DB_ENTRY_ADD_CHANGE); - nh_req.key.reset(new ArpNHKey(nexthop_vrf_name, ip, policy)); + ArpNHKey *nh_key = new ArpNHKey(nexthop_vrf_name, ip, policy); + if (op == DBRequest::DB_ENTRY_DELETE) { + //In case of delete we want to set the + //nexthop as invalid, hence use resync operation + //We dont want the nexthop to created again + //in case of duplicate delete + nh_key->sub_op_ = AgentKey::RESYNC; + } + nh_req.key.reset(nh_key); ArpNHData *arp_data = new ArpNHData(mac, static_cast(intf.GetDBRequestKey().release()), resolved); diff --git a/src/vnsw/agent/oper/interface.cc b/src/vnsw/agent/oper/interface.cc index 74d4894f03a..637c1ea7027 100644 --- a/src/vnsw/agent/oper/interface.cc +++ b/src/vnsw/agent/oper/interface.cc @@ -83,6 +83,18 @@ void InterfaceTable::RegisterDBClients(IFMapDependencyManager *dep) { autogen::LogicalInterface::ID_PERMS); } +bool InterfaceTable::IFNodeToUuid(IFMapNode *node, boost::uuids::uuid &u) { + if (strcmp(node->table()->Typename(), "virtual-machine-interface") == 0) { + return VmiIFNodeToUuid(node, u); + } + + if (strcmp(node->table()->Typename(), "logical-interface") == 0) { + return LogicalInterfaceIFNodeToUuid(node, u); + } + + return false; +} + bool InterfaceTable::IFNodeToReq(IFMapNode *node, DBRequest &req) { if (strcmp(node->table()->Typename(), "physical-interface") == 0) { return PhysicalInterfaceIFNodeToReq(node, req); diff --git a/src/vnsw/agent/oper/interface.h b/src/vnsw/agent/oper/interface.h index d3763bc434f..0812da15d2f 100644 --- a/src/vnsw/agent/oper/interface.h +++ b/src/vnsw/agent/oper/interface.h @@ -13,7 +13,6 @@ #include #include #include -#include struct InterfaceData; class VmInterface; @@ -275,10 +274,13 @@ class InterfaceTable : public AgentOperDBTable { // Config handlers bool VmiIFNodeToReq(IFMapNode *node, DBRequest &req); + bool VmiIFNodeToUuid(IFMapNode *node, boost::uuids::uuid &u); + bool LogicalInterfaceIFNodeToUuid(IFMapNode *node, boost::uuids::uuid &u); bool PhysicalInterfaceIFNodeToReq(IFMapNode *node, DBRequest &req); bool LogicalInterfaceIFNodeToReq(IFMapNode *node, DBRequest &req); bool RemotePhysicalInterfaceIFNodeToReq(IFMapNode *node, DBRequest &req); bool IFNodeToReq(IFMapNode *node, DBRequest &req); + bool IFNodeToUuid(IFMapNode *node, boost::uuids::uuid &u); // Handle change in config VRF for the interface void VmInterfaceVrfSync(IFMapNode *node); @@ -320,7 +322,6 @@ class InterfaceTable : public AgentOperDBTable { static InterfaceTable *GetInstance() { return interface_table_; } Agent *agent() const { return agent_; } OperDB *operdb() const { return operdb_; } - MacVmBinding &mac_vm_binding() {return mac_vm_binding_;} private: bool L2VmInterfaceWalk(DBTablePartBase *partition, @@ -338,7 +339,6 @@ class InterfaceTable : public AgentOperDBTable { DhcpSnoopMap dhcp_snoop_map_; UpdateFloatingIpFn update_floatingip_cb_; VmiToVmiTypeMap vmi_to_vmitype_map_; - MacVmBinding mac_vm_binding_; DISALLOW_COPY_AND_ASSIGN(InterfaceTable); }; diff --git a/src/vnsw/agent/oper/loadbalancer.cc b/src/vnsw/agent/oper/loadbalancer.cc index 5f990634982..9068d0a27e7 100644 --- a/src/vnsw/agent/oper/loadbalancer.cc +++ b/src/vnsw/agent/oper/loadbalancer.cc @@ -8,6 +8,7 @@ #include "loadbalancer_properties.h" #include #include +#include class LoadbalancerData : public AgentData { public: @@ -213,6 +214,8 @@ DBEntry *LoadbalancerTable::Add(const DBRequest *request) { static_cast(request->data.get()); loadbalancer->set_node(data->node()); assert(dependency_manager_); + loadbalancer->SetIFMapNodeState( + dependency_manager_->SetState(data->node())); dependency_manager_->SetObject(data->node(), loadbalancer); return loadbalancer; @@ -221,7 +224,8 @@ DBEntry *LoadbalancerTable::Add(const DBRequest *request) { bool LoadbalancerTable::Delete(DBEntry *entry, const DBRequest *request) { Loadbalancer *loadbalancer = static_cast(entry); assert(dependency_manager_); - dependency_manager_->ResetObject(loadbalancer->node()); + dependency_manager_->SetObject(loadbalancer->node(), NULL); + loadbalancer->SetIFMapNodeState(NULL); return true; } @@ -248,11 +252,26 @@ void LoadbalancerTable::Initialize( boost::bind(&LoadbalancerTable::ChangeEventHandler, this, _1)); } -bool LoadbalancerTable::IFNodeToReq(IFMapNode *node, DBRequest &request) { +bool LoadbalancerTable::IFNodeToUuid(IFMapNode *node, boost::uuids::uuid &u) { autogen::LoadbalancerPool *pool = - static_cast(node->GetObject()); + static_cast(node->GetObject()); const autogen::IdPermsType &id = pool->id_perms(); - request.key.reset(new LoadbalancerKey(IdPermsGetUuid(id))); + u = IdPermsGetUuid(id); + return true; +} + +bool LoadbalancerTable::IFNodeToReq(IFMapNode *node, DBRequest &request) { + boost::uuids::uuid id; + if (agent() && agent()->cfg_listener()) { + agent()->cfg_listener()->GetCfgDBStateUuid(node, id); + } else { + IFNodeToUuid(node, id); + } + if (boost::uuids::nil_uuid() == id) + return false; + + request.key.reset(new LoadbalancerKey(id)); + if (!node->IsDeleted()) { request.oper = DBRequest::DB_ENTRY_ADD_CHANGE; request.data.reset(new LoadbalancerData(node)); diff --git a/src/vnsw/agent/oper/loadbalancer.h b/src/vnsw/agent/oper/loadbalancer.h index a5a3ed12e44..8b370693d96 100644 --- a/src/vnsw/agent/oper/loadbalancer.h +++ b/src/vnsw/agent/oper/loadbalancer.h @@ -7,6 +7,7 @@ #include #include "cmn/agent_db.h" +#include "oper/ifmap_dependency_manager.h" class IFMapDependencyManager; class LoadbalancerProperties; @@ -55,11 +56,15 @@ class Loadbalancer : public AgentRefCount, const boost::uuids::uuid &uuid() const { return uuid_; } + void SetIFMapNodeState(IFMapDependencyManager::IFMapNodePtr ref) { + ifmap_node_state_ref_ = ref; + } + private: boost::uuids::uuid uuid_; IFMapNode *node_; std::auto_ptr properties_; - + IFMapDependencyManager::IFMapNodePtr ifmap_node_state_ref_; DISALLOW_COPY_AND_ASSIGN(Loadbalancer); }; @@ -89,6 +94,7 @@ class LoadbalancerTable : public AgentDBTable { * Convert the ifmap node to a (key,data) pair stored in the database. */ virtual bool IFNodeToReq(IFMapNode *node, DBRequest &req); + virtual bool IFNodeToUuid(IFMapNode *node, boost::uuids::uuid &u); static DBTableBase *CreateTable(DB *db, const std::string &name); diff --git a/src/vnsw/agent/oper/logical_interface.cc b/src/vnsw/agent/oper/logical_interface.cc index db5fb2677ad..83f39af6576 100644 --- a/src/vnsw/agent/oper/logical_interface.cc +++ b/src/vnsw/agent/oper/logical_interface.cc @@ -220,10 +220,7 @@ void VlanLogicalInterface::SetSandeshData(SandeshLogicalInterface *data) const { // Config handling routines ///////////////////////////////////////////////////////////////////////////// static LogicalInterfaceKey *BuildKey(IFMapNode *node, - const autogen::LogicalInterface *port) { - autogen::IdPermsType id_perms = port->id_perms(); - boost::uuids::uuid u; - CfgUuidSet(id_perms.uuid.uuid_mslong, id_perms.uuid.uuid_lslong, u); + boost::uuids::uuid &u) { return new VlanLogicalInterfaceKey(u, node->name()); } @@ -283,13 +280,29 @@ static LogicalInterfaceData *BuildData(Agent *agent, IFMapNode *node, port->vlan_tag()); } +bool InterfaceTable::LogicalInterfaceIFNodeToUuid(IFMapNode *node, + boost::uuids::uuid &u) { + + autogen::LogicalInterface *port = + static_cast (node->GetObject()); + assert(port); + + autogen::IdPermsType id_perms = port->id_perms(); + CfgUuidSet(id_perms.uuid.uuid_mslong, id_perms.uuid.uuid_lslong, u); + return true; +} + bool InterfaceTable::LogicalInterfaceIFNodeToReq(IFMapNode *node, DBRequest &req) { autogen::LogicalInterface *port = static_cast (node->GetObject()); assert(port); - req.key.reset(BuildKey(node, port)); + boost::uuids::uuid u; + if (agent()->cfg_listener()->GetCfgDBStateUuid(node, u) == false) + return false; + + req.key.reset(BuildKey(node, u)); if (node->IsDeleted()) { req.oper = DBRequest::DB_ENTRY_DELETE; return true; diff --git a/src/vnsw/agent/oper/mac_vm_binding.cc b/src/vnsw/agent/oper/mac_vm_binding.cc deleted file mode 100644 index 905b4272ddd..00000000000 --- a/src/vnsw/agent/oper/mac_vm_binding.cc +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved. - */ - -#include -#include -#include - -#include "base/logging.h" -#include "db/db.h" -#include "db/db_entry.h" -#include "db/db_table.h" -#include "net/address_util.h" - -#include "oper/operdb_init.h" -#include "oper/agent_types.h" -#include "oper/mac_vm_binding.h" -#include "oper/interface.h" -#include "oper/vm_interface.h" -#include "oper/vn.h" - -MacVmBinding::MacVmBinding() : mac_vm_binding_set_() { -} - -MacVmBinding::~MacVmBinding() { -} - -void MacVmBinding::AddMacVmBinding(const VmInterface *vm_interface) { - UpdateBinding(vm_interface, false); -} - -void MacVmBinding::DeleteMacVmBinding(const VmInterface *vm_interface) { - UpdateBinding(vm_interface, true); -} - -void MacVmBinding::UpdateBinding(const VmInterface *vm_interface, - bool del) { - if (vm_interface->vm_mac().empty()) - return; - - boost::system::error_code ec; - MacAddress address(vm_interface->vm_mac(), &ec); - if (ec) { - return; - } - - MacVmBindingSet::iterator it = FindInterfaceUsingMac(address, vm_interface); - if (it != mac_vm_binding_set_.end()) - mac_vm_binding_set_.erase(it); - - if (!del) { - if (!vm_interface->vn() || vm_interface->vn()->GetVxLanId() == 0) { - return; - } - // assumed that VM mac does not change - MacVmBindingKey key(address, vm_interface->vn()->GetVxLanId(), - vm_interface); - mac_vm_binding_set_.insert(key); - } -} - -MacVmBinding::MacVmBindingSet::iterator -MacVmBinding::FindInterfaceUsingMac(MacAddress &address, - const Interface *interface) { - MacVmBindingSet::iterator it = - mac_vm_binding_set_.lower_bound(MacVmBindingKey(address, 0, NULL)); - while (it != mac_vm_binding_set_.end()) { - if (it->interface == interface) - return it; - it++; - } - - return it; -} - -const Interface * -MacVmBinding::FindMacVmBinding(const MacAddress &address, int vxlan) const { - MacVmBindingKey key(address, vxlan, NULL); - MacVmBindingSet::iterator it = mac_vm_binding_set_.find(key); - if (it == mac_vm_binding_set_.end()) - return NULL; - return it->interface.get(); -} diff --git a/src/vnsw/agent/oper/mac_vm_binding.h b/src/vnsw/agent/oper/mac_vm_binding.h deleted file mode 100644 index 0a6c9bd0b0c..00000000000 --- a/src/vnsw/agent/oper/mac_vm_binding.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved. - */ - -#ifndef vnsw_agent_mac_vm_binding_h_ -#define vnsw_agent_mac_vm_binding_h_ - -#include -#include - -class VmInterface; - -class MacVmBinding { -public: - MacVmBinding(); - virtual ~MacVmBinding(); - const Interface *FindMacVmBinding(const MacAddress &address, - int vxlan) const; - void AddMacVmBinding(const VmInterface *vm_interface); - void DeleteMacVmBinding(const VmInterface *vm_interface); - -private: - struct MacVmBindingKey { - MacAddress mac; - int vxlan; - InterfaceConstRef interface; - - MacVmBindingKey(const MacAddress &m, int v, InterfaceConstRef intf) : - mac(m), vxlan(v), interface(intf) {} - bool operator<(const MacVmBindingKey &rhs) const { - if (mac != rhs.mac) - return mac < rhs.mac; - - return vxlan < rhs.vxlan; - } - }; - typedef std::set MacVmBindingSet; - void UpdateBinding(const VmInterface *vm_interface, bool del); - MacVmBindingSet::iterator FindInterfaceUsingMac(MacAddress &address, - const Interface *interface); - - MacVmBindingSet mac_vm_binding_set_; -}; - -#endif // vnsw_agent_mac_vm_binding_h_ diff --git a/src/vnsw/agent/oper/multicast.cc b/src/vnsw/agent/oper/multicast.cc index 68526524139..104a51f89ed 100644 --- a/src/vnsw/agent/oper/multicast.cc +++ b/src/vnsw/agent/oper/multicast.cc @@ -946,9 +946,11 @@ void MulticastHandler::Shutdown() { GetMulticastObjList().begin(); it != GetMulticastObjList().end(); it++) { MulticastGroupObject *obj = (*it); + BridgeAgentRouteTable *bridge_table = + static_cast + (agent_->vrf_table()->GetBridgeRouteTable(obj->vrf_name())); AgentRoute *route = - BridgeAgentRouteTable::FindRoute(agent_, obj->vrf_name(), - MacAddress::BroadcastMac()); + bridge_table->FindRoute(MacAddress::BroadcastMac()); if (route == NULL) return; diff --git a/src/vnsw/agent/oper/oper_db.h b/src/vnsw/agent/oper/oper_db.h index 4ffd2a81fcf..deb2f83f3f2 100644 --- a/src/vnsw/agent/oper/oper_db.h +++ b/src/vnsw/agent/oper/oper_db.h @@ -29,36 +29,62 @@ struct AgentOperDBKey : public AgentKey { }; struct AgentOperDBData : public AgentData { - AgentOperDBData(Agent *agent, IFMapNode *node) : - AgentData(), ifmap_node_(NULL) { - SetIFMapNode(agent, node); + + AgentOperDBData(const Agent *agent, IFMapNode *node) : + AgentData(), agent_(agent) { + SetIFMapNode(node); + } + virtual ~AgentOperDBData() { + SetIFMapNode(NULL); } - virtual ~AgentOperDBData() { } - void SetIFMapNode(Agent *agent, IFMapNode *node) { - if (node == NULL) + + void SetIFMapNode(IFMapNode *node) { + + if (node == NULL) { + ifmap_node_state_ = NULL; return; - IFMapDependencyManager *dep = agent->oper_db()->dependency_manager(); - dep->SetState(node); - ifmap_node_ = node; + } + + assert(agent_); + + // We dont allow changing the node + assert(!ifmap_node_state_); + + IFMapDependencyManager *dep = agent_->oper_db()->dependency_manager(); + ifmap_node_state_ = dep->SetState(node); } - IFMapNode *ifmap_node() const { return ifmap_node_; } + IFMapNode *ifmap_node() const { + if (!ifmap_node_state_) + return NULL; + IFMapNodeState *state = ifmap_node_state_.get(); + return state->node(); + } private: + const Agent *agent_; // IFMap Node pointer for the object - IFMapNode *ifmap_node_; + IFMapDependencyManager::IFMapNodePtr ifmap_node_state_; }; class AgentOperDBEntry : public AgentDBEntry { public: - AgentOperDBEntry() : AgentDBEntry(), ifmap_node_(NULL) { } + AgentOperDBEntry() : AgentDBEntry() { } virtual ~AgentOperDBEntry() { } - IFMapNode *ifmap_node() const { return ifmap_node_; } + IFMapNode *ifmap_node() const { + if (!ifmap_node_state_) + return NULL; + IFMapNodeState *state = ifmap_node_state_.get(); + return state->node(); + } + + void SetIFMapNodeState(IFMapDependencyManager::IFMapNodePtr sref) { + ifmap_node_state_ = sref; + } private: friend class AgentOperDBTable; - // IFMapNode for the DBEntry - IFMapNode *ifmap_node_; + IFMapDependencyManager::IFMapNodePtr ifmap_node_state_; DISALLOW_COPY_AND_ASSIGN(AgentOperDBEntry); }; @@ -91,9 +117,9 @@ class AgentOperDBTable : public AgentDBTable { return; AgentOperDBEntry *agent_entry = static_cast(entry); - if (agent_entry->ifmap_node_) { + if (agent_entry->ifmap_node()) { DBRequest req; - if (IFNodeToReq(agent_entry->ifmap_node_, req) == true) { + if (IFNodeToReq(agent_entry->ifmap_node(), req) == true) { Enqueue(&req); } } @@ -106,16 +132,21 @@ class AgentOperDBTable : public AgentDBTable { if (entry == NULL) return; - if (entry->ifmap_node_ == node) + IFMapNode *old_node = entry->ifmap_node(); + + if (old_node == node) return; IFMapDependencyManager *dep = agent()->oper_db()->dependency_manager(); - if (entry->ifmap_node_ != NULL) - dep->ResetObject(entry->ifmap_node_); + if (old_node) { + dep->SetObject(old_node, NULL); + entry->SetIFMapNodeState(NULL); + } - entry->ifmap_node_ = node; - if (entry->ifmap_node_) + if (node) { + entry->SetIFMapNodeState(dep->SetState(node)); dep->SetObject(node, entry); + } } // Implement Add, Delete, OnChange to provide common agent functionality @@ -123,7 +154,6 @@ class AgentOperDBTable : public AgentDBTable { virtual DBEntry *Add(const DBRequest *req) { AgentOperDBEntry *entry = static_cast (OperDBAdd(req)); - AgentOperDBData *data = static_cast(req->data.get()); if (data && data->ifmap_node()) UpdateIfMapNode(entry, data->ifmap_node()); @@ -153,6 +183,7 @@ class AgentOperDBTable : public AgentDBTable { virtual bool Delete(DBEntry *entry, const DBRequest *req) { AgentOperDBEntry *oper_entry = static_cast(entry); bool ret = OperDBDelete(entry, req); + UpdateIfMapNode(oper_entry, NULL); return ret; } diff --git a/src/vnsw/agent/oper/operdb_init.cc b/src/vnsw/agent/oper/operdb_init.cc index a77da400e1e..f279ae8a3d7 100644 --- a/src/vnsw/agent/oper/operdb_init.cc +++ b/src/vnsw/agent/oper/operdb_init.cc @@ -160,12 +160,14 @@ void OperDB::CreateDBTables(DB *db) { db->CreateTable("db.service-instance.0")); agent_->set_service_instance_table(si_table); si_table->Initialize(agent_->cfg()->cfg_graph(), dependency_manager_.get()); + si_table->set_agent(agent_); LoadbalancerTable *lb_table = static_cast(db->CreateTable("db.loadbalancer-pool.0")); agent_->set_loadbalancer_table(lb_table); lb_table->Initialize(agent_->cfg()->cfg_graph(), dependency_manager_.get()); + lb_table->set_agent(agent_); PhysicalDeviceTable *dev_table = DBTableCreate(db, agent_, this, diff --git a/src/vnsw/agent/oper/operdb_init.h b/src/vnsw/agent/oper/operdb_init.h index 56058f9e526..681449c0fd1 100644 --- a/src/vnsw/agent/oper/operdb_init.h +++ b/src/vnsw/agent/oper/operdb_init.h @@ -17,7 +17,6 @@ class PathPreferenceModule; class IFMapDependencyManager; class MulticastHandler; class InstanceManager; -class MacVmBinding; class NexthopManager; class OperDB { diff --git a/src/vnsw/agent/oper/peer.h b/src/vnsw/agent/oper/peer.h index 88a5c18ec6a..c5f27e44749 100644 --- a/src/vnsw/agent/oper/peer.h +++ b/src/vnsw/agent/oper/peer.h @@ -22,6 +22,7 @@ #define MULTICAST_PEER_NAME "Multicast" #define MULTICAST_TOR_PEER_NAME "Multicast TOR" #define MULTICAST_FABRIC_TREE_BUILDER_NAME "MulticastTreeBuilder" +#define MAC_VM_BINDING_PEER_NAME "MacVmBindingPeer" class AgentXmppChannel; class ControllerRouteWalker; @@ -45,7 +46,8 @@ class Peer { VGW_PEER, MULTICAST_FABRIC_TREE_BUILDER, OVS_PEER, - MULTICAST_TOR_PEER + MULTICAST_TOR_PEER, + MAC_VM_BINDING_PEER }; Peer(Type type, const std::string &name, bool controller_export); diff --git a/src/vnsw/agent/oper/physical_device.cc b/src/vnsw/agent/oper/physical_device.cc index df2093b93ee..7f17b26de28 100644 --- a/src/vnsw/agent/oper/physical_device.cc +++ b/src/vnsw/agent/oper/physical_device.cc @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -174,10 +175,8 @@ void PhysicalDeviceTable::RegisterDBClients(IFMapDependencyManager *dep) { autogen::PhysicalRouter::ID_PERMS); } -static PhysicalDeviceKey *BuildKey(const autogen::PhysicalRouter *router) { - autogen::IdPermsType id_perms = router->id_perms(); - boost::uuids::uuid u; - CfgUuidSet(id_perms.uuid.uuid_mslong, id_perms.uuid.uuid_lslong, u); +static PhysicalDeviceKey *BuildKey(const autogen::PhysicalRouter + *router, boost::uuids::uuid &u) { return new PhysicalDeviceKey(u); } @@ -192,12 +191,24 @@ static PhysicalDeviceData *BuildData(Agent *agent, IFMapNode *node, router->vendor_name(), ip, mip, "OVS", node); } +bool PhysicalDeviceTable::IFNodeToUuid(IFMapNode *node, boost::uuids::uuid &u) { + autogen::PhysicalRouter *router = static_cast + (node->GetObject()); + autogen::IdPermsType id_perms = router->id_perms(); + CfgUuidSet(id_perms.uuid.uuid_mslong, id_perms.uuid.uuid_lslong, u); + return true; +} + bool PhysicalDeviceTable::IFNodeToReq(IFMapNode *node, DBRequest &req) { autogen::PhysicalRouter *router = static_cast (node->GetObject()); assert(router); - req.key.reset(BuildKey(router)); + boost::uuids::uuid u; + if (agent()->cfg_listener()->GetCfgDBStateUuid(node, u) == false) + return false; + + req.key.reset(BuildKey(router, u)); if (node->IsDeleted()) { req.oper = DBRequest::DB_ENTRY_DELETE; agent()->physical_device_vn_table()->ConfigUpdate(node); diff --git a/src/vnsw/agent/oper/physical_device.h b/src/vnsw/agent/oper/physical_device.h index a2fdcfea44d..2430b0192a8 100644 --- a/src/vnsw/agent/oper/physical_device.h +++ b/src/vnsw/agent/oper/physical_device.h @@ -96,6 +96,7 @@ class PhysicalDeviceTable : public AgentOperDBTable { virtual bool OperDBOnChange(DBEntry *entry, const DBRequest *req); virtual bool OperDBDelete(DBEntry *entry, const DBRequest *req); virtual bool IFNodeToReq(IFMapNode *node, DBRequest &req); + virtual bool IFNodeToUuid(IFMapNode *node, boost::uuids::uuid &u); PhysicalDevice *Find(const boost::uuids::uuid &u); diff --git a/src/vnsw/agent/oper/physical_device_vn.cc b/src/vnsw/agent/oper/physical_device_vn.cc index ae178a0e35c..a022b8b8252 100644 --- a/src/vnsw/agent/oper/physical_device_vn.cc +++ b/src/vnsw/agent/oper/physical_device_vn.cc @@ -105,7 +105,6 @@ bool PhysicalDeviceVnTable::OnChange(DBEntry *e, const DBRequest *req) { PhysicalDeviceVnData *data = static_cast(req->data.get()); bool ret = entry->Copy(this, data); - entry->SendObjectLog(AgentLogEvent::CHANGE); return ret; } @@ -114,7 +113,6 @@ bool PhysicalDeviceVnTable::Resync(DBEntry *e, const DBRequest *req) { PhysicalDeviceVnData *data = static_cast(req->data.get()); bool ret = entry->Copy(this, data); - entry->SendObjectLog(AgentLogEvent::RESYNC); return ret; } diff --git a/src/vnsw/agent/oper/service_instance.cc b/src/vnsw/agent/oper/service_instance.cc index eec009f48ca..642ec68d449 100644 --- a/src/vnsw/agent/oper/service_instance.cc +++ b/src/vnsw/agent/oper/service_instance.cc @@ -10,6 +10,7 @@ #include "oper/ifmap_dependency_manager.h" #include "oper/operdb_init.h" #include +#include #include #include #include @@ -672,6 +673,8 @@ DBEntry *ServiceInstanceTable::Add(const DBRequest *request) { static_cast(request->data.get()); svc_instance->set_node(data->node()); assert(dependency_manager_); + svc_instance->SetIFMapNodeState + (dependency_manager_->SetState(data->node())); dependency_manager_->SetObject(data->node(), svc_instance); return svc_instance; @@ -680,7 +683,8 @@ DBEntry *ServiceInstanceTable::Add(const DBRequest *request) { bool ServiceInstanceTable::Delete(DBEntry *entry, const DBRequest *request) { ServiceInstance *svc_instance = static_cast(entry); assert(dependency_manager_); - dependency_manager_->ResetObject(svc_instance->node()); + dependency_manager_->SetObject(svc_instance->node(), NULL); + svc_instance->SetIFMapNodeState(NULL); return true; } @@ -716,10 +720,11 @@ void ServiceInstanceTable::Initialize( } bool ServiceInstanceTable::IFNodeToReq(IFMapNode *node, DBRequest &request) { - autogen::ServiceInstance *svc_instance = - static_cast(node->GetObject()); - const autogen::IdPermsType &id = svc_instance->id_perms(); - request.key.reset(new ServiceInstanceKey(IdPermsGetUuid(id))); + uuid id; + if (agent()->cfg_listener()->GetCfgDBStateUuid(node, id) == false) + return false; + + request.key.reset(new ServiceInstanceKey(id)); if (!node->IsDeleted()) { request.oper = DBRequest::DB_ENTRY_ADD_CHANGE; request.data.reset(new ServiceInstanceCreate(node)); @@ -729,6 +734,13 @@ bool ServiceInstanceTable::IFNodeToReq(IFMapNode *node, DBRequest &request) { return true; } +bool ServiceInstanceTable::IFNodeToUuid(IFMapNode *node, uuid &idperms_uuid) { + autogen::ServiceInstance *svc_instance = + static_cast(node->GetObject()); + const autogen::IdPermsType &id = svc_instance->id_perms(); + idperms_uuid = IdPermsGetUuid(id); + return true; +} void ServiceInstanceTable::ChangeEventHandler(DBEntry *entry) { ServiceInstance *svc_instance = static_cast(entry); diff --git a/src/vnsw/agent/oper/service_instance.h b/src/vnsw/agent/oper/service_instance.h index fd6ae2d10bb..32572c1f471 100644 --- a/src/vnsw/agent/oper/service_instance.h +++ b/src/vnsw/agent/oper/service_instance.h @@ -8,6 +8,7 @@ #include #include #include "cmn/agent_db.h" +#include "oper/ifmap_dependency_manager.h" class DBGraph; class IFMapDependencyManager; @@ -122,10 +123,15 @@ class ServiceInstance : public AgentRefCount, bool IsUsable() const; + void SetIFMapNodeState(IFMapDependencyManager::IFMapNodePtr ref) { + ifmap_node_state_ref_ = ref; + } + private: boost::uuids::uuid uuid_; IFMapNode *node_; Properties properties_; + IFMapDependencyManager::IFMapNodePtr ifmap_node_state_ref_; DISALLOW_COPY_AND_ASSIGN(ServiceInstance); }; @@ -155,6 +161,7 @@ class ServiceInstanceTable : public AgentDBTable { * Convert the ifmap node to a (key,data) pair stored in the database. */ virtual bool IFNodeToReq(IFMapNode *node, DBRequest &req); + virtual bool IFNodeToUuid(IFMapNode *node, boost::uuids::uuid &id); static DBTableBase *CreateTable(DB *db, const std::string &name); diff --git a/src/vnsw/agent/oper/sg.cc b/src/vnsw/agent/oper/sg.cc index a1226b4b13a..9c34538f109 100644 --- a/src/vnsw/agent/oper/sg.cc +++ b/src/vnsw/agent/oper/sg.cc @@ -100,13 +100,21 @@ DBTableBase *SgTable::CreateTable(DB *db, const std::string &name) { return sg_table_; }; -bool SgTable::IFNodeToReq(IFMapNode *node, DBRequest &req) { +bool SgTable::IFNodeToUuid(IFMapNode *node, boost::uuids::uuid &u) { SecurityGroup *cfg = static_cast(node->GetObject()); assert(cfg); - autogen::IdPermsType id_perms = cfg->id_perms(); - boost::uuids::uuid u; CfgUuidSet(id_perms.uuid.uuid_mslong, id_perms.uuid.uuid_lslong, u); + return true; +} + +bool SgTable::IFNodeToReq(IFMapNode *node, DBRequest &req) { + SecurityGroup *cfg = static_cast(node->GetObject()); + assert(cfg); + + uuid u; + if (agent()->cfg_listener()->GetCfgDBStateUuid(node, u) == false) + return false; SgKey *key = new SgKey(u); SgData *data = NULL; @@ -177,6 +185,28 @@ bool SgTable::IFNodeToReq(IFMapNode *node, DBRequest &req) { return false; } +bool SgTable::IFLinkToReq(IFMapLink *link, IFMapNode *node, + const std::string &peer_type, IFMapNode *peer, + DBRequest &req) { + // Add/Delete of link other than VMInterface will most likely need re-eval + // of VN. + if (peer_type != "virtual-machine-interface") { + return IFNodeToReq(node, req); + } + + // If peer is VMI, invoke re-eval if peer node is present + if (peer && peer->table() == agent()->cfg()->cfg_vm_interface_table()) { + DBRequest vmi_req; + if (agent()->interface_table()->IFNodeToReq(peer, vmi_req) == true) { + LOG(DEBUG, "SG change sync for Port " << peer->name()); + agent()->interface_table()->Enqueue(&vmi_req); + } + return false; + } + + return false; +} + bool SgEntry::DBEntrySandesh(Sandesh *sresp, std::string &name) const { SgListResp *resp = static_cast(sresp); std::string str_uuid = UuidToString(GetSgUuid()); diff --git a/src/vnsw/agent/oper/sg.h b/src/vnsw/agent/oper/sg.h index e23104e6723..3d7c6fe317e 100644 --- a/src/vnsw/agent/oper/sg.h +++ b/src/vnsw/agent/oper/sg.h @@ -83,6 +83,10 @@ class SgTable : public AgentDBTable { virtual bool Delete(DBEntry *entry, const DBRequest *req); virtual bool IFNodeToReq(IFMapNode *node, DBRequest &req); + virtual bool IFNodeToUuid(IFMapNode *node, boost::uuids::uuid &u); + virtual bool IFLinkToReq(IFMapLink *link, IFMapNode *node, + const std::string &peer_type, IFMapNode *peer, + DBRequest &req); static DBTableBase *CreateTable(DB *db, const std::string &name); static SgTable *GetInstance() {return sg_table_;}; diff --git a/src/vnsw/agent/oper/test/ifmap_dependency_manager_test.cc b/src/vnsw/agent/oper/test/ifmap_dependency_manager_test.cc index 7ec81cadbaf..bc332def3a7 100644 --- a/src/vnsw/agent/oper/test/ifmap_dependency_manager_test.cc +++ b/src/vnsw/agent/oper/test/ifmap_dependency_manager_test.cc @@ -141,7 +141,7 @@ class IFMapDependencyManagerTest : public ::testing::Test { for (DBEntry *entry = tslice->GetFirst(); entry; entry = tslice->GetNext(entry)) { TestEntry *test_entry = static_cast(entry); - manager_->ResetObject(test_entry->node()); + manager_->SetObject(test_entry->node(), NULL); test_entry->reset_node(); list.push_back(test_entry->name()); } diff --git a/src/vnsw/agent/oper/test/loadbalancer_test.cc b/src/vnsw/agent/oper/test/loadbalancer_test.cc index 3cc9d313b24..1de13068d45 100644 --- a/src/vnsw/agent/oper/test/loadbalancer_test.cc +++ b/src/vnsw/agent/oper/test/loadbalancer_test.cc @@ -48,15 +48,15 @@ class LoadbalancerTest : public ::testing::Test { } virtual void TearDown() { - manager_->Terminate(); + loadbalancer_table_->Clear(); config_listener_.Shutdown(); + manager_->Terminate(); IFMapLinkTable *link_table = static_cast( database_.FindTable(IFMAP_AGENT_LINK_DB_NAME)); assert(link_table); link_table->Clear(); - loadbalancer_table_->Clear(); db_util::Clear(&database_); DB::ClearFactoryRegistry(); } @@ -172,6 +172,7 @@ TEST_F(LoadbalancerTest, ConfigPool) { EXPECT_EQ("127.0.0.1", addresses.at(0)); EXPECT_EQ("127.0.0.2", addresses.at(1)); ASSERT_EQ(2, props->healthmonitors().size()); + manager_->SetObject(loadbalancer->node(), NULL); } static void SetUp() { diff --git a/src/vnsw/agent/oper/test/physical-device-vn.xml b/src/vnsw/agent/oper/test/physical-device-vn.xml index 99e7d238313..c2844c37fc2 100644 --- a/src/vnsw/agent/oper/test/physical-device-vn.xml +++ b/src/vnsw/agent/oper/test/physical-device-vn.xml @@ -1,6 +1,9 @@ - + + + @@ -93,4 +96,116 @@ /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/vnsw/agent/oper/test/test_intf.cc b/src/vnsw/agent/oper/test/test_intf.cc index db8615b7e24..4d0b69db9aa 100644 --- a/src/vnsw/agent/oper/test/test_intf.cc +++ b/src/vnsw/agent/oper/test/test_intf.cc @@ -2637,6 +2637,29 @@ TEST_F(IntfTest, VrfTranslateAddDelete) { client->WaitForIdle(); } +TEST_F(IntfTest, VMI_Sequence_1) { + AddVn("vn1", 1); + AddPort("vmi1", 1, ""); + client->WaitForIdle(); + + AddLink("virtual-machine-interface", "vmi1", "virtual-network", "vn1"); + AddVrf("vrf1"); + AddLink("virtual-network", "vn1", "routing-instance", "vrf1"); + client->WaitForIdle(); + + VrfEntry *vrf = VrfGet("vrf1"); + VnEntry *vn = VnGet(1); + EXPECT_TRUE(vn->GetVrf() != NULL); + EXPECT_TRUE(vrf->vn() != NULL); + + DelLink("virtual-machine-interface", "vmi1", "virtual-network", "vn1"); + DelLink("virtual-network", "vn1", "routing-instance", "vrf1"); + DelVrf("vrf1"); + DelVn("vn1"); + DelPort("vmi1"); + client->WaitForIdle(); +} + int main(int argc, char **argv) { GETUSERARGS(); diff --git a/src/vnsw/agent/oper/vm.cc b/src/vnsw/agent/oper/vm.cc index 498a4d91ca1..6d6fe121360 100644 --- a/src/vnsw/agent/oper/vm.cc +++ b/src/vnsw/agent/oper/vm.cc @@ -11,6 +11,7 @@ #include #include #include +#include using namespace std; using namespace autogen; @@ -114,16 +115,22 @@ DBTableBase *VmTable::CreateTable(DB *db, const std::string &name) { vm_table_->Init(); return vm_table_; }; - -bool VmTable::IFNodeToReq(IFMapNode *node, DBRequest &req){ +bool VmTable::IFNodeToUuid(IFMapNode *node, boost::uuids::uuid &u) { VirtualMachine *cfg = static_cast (node->GetObject()); assert(cfg); autogen::IdPermsType id_perms = cfg->id_perms(); - boost::uuids::uuid u; CfgUuidSet(id_perms.uuid.uuid_mslong, id_perms.uuid.uuid_lslong, u); + return true; +} + +bool VmTable::IFNodeToReq(IFMapNode *node, DBRequest &req){ + uuid id; + if (agent()->cfg_listener()->GetCfgDBStateUuid(node, id) == false) + return false; + string virtual_router_type = "none"; - VmKey *key = new VmKey(u); + VmKey *key = new VmKey(id); VmData *data = NULL; if (node->IsDeleted()) { req.oper = DBRequest::DB_ENTRY_DELETE; diff --git a/src/vnsw/agent/oper/vm.h b/src/vnsw/agent/oper/vm.h index 1649b0360db..af1f3c82b38 100644 --- a/src/vnsw/agent/oper/vm.h +++ b/src/vnsw/agent/oper/vm.h @@ -70,6 +70,7 @@ class VmTable : public AgentDBTable { virtual bool OnChange(DBEntry *entry, const DBRequest *req); virtual bool Delete(DBEntry *entry, const DBRequest *req); virtual bool IFNodeToReq(IFMapNode *node, DBRequest &req); + virtual bool IFNodeToUuid(IFMapNode *node, boost::uuids::uuid &u); static DBTableBase *CreateTable(DB *db, const std::string &name); static VmTable *GetInstance() {return vm_table_;} diff --git a/src/vnsw/agent/oper/vm_interface.cc b/src/vnsw/agent/oper/vm_interface.cc index 9593c9f4705..3d3ce157b23 100644 --- a/src/vnsw/agent/oper/vm_interface.cc +++ b/src/vnsw/agent/oper/vm_interface.cc @@ -31,7 +31,6 @@ #include #include #include -#include #include #include @@ -708,11 +707,10 @@ static void ComputeTypeInfo(Agent *agent, VmInterfaceConfigData *data, autogen::LogicalInterface *port = static_cast (logical_node->GetObject()); - data->rx_vlan_id_ = port->vlan_tag(); - data->tx_vlan_id_ = port->vlan_tag(); - } else { - data->rx_vlan_id_ = 0; - data->tx_vlan_id_ = 0; + if (port->vlan_tag()) { + data->rx_vlan_id_ = port->vlan_tag(); + data->tx_vlan_id_ = port->vlan_tag(); + } } return; } else { @@ -765,6 +763,15 @@ static bool DeleteVmi(InterfaceTable *table, const uuid &u, DBRequest *req) { } } +bool InterfaceTable::VmiIFNodeToUuid(IFMapNode *node, boost::uuids::uuid &u) { + + VirtualMachineInterface *cfg = static_cast + (node->GetObject()); + autogen::IdPermsType id_perms = cfg->id_perms(); + CfgUuidSet(id_perms.uuid.uuid_mslong, id_perms.uuid.uuid_lslong, u); + return true; +} + // Virtual Machine Interface is added or deleted into oper DB from Nova // messages. The Config notify is used only to change interface. bool InterfaceTable::VmiIFNodeToReq(IFMapNode *node, DBRequest &req) { @@ -772,9 +779,9 @@ bool InterfaceTable::VmiIFNodeToReq(IFMapNode *node, DBRequest &req) { VirtualMachineInterface *cfg = static_cast (node->GetObject()); assert(cfg); - autogen::IdPermsType id_perms = cfg->id_perms(); - boost::uuids::uuid u; - CfgUuidSet(id_perms.uuid.uuid_mslong, id_perms.uuid.uuid_lslong, u); + uuid u; + if (agent()->cfg_listener()->GetCfgDBStateUuid(node, u) == false) + return false; // Handle object delete if (node->IsDeleted()) { @@ -789,8 +796,8 @@ bool InterfaceTable::VmiIFNodeToReq(IFMapNode *node, DBRequest &req) { // Update interface configuration req.oper = DBRequest::DB_ENTRY_ADD_CHANGE; - VmInterfaceConfigData *data = new VmInterfaceConfigData(NULL, NULL); - data->SetIFMapNode(agent(), node); + VmInterfaceConfigData *data = new VmInterfaceConfigData(agent(), NULL); + data->SetIFMapNode(node); IFMapNode *vn_node = NULL; @@ -987,6 +994,7 @@ bool VmInterface::Resync(const InterfaceTable *table, Ip4Address old_subnet = subnet_; uint8_t old_subnet_plen = subnet_plen_; int old_ethernet_tag = ethernet_tag_; + bool old_dhcp_enable = dhcp_enable_; if (data) { ret = data->OnResync(table, this, &sg_changed, &ecmp_changed, @@ -1017,7 +1025,8 @@ bool VmInterface::Resync(const InterfaceTable *table, ApplyConfig(old_ipv4_active, old_l2_active, old_policy, old_vrf.get(), old_addr, old_ethernet_tag, old_need_linklocal_ip, sg_changed, old_ipv6_active, old_v6_addr, ecmp_changed, - local_pref_changed, old_subnet, old_subnet_plen); + local_pref_changed, old_subnet, old_subnet_plen, + old_dhcp_enable); return ret; } @@ -1163,6 +1172,35 @@ const MacAddress& VmInterface::GetVifMac(const Agent *agent) const { } } +void VmInterface::ApplyConfigCommon(const VrfEntry *old_vrf, + bool old_l2_active, + bool old_dhcp_enable) { + //DHCP MAC IP binding + ApplyMacVmBindingConfig(old_vrf, old_l2_active, old_dhcp_enable); + //Security Group update + if (IsActive()) + UpdateSecurityGroup(); + else + DeleteSecurityGroup(); + +} + +void VmInterface::ApplyMacVmBindingConfig(const VrfEntry *old_vrf, + bool old_l2_active, + bool old_dhcp_enable) { + if (L2Deactivated(old_l2_active)) { + DeleteMacVmBinding(old_vrf); + return; + } + + //Interface has been activated or + //dhcp toggled for already activated interface + if (L2Activated(old_l2_active) || + (l2_active_ && (old_dhcp_enable != dhcp_enable_))) { + UpdateMacVmBinding(); + } +} + // Apply the latest configuration void VmInterface::ApplyConfig(bool old_ipv4_active, bool old_l2_active, bool old_policy, VrfEntry *old_vrf, const Ip4Address &old_addr, @@ -1171,19 +1209,9 @@ void VmInterface::ApplyConfig(bool old_ipv4_active, bool old_l2_active, bool old const Ip6Address &old_v6_addr, bool ecmp_mode_changed, bool local_pref_changed, const Ip4Address &old_subnet, - uint8_t old_subnet_plen) { - //MAC VM binding is handled for all VM interface - if (l2_active_ && bridging_) { - UpdateMacVmBinding(old_l2_active); - } else { - DeleteMacVmBinding(old_l2_active); - } - - if (IsActive()) - UpdateSecurityGroup(); - else - DeleteSecurityGroup(); - + uint8_t old_subnet_plen, + bool old_dhcp_enable) { + ApplyConfigCommon(old_vrf, old_l2_active, old_dhcp_enable); //Need not apply config for TOR VMI as it is more of an inidicative //interface. No route addition or NH addition happens for this interface. if (device_type_ == VmInterface::TOR && @@ -2077,46 +2105,14 @@ void VmInterface::UpdateFlowKeyNextHop() { agent->nexthop_table()->FindActiveEntry(&key)); } -void VmInterface::UpdateMacVmBinding(bool old_l2_active) { - if (L2Activated(old_l2_active)) { - InterfaceTable *table = static_cast(get_table()); - table->mac_vm_binding().AddMacVmBinding(this); - int vxlan_id = vn_.get() ? vn_.get()->GetVxLanId() : 0; - EvpnAgentRouteTable *evpn_table = static_cast - (vrf_.get()->GetEvpnRouteTable()); - EvpnRouteEntry *evpn_rt = - evpn_table->FindRoute(MacAddress::FromString(vm_mac_), Ip4Address(), - vxlan_id); - if (evpn_rt == NULL) - evpn_rt = evpn_table->FindRoute(MacAddress::FromString(vm_mac_), Ip6Address(), - vxlan_id); - if (evpn_rt) { - for(Route::PathList::const_iterator it = evpn_rt->GetPathList().begin(); - it != evpn_rt->GetPathList().end(); it++) { - const AgentPath *path = static_cast(it.operator->()); - if (path) { - path->set_flood_dhcp(!dhcp_enable_config()); - } - } - evpn_table->NotifyEntry(evpn_rt); - } - BridgeRouteEntry *br_rt = - BridgeAgentRouteTable::FindRoute(evpn_table->agent(), - vrf_.get()->GetName(), - MacAddress::FromString(vm_mac_)); - BridgeAgentRouteTable *br_table = static_cast - (vrf_.get()->GetBridgeRouteTable()); - if (br_rt) { - for(Route::PathList::const_iterator it = br_rt->GetPathList().begin(); - it != br_rt->GetPathList().end(); it++) { - const AgentPath *path = static_cast(it.operator->()); - if (path) { - path->set_flood_dhcp(!dhcp_enable_config()); - } - } - br_table->NotifyEntry(br_rt); - } - } +void VmInterface::UpdateMacVmBinding() { + BridgeAgentRouteTable *table = static_cast + (vrf_->GetBridgeRouteTable()); + Agent *agent = table->agent(); + table->AddMacVmBindingRoute(agent->mac_vm_binding_peer(), + vrf_->GetName(), + MacAddress::FromString(vm_mac_), + this); } void VmInterface::UpdateL2NextHop(bool old_l2_active) { @@ -2137,11 +2133,16 @@ void VmInterface::UpdateL3NextHop(bool old_ipv4_active, bool old_ipv6_active) { } } -void VmInterface::DeleteMacVmBinding(bool old_l2_active) { - if (L2Deactivated(old_l2_active)) { - InterfaceTable *table = static_cast(get_table()); - table->mac_vm_binding().DeleteMacVmBinding(this); - } +void VmInterface::DeleteMacVmBinding(const VrfEntry *old_vrf) { + if (old_vrf == NULL) + return; + BridgeAgentRouteTable *table = static_cast + (old_vrf->GetBridgeRouteTable()); + Agent *agent = table->agent(); + table->DeleteMacVmBindingRoute(agent->mac_vm_binding_peer(), + old_vrf->GetName(), + MacAddress::FromString(vm_mac_), + this); } void VmInterface::DeleteL2NextHop(bool old_l2_active) { diff --git a/src/vnsw/agent/oper/vm_interface.h b/src/vnsw/agent/oper/vm_interface.h index 2e7ffc5c539..e28f0601457 100644 --- a/src/vnsw/agent/oper/vm_interface.h +++ b/src/vnsw/agent/oper/vm_interface.h @@ -522,6 +522,12 @@ class VmInterface : public Interface { bool ResyncConfig(VmInterfaceConfigData *data); bool CopyIpAddress(Ip4Address &addr); bool CopyIp6Address(const Ip6Address &addr); + void ApplyMacVmBindingConfig(const VrfEntry *old_vrf, + bool old_l2_active, + bool old_dhcp_enable); + void ApplyConfigCommon(const VrfEntry *old_vrf, + bool old_l2_active, + bool old_dhcp_enable); bool CopyConfig(const InterfaceTable *table, const VmInterfaceConfigData *data, bool *sg_changed, bool *ecmp_changed, bool *local_pref_changed); @@ -531,7 +537,7 @@ class VmInterface : public Interface { bool sg_changed, bool old_ipv6_active, const Ip6Address &old_v6_addr, bool ecmp_changed, bool local_pref_changed, const Ip4Address &old_subnet, - const uint8_t old_subnet_plen); + const uint8_t old_subnet_plen, bool old_dhcp_enable); void UpdateL3(bool old_ipv4_active, VrfEntry *old_vrf, const Ip4Address &old_addr, int old_ethernet_tag, bool force_update, bool policy_change, bool old_ipv6_active, @@ -553,11 +559,11 @@ class VmInterface : public Interface { void DeleteL3TunnelId(); void UpdateMulticastNextHop(bool old_ipv4_active, bool old_l2_active); void DeleteMulticastNextHop(); - void UpdateMacVmBinding(bool old_l2_active); + void UpdateMacVmBinding(); void UpdateL2NextHop(bool old_l2_active); void UpdateFlowKeyNextHop(); void DeleteL2NextHop(bool old_l2_active); - void DeleteMacVmBinding(bool old_l2_active); + void DeleteMacVmBinding(const VrfEntry *old_vrf); void UpdateL3NextHop(bool old_ipv4_active, bool old_ipv6_active); void DeleteL3NextHop(bool old_ipv4_active, bool old_ipv6_active); bool L2Activated(bool old_l2_active); diff --git a/src/vnsw/agent/oper/vn.cc b/src/vnsw/agent/oper/vn.cc index afb159d468c..22ea1e87dd1 100644 --- a/src/vnsw/agent/oper/vn.cc +++ b/src/vnsw/agent/oper/vn.cc @@ -623,7 +623,7 @@ VnData *VnTable::BuildData(IFMapNode *node) { bool bridging = true; bool layer3_forwarding = true; - return new VnData(node->name(), acl_uuid, vrf_name, mirror_acl_uuid, + return new VnData(agent(), node->name(), acl_uuid, vrf_name, mirror_acl_uuid, mirror_cfg_acl_uuid, vn_ipam, vn_ipam_data, cfg->properties().vxlan_network_identifier, cfg->properties().network_id, bridging, layer3_forwarding, @@ -658,38 +658,53 @@ void VnTable::ResyncVmInterface(IFMapNode *node) { } } -bool VnTable::IFLinkToReq(IFMapLink *link, IFMapNode *node, IFMapNode *peer, - DBRequest &req) { + +bool VnTable::IFNodeToUuid(IFMapNode *node, boost::uuids::uuid &u) { VirtualNetwork *cfg = static_cast (node->GetObject()); assert(cfg); autogen::IdPermsType id_perms = cfg->id_perms(); - boost::uuids::uuid u; CfgUuidSet(id_perms.uuid.uuid_mslong, id_perms.uuid.uuid_lslong, u); - req.key.reset(new VnKey(u)); + return true; +} + +bool VnTable::IFLinkToReq(IFMapLink *link, IFMapNode *node, + const string &peer_type, IFMapNode *peer, + DBRequest &req) { + // Add/Delete of link other than VMInterface will most likely need re-eval - // of VN - if (peer->table() != agent()->cfg()->cfg_vm_interface_table()) { + // of VN. + if (peer_type != "virtual-machine-interface") { + VirtualNetwork *cfg = static_cast (node->GetObject()); + assert(cfg); + boost::uuids::uuid u; + agent()->cfg_listener()->GetCfgDBStateUuid(node, u); + req.key.reset(new VnKey(u)); req.data.reset(BuildData(node)); Enqueue(&req); } - // Any change to ACL/IPAM will need re-eval of all VMInterface on this VN - if (peer->table() == agent()->cfg()->cfg_acl_table() || - peer->table() == agent()->cfg()->cfg_vn_network_ipam_table()) { - ResyncVmInterface(node); - } - - if (peer->table() == agent()->cfg()->cfg_vm_interface_table()) { - DBRequest req; - if (agent()->interface_table()->IFNodeToReq(peer, req) == true) { + // If peer is VMI, invoke re-eval if peer node is present + if (peer && peer->table() == agent()->cfg()->cfg_vm_interface_table()) { + DBRequest vmi_req; + if (agent()->interface_table()->IFNodeToReq(peer, vmi_req) == true) { LOG(DEBUG, "VN change sync for Port " << peer->name()); - agent()->interface_table()->Enqueue(&req); + agent()->interface_table()->Enqueue(&vmi_req); } + return false; + } + + // Any change to ACL/IPAM will need re-eval of all VMInterface on this VN + if (peer_type == "virtual-network-network-ipam" || + peer_type == "access-control-list") { + ResyncVmInterface(node); + return false; } - if (peer->table() == agent()->cfg()->cfg_floatingip_pool_table()) { + // If peer is known and is floating-ip pool, propogate change to it + if (peer && peer->table() == agent()->cfg()->cfg_floatingip_pool_table()) { VmInterface::FloatingIpPoolSync(agent()->interface_table(), peer); + return false; } return false; @@ -700,7 +715,9 @@ bool VnTable::IFNodeToReq(IFMapNode *node, DBRequest &req) { assert(cfg); autogen::IdPermsType id_perms = cfg->id_perms(); boost::uuids::uuid u; - CfgUuidSet(id_perms.uuid.uuid_mslong, id_perms.uuid.uuid_lslong, u); + if (agent()->cfg_listener()->GetCfgDBStateUuid(node, u) == false) + return false; + req.key.reset(new VnKey(u)); VnData *data = NULL; @@ -710,7 +727,7 @@ bool VnTable::IFNodeToReq(IFMapNode *node, DBRequest &req) { req.oper = DBRequest::DB_ENTRY_ADD_CHANGE; data = BuildData(node); req.data.reset(data); - data->SetIFMapNode(agent(), node); + data->SetIFMapNode(node); } Enqueue(&req); @@ -756,7 +773,7 @@ void VnTable::AddVn(const uuid &vn_uuid, const string &name, int vxlan_id, bool admin_state, bool enable_rpf) { DBRequest req; VnKey *key = new VnKey(vn_uuid); - VnData *data = new VnData(name, acl_id, vrf_name, nil_uuid(), + VnData *data = new VnData(agent(), name, acl_id, vrf_name, nil_uuid(), nil_uuid(), ipam, vn_ipam_data, vxlan_id, vxlan_id, true, true, admin_state, enable_rpf); diff --git a/src/vnsw/agent/oper/vn.h b/src/vnsw/agent/oper/vn.h index 11311fcef25..8d80e92c4c9 100644 --- a/src/vnsw/agent/oper/vn.h +++ b/src/vnsw/agent/oper/vn.h @@ -83,12 +83,12 @@ struct VnData : public AgentOperDBData { typedef std::map VnIpamDataMap; typedef std::pair VnIpamDataPair; - VnData(const string &name, const uuid &acl_id, const string &vrf_name, - const uuid &mirror_acl_id, const uuid &mc_acl_id, + VnData(const Agent *agent, const string &name, const uuid &acl_id, + const string &vrf_name, const uuid &mirror_acl_id, const uuid &mc_acl_id, const std::vector &ipam, const VnIpamDataMap &vn_ipam_data, int vxlan_id, int vnid, bool bridging, bool layer3_forwarding, bool admin_state, bool enable_rpf) : - AgentOperDBData(NULL, NULL), name_(name), vrf_name_(vrf_name), + AgentOperDBData(agent, NULL), name_(name), vrf_name_(vrf_name), acl_id_(acl_id), mirror_acl_id_(mirror_acl_id), mirror_cfg_acl_id_(mc_acl_id), ipam_(ipam), vn_ipam_data_(vn_ipam_data), vxlan_id_(vxlan_id), vnid_(vnid), bridging_(bridging), @@ -152,7 +152,7 @@ class VnEntry : AgentRefCount, public AgentOperDBEntry { bool ReEvaluateVxlan(VrfEntry *old_vrf, int new_vxlan_id, int new_vnid, bool new_bridging, bool vxlan_network_identifier_mode_changed); - void UpdateDhcpFloodFlag(); + void UpdateMacVmBindingFloodFlag(); const VxLanId *vxlan_id_ref() const {return vxlan_id_ref_.get();} const VxLanId *vxlan_id() const {return vxlan_id_ref_.get();} @@ -209,8 +209,10 @@ class VnTable : public AgentOperDBTable { void ResyncVmInterface(IFMapNode *node); virtual bool IFNodeToReq(IFMapNode *node, DBRequest &req); - virtual bool IFLinkToReq(IFMapLink *link, IFMapNode *node, IFMapNode *peer, + virtual bool IFLinkToReq(IFMapLink *link, IFMapNode *node, + const std::string &peer_type, IFMapNode *peer, DBRequest &req); + virtual bool IFNodeToUuid(IFMapNode *node, boost::uuids::uuid &u); static DBTableBase *CreateTable(DB *db, const std::string &name); static VnTable *GetInstance() {return vn_table_;}; diff --git a/src/vnsw/agent/oper/vrf.cc b/src/vnsw/agent/oper/vrf.cc index e760fb22e85..827d977d0cb 100644 --- a/src/vnsw/agent/oper/vrf.cc +++ b/src/vnsw/agent/oper/vrf.cc @@ -607,23 +607,27 @@ static VrfData *BuildData(Agent *agent, IFMapNode *node) { return new VrfData(VrfData::ConfigVrf, vn_uuid); } -bool VrfTable::IFLinkToReq(IFMapLink *link, IFMapNode *node, IFMapNode *peer, +bool VrfTable::IFLinkToReq(IFMapLink *link, IFMapNode *node, + const string &peer_type, IFMapNode *peer, DBRequest &req) { - req.oper = DBRequest::DB_ENTRY_ADD_CHANGE; - req.key.reset(new VrfKey(node->name())); - - if (peer->table() == agent()->cfg()->cfg_vn_table()) { - // Change in VN neighbour can change VN in the VRF - req.data.reset(BuildData(agent(), node)); - Enqueue(&req); - - // Resync dependent Floating-IP - VmInterface::FloatingIpVnSync(agent()->interface_table(), peer); - } - - // Change to virtual-machine-interface-routing-instance can modify VRF - // in connected VMInterface - if (peer->table() == agent()->cfg()->cfg_vm_port_vrf_table()) { + // If peer is VN, it means there is change in VRF to VN link. This can + // affect config for config modules. Invoke IFNodeToReq iteself. This + // should not affect scaling since we dont expect many changes for + // VN to VRF link + if (peer_type == "virtual-network") { + return IFNodeToReq(node, req); + } + + // Another neighbour we are interested in + // virtual-machine-interface-routing-instance. Change to think link can + // modify VRF for connected interface. There are two cases here, + // peer is NULL : + // Means, virtual-machine-interface-routing-instance node is deleted. + // It also means, VMI link is also deleted and it would have taken + // care of the necessary changes. + // peer is Non-NULL: + // Propogate change till the connected VMI + if (peer && peer->table() == agent()->cfg()->cfg_vm_port_vrf_table()) { if (agent()->cfg_listener()->SkipNode (peer, agent()->cfg()->cfg_vm_port_vrf_table())) { return false; diff --git a/src/vnsw/agent/oper/vrf.h b/src/vnsw/agent/oper/vrf.h index 1bd4bde223c..bb8d43209d0 100644 --- a/src/vnsw/agent/oper/vrf.h +++ b/src/vnsw/agent/oper/vrf.h @@ -169,7 +169,8 @@ class VrfTable : public AgentDBTable { static VrfTable *GetInstance() {return vrf_table_;}; virtual bool IFNodeToReq(IFMapNode *node, DBRequest &req); - virtual bool IFLinkToReq(IFMapLink *link, IFMapNode *node, IFMapNode *peer, + virtual bool IFLinkToReq(IFMapLink *link, IFMapNode *node, + const string &peer_type, IFMapNode *peer, DBRequest &req); VrfEntry *FindVrfFromName(const string &name); diff --git a/src/vnsw/agent/ovs_tor_agent/ovsdb_client/ovsdb_client_idl.cc b/src/vnsw/agent/ovs_tor_agent/ovsdb_client/ovsdb_client_idl.cc index 9dbd0747be2..950565ec467 100644 --- a/src/vnsw/agent/ovs_tor_agent/ovsdb_client/ovsdb_client_idl.cc +++ b/src/vnsw/agent/ovs_tor_agent/ovsdb_client/ovsdb_client_idl.cc @@ -154,6 +154,10 @@ OvsdbClientIdl::OvsdbMsg::OvsdbMsg(struct jsonrpc_msg *m) : msg(m) { } OvsdbClientIdl::OvsdbMsg::~OvsdbMsg() { + if (this->msg != NULL) { + ovsdb_wrapper_jsonrpc_msg_destroy(this->msg); + this->msg = NULL; + } } void OvsdbClientIdl::OnEstablish() { @@ -244,9 +248,9 @@ void OvsdbClientIdl::MessageProcess(const u_int8_t *buf, std::size_t len) { bool OvsdbClientIdl::ProcessMessage(OvsdbMsg *msg) { if (!deleted_) { ovsdb_wrapper_idl_msg_process(idl_, msg->msg); + // msg->msg is freed by process method above + msg->msg = NULL; } - // msg->msg is freed by process method above - msg->msg = NULL; delete msg; return true; } diff --git a/src/vnsw/agent/ovs_tor_agent/ovsdb_client/ovsdb_client_idl.h b/src/vnsw/agent/ovs_tor_agent/ovsdb_client/ovsdb_client_idl.h index 6e80a9de2cd..0599fcaa572 100644 --- a/src/vnsw/agent/ovs_tor_agent/ovsdb_client/ovsdb_client_idl.h +++ b/src/vnsw/agent/ovs_tor_agent/ovsdb_client/ovsdb_client_idl.h @@ -108,6 +108,7 @@ class OvsdbClientIdl { KSyncObjectManager *ksync_obj_manager(); OvsPeer *route_peer(); + bool deleted() { return deleted_; } Agent *agent() {return agent_;} VMInterfaceKSyncObject *vm_interface_table(); PhysicalSwitchTable *physical_switch_table(); diff --git a/src/vnsw/agent/ovs_tor_agent/ovsdb_client/ovsdb_route_peer.cc b/src/vnsw/agent/ovs_tor_agent/ovsdb_client/ovsdb_route_peer.cc index 7ee3d1719fa..467b1718769 100644 --- a/src/vnsw/agent/ovs_tor_agent/ovsdb_client/ovsdb_route_peer.cc +++ b/src/vnsw/agent/ovs_tor_agent/ovsdb_client/ovsdb_route_peer.cc @@ -51,9 +51,9 @@ bool OvsPeer::AddOvsRoute(const VnEntry *vn, uint32_t vxlan_id = vn->vxlan_id()->vxlan_id(); SecurityGroupList sg_list; - InterfaceTable *intf_table = agent->interface_table(); - const VmInterface *vmi = dynamic_cast - (intf_table->mac_vm_binding().FindMacVmBinding(mac, vxlan_id)); + BridgeAgentRouteTable *bridge_table = + dynamic_cast(vrf->GetBridgeRouteTable()); + const VmInterface *vmi = bridge_table->FindVmFromDhcpBinding(mac); if (vmi) { vmi->CopySgIdList(&sg_list); } diff --git a/src/vnsw/agent/ovs_tor_agent/ovsdb_client/unicast_mac_remote_ovsdb.cc b/src/vnsw/agent/ovs_tor_agent/ovsdb_client/unicast_mac_remote_ovsdb.cc index fe5f3659ed2..5ab20fe20d8 100644 --- a/src/vnsw/agent/ovs_tor_agent/ovsdb_client/unicast_mac_remote_ovsdb.cc +++ b/src/vnsw/agent/ovs_tor_agent/ovsdb_client/unicast_mac_remote_ovsdb.cc @@ -280,6 +280,17 @@ OvsdbDBEntry *UnicastMacRemoteTable::AllocOvsEntry(struct ovsdb_idl_row *row) { return static_cast(Create(&key)); } +KSyncDBObject::DBFilterResp UnicastMacRemoteTable::DBEntryFilter( + const DBEntry *db_entry) { + // Since Object delete for unicast remote table happens by db + // walk on vrf table, it needs to implement filter to ignore + // db Add/Change notifications if idl is marked deleted. + if (client_idl()->deleted()) { + return DBFilterIgnore; + } + return DBFilterAccept; +} + void UnicastMacRemoteTable::ManagedDelete() { deleted_ = true; Unregister(); diff --git a/src/vnsw/agent/ovs_tor_agent/ovsdb_client/unicast_mac_remote_ovsdb.h b/src/vnsw/agent/ovs_tor_agent/ovsdb_client/unicast_mac_remote_ovsdb.h index 20dfd7857e4..a776547c733 100644 --- a/src/vnsw/agent/ovs_tor_agent/ovsdb_client/unicast_mac_remote_ovsdb.h +++ b/src/vnsw/agent/ovs_tor_agent/ovsdb_client/unicast_mac_remote_ovsdb.h @@ -25,6 +25,9 @@ class UnicastMacRemoteTable : public OvsdbDBObject { KSyncEntry *Alloc(const KSyncEntry *key, uint32_t index); KSyncEntry *DBToKSyncEntry(const DBEntry*); OvsdbDBEntry *AllocOvsEntry(struct ovsdb_idl_row *row); + + KSyncDBObject::DBFilterResp DBEntryFilter(const DBEntry *entry); + void ManagedDelete(); void Unregister(); virtual void EmptyTable(); diff --git a/src/vnsw/agent/ovs_tor_agent/tor_agent_init.cc b/src/vnsw/agent/ovs_tor_agent/tor_agent_init.cc index 37fc2d06356..fc7fb87a3b1 100644 --- a/src/vnsw/agent/ovs_tor_agent/tor_agent_init.cc +++ b/src/vnsw/agent/ovs_tor_agent/tor_agent_init.cc @@ -76,7 +76,8 @@ void TorAgentInit::CreateModules() { ovsdb_client_.reset(OvsdbClient::Allocate(agent(), static_cast(agent_param()), ovs_peer_manager())); - uve_.reset(new AgentUveBase(agent(), AgentUveBase::kBandwidthInterval)); + uve_.reset(new AgentUveBase(agent(), AgentUveBase::kBandwidthInterval, + true)); agent()->set_uve(uve_.get()); } diff --git a/src/vnsw/agent/pkt/flow_table.cc b/src/vnsw/agent/pkt/flow_table.cc index e7ea3dfbd53..c230ce2558f 100644 --- a/src/vnsw/agent/pkt/flow_table.cc +++ b/src/vnsw/agent/pkt/flow_table.cc @@ -3043,7 +3043,7 @@ AgentRoute *FlowTable::GetL2Route(const VrfEntry *vrf, const MacAddress &mac) { BridgeAgentRouteTable *table = static_cast (vrf->GetBridgeRouteTable()); - return table->FindRoute(agent(), vrf->GetName(), mac); + return table->FindRoute(mac); } AgentRoute *FlowTable::GetUcRoute(const VrfEntry *entry, diff --git a/src/vnsw/agent/pkt/pkt_flow_info.cc b/src/vnsw/agent/pkt/pkt_flow_info.cc index 94e3da9f17f..d6b185619ac 100644 --- a/src/vnsw/agent/pkt/pkt_flow_info.cc +++ b/src/vnsw/agent/pkt/pkt_flow_info.cc @@ -258,7 +258,20 @@ static bool NhDecode(const NextHop *nh, const PktInfo *pkt, PktFlowInfo *info, const InetUnicastRouteEntry *rt = static_cast(in->rt_); if (rt != NULL && rt->GetLocalNextHop()) { - out->nh_ = GetPolicyEnabledNH(rt->GetLocalNextHop())->id(); + const NextHop *local_nh = rt->GetLocalNextHop(); + out->nh_ = local_nh->id(); + if (local_nh->GetType() == NextHop::INTERFACE) { + const Interface *local_intf = + static_cast(local_nh)->GetInterface(); + //Get policy enabled nexthop only for + //vm interface, in case of vgw or service interface in + //transparent mode we should still + //use policy disabled interface + if (local_intf && + local_intf->type() == Interface::VM_INTERFACE) { + out->nh_ = GetPolicyEnabledNH(local_nh)->id(); + } + } } else { out->nh_ = in->nh_; } diff --git a/src/vnsw/agent/pkt/pkt_handler.cc b/src/vnsw/agent/pkt/pkt_handler.cc index 47b3c50c662..ffcdbaca36c 100644 --- a/src/vnsw/agent/pkt/pkt_handler.cc +++ b/src/vnsw/agent/pkt/pkt_handler.cc @@ -16,7 +16,6 @@ #include "oper/route_common.h" #include "oper/vrf.h" #include "oper/tunnel_nh.h" -#include "oper/mac_vm_binding.h" #include "pkt/control_interface.h" #include "pkt/pkt_handler.h" #include "pkt/proto.h" @@ -229,7 +228,7 @@ void PktHandler::ComputeForwardingMode(PktInfo *pkt_info) const { BridgeAgentRouteTable *l2_table = static_cast (vrf->GetBridgeRouteTable()); AgentRoute *rt = static_cast - (l2_table->FindRoute(agent_, vrf->GetName(), pkt_info->dmac)); + (l2_table->FindRoute(pkt_info->dmac)); if (rt == NULL) { return; } @@ -363,6 +362,17 @@ int PktHandler::ParseIpPacket(PktInfo *pkt_info, PktType::Type &pkt_type, if (icmp->icmp_type == ICMP_ECHO || icmp->icmp_type == ICMP_ECHOREPLY) { pkt_info->dport = ICMP_ECHOREPLY; pkt_info->sport = htons(icmp->icmp_id); + } else if (icmp->icmp_type == ICMP_DEST_UNREACH) { + //Agent has to look at inner payload + //and recalculate the parameter + ParseIpPacket(pkt_info, pkt_type, pkt + len + sizeof(icmp)); + //Swap the key parameter, which would be used as key + IpAddress src_ip = pkt_info->ip_saddr; + pkt_info->ip_saddr = pkt_info->ip_daddr; + pkt_info->ip_daddr = src_ip; + uint16_t port = pkt_info->sport; + pkt_info->sport = pkt_info->dport; + pkt_info->dport = port; } else { pkt_info->sport = 0; } @@ -520,7 +530,6 @@ int PktHandler::ParseUserPkt(PktInfo *pkt_info, Interface *intf, // IP Packets len += ParseIpPacket(pkt_info, pkt_type, (pkt + len)); - // If it is a packet from TOR that we serve, dont parse any further if (IsManagedTORPacket(intf, pkt_info, pkt_type, (pkt + len))) { return len; @@ -614,8 +623,7 @@ bool PktHandler::IsToRDevice(uint32_t vrf_id, const IpAddress &ip) { if (table == NULL) return false; - BridgeRouteEntry *rt = table->FindRoute(agent(), vrf->GetName(), - MacAddress::BroadcastMac()); + BridgeRouteEntry *rt = table->FindRoute(MacAddress::BroadcastMac()); if (rt == NULL) return false; @@ -671,7 +679,6 @@ bool PktHandler::IsManagedTORPacket(Interface *intf, PktInfo *pkt_info, return false; // Get VXLAN id and point to original L2 frame after the VXLAN header - uint32_t vxlan = ntohl(*(uint32_t *)(pkt + 4)) >> 8; pkt += 8; // get to the actual packet header @@ -680,9 +687,14 @@ bool PktHandler::IsManagedTORPacket(Interface *intf, PktInfo *pkt_info, ether_addr addr; memcpy(addr.ether_addr_octet, pkt_info->eth->ether_shost, ETH_ALEN); MacAddress address(addr); - const Interface *vm_intf = - agent_->interface_table()-> - mac_vm_binding().FindMacVmBinding(address, vxlan); + const VrfEntry *vrf = agent_->vrf_table()-> + FindVrfFromId(pkt_info->agent_hdr.vrf); + if (vrf == NULL) + return false; + BridgeAgentRouteTable *bridge_table = + dynamic_cast(vrf->GetBridgeRouteTable()); + assert(bridge_table != NULL); + const VmInterface *vm_intf = bridge_table->FindVmFromDhcpBinding(address); if (vm_intf == NULL) { return false; } @@ -696,7 +708,6 @@ bool PktHandler::IsManagedTORPacket(Interface *intf, PktInfo *pkt_info, pkt_info->agent_hdr.cmd = AgentHdr::TRAP_TOR_CONTROL_PKT; pkt_info->agent_hdr.cmd_param = pkt_info->agent_hdr.ifindex; pkt_info->agent_hdr.ifindex = vm_intf->id(); - pkt_info->agent_hdr.vrf = vm_intf->vrf_id(); // Parse payload if (pkt_info->ether_type == ETHERTYPE_ARP) { diff --git a/src/vnsw/agent/pkt/pkt_handler.h b/src/vnsw/agent/pkt/pkt_handler.h index 5310652514a..7d261fba7c0 100644 --- a/src/vnsw/agent/pkt/pkt_handler.h +++ b/src/vnsw/agent/pkt/pkt_handler.h @@ -297,22 +297,6 @@ class PktHandler { PktModule *pkt_module() const { return pkt_module_; } private: - struct MacVmBindingKey { - MacAddress mac; - int vxlan; - InterfaceConstRef interface; - - MacVmBindingKey(const MacAddress &m, int v, InterfaceConstRef intf) : - mac(m), vxlan(v), interface(intf) {} - bool operator<(const MacVmBindingKey &rhs) const { - if (mac != rhs.mac) - return mac < rhs.mac; - - return vxlan < rhs.vxlan; - } - }; - typedef std::set MacVmBindingSet; - int ParseEthernetHeader(PktInfo *pkt_info, uint8_t *pkt); int ParseMplsHdr(PktInfo *pkt_info, uint8_t *pkt); int ParseIpPacket(PktInfo *pkt_info, PktType::Type &pkt_type, diff --git a/src/vnsw/agent/pkt/test/test_ecmp.cc b/src/vnsw/agent/pkt/test/test_ecmp.cc index aa5a084e888..5b9d96febe3 100644 --- a/src/vnsw/agent/pkt/test/test_ecmp.cc +++ b/src/vnsw/agent/pkt/test/test_ecmp.cc @@ -2263,6 +2263,67 @@ TEST_F(EcmpTest, TrapFlag) { client->WaitForIdle(); } +//Send a packet from vgw to ecmp destination +TEST_F(EcmpTest, VgwFlag) { + Agent *agent = Agent::GetInstance(); + InetInterface::CreateReq(agent->interface_table(), "vgw1", + InetInterface::SIMPLE_GATEWAY, "vrf2", + Ip4Address(0), 0, Ip4Address(0), Agent::NullString(), + ""); + client->WaitForIdle(); + + InetInterfaceKey *intf_key = new InetInterfaceKey("vgw1"); + std::auto_ptr nh_key(new InterfaceNHKey(intf_key, false, + InterfaceNHFlags::INET4)); + + Ip4Address remote_server_ip1 = Ip4Address::from_string("10.10.10.100"); + ComponentNHKeyPtr nh_data1(new ComponentNHKey(16, nh_key)); + ComponentNHKeyPtr nh_data2(new ComponentNHKey(20, agent->fabric_vrf_name(), + agent->router_id(), + remote_server_ip1, + false, + TunnelType::DefaultType())); + Ip4Address ip = Ip4Address::from_string("0.0.0.0"); + ComponentNHKeyList comp_nh_list; + comp_nh_list.push_back(nh_data1); + comp_nh_list.push_back(nh_data2); + EcmpTunnelRouteAdd(bgp_peer, "vrf2", ip, 0, + comp_nh_list, false, "vn2", + SecurityGroupList(), PathPreference()); + client->WaitForIdle(); + + InetInterfaceKey tmp_key("vgw1"); + Interface *intf = + static_cast(agent->interface_table()-> + FindActiveEntry(&tmp_key)); + + //Send packet on vgw interface + TxIpPacket(intf->id(), "100.1.1.1", "2.2.2.2", 1); + client->WaitForIdle(); + + FlowEntry *entry; + FlowEntry *rev_entry; + entry = FlowGet(VrfGet("vrf2")->vrf_id(), + "2.2.2.2", "100.1.1.1", 1, 0, 0, intf->flow_key_nh()->id()); + EXPECT_TRUE(entry != NULL); + EXPECT_TRUE(entry->data().component_nh_idx == + CompositeNH::kInvalidComponentNHIdx); + + rev_entry = FlowGet(VrfGet("vrf2")->vrf_id(), + "100.1.1.1", "2.2.2.2", 1, 0, 0, intf->flow_key_nh()->id()); + EXPECT_TRUE(rev_entry != NULL); + EXPECT_TRUE(rev_entry->data().component_nh_idx == + CompositeNH::kInvalidComponentNHIdx); + + client->WaitForIdle(); + agent->fabric_inet4_unicast_table()->DeleteReq(bgp_peer, "vrf2", + ip, 0, NULL); + InetInterface::DeleteReq(agent->interface_table(), "vgw1"); + client->WaitForIdle(); + WAIT_FOR(1000, 1000, (Agent::GetInstance()->pkt()-> + flow_table()->Size() == 0)); +} + int main(int argc, char *argv[]) { GETUSERARGS(); client = TestInit(init_file, ksync_init, true, true, true, 100*1000); diff --git a/src/vnsw/agent/services/arp_entry.cc b/src/vnsw/agent/services/arp_entry.cc index 274d85c8ef7..3736f9e8232 100644 --- a/src/vnsw/agent/services/arp_entry.cc +++ b/src/vnsw/agent/services/arp_entry.cc @@ -175,7 +175,7 @@ void ArpEntry::SendArpRequest() { ip = vmi->GetGateway(); vrf_id = nh_vrf_->vrf_id(); if (vmi->parent()) { - intf_id = vmi->parent()->id(); + intf_id = vmi->id(); smac = vmi->parent()->mac(); } } else { diff --git a/src/vnsw/agent/services/arp_proto.cc b/src/vnsw/agent/services/arp_proto.cc index e3d5fe7f6cd..4ef4e553217 100644 --- a/src/vnsw/agent/services/arp_proto.cc +++ b/src/vnsw/agent/services/arp_proto.cc @@ -205,12 +205,10 @@ void ArpDBState::UpdateArpRoutes(const InetUnicastRouteEntry *rt) { ArpProto::ArpIterator start_iter = vrf_state_->arp_proto->FindUpperBoundArpEntry(start_key); - if (start_iter->first.vrf != rt->vrf()) { - return; - } - - while (IsIp4SubnetMember(Ip4Address(start_iter->first.ip), + while (start_iter != vrf_state_->arp_proto->arp_cache().end() && + start_iter->first.vrf == rt->vrf() && + IsIp4SubnetMember(Ip4Address(start_iter->first.ip), rt->addr().to_v4(), plen)) { start_iter->second->Resync(policy_, vn_, sg_list_); start_iter++; @@ -226,11 +224,9 @@ void ArpDBState::Delete(const InetUnicastRouteEntry *rt) { ArpProto::ArpIterator start_iter = vrf_state_->arp_proto->FindUpperBoundArpEntry(start_key); - if (start_iter->first.vrf != rt->vrf()) { - return; - } - - while (IsIp4SubnetMember(Ip4Address(start_iter->first.ip), + while (start_iter != vrf_state_->arp_proto->arp_cache().end() && + start_iter->first.vrf == rt->vrf() && + IsIp4SubnetMember(Ip4Address(start_iter->first.ip), rt->addr().to_v4(), plen)) { ArpProto::ArpIterator tmp = start_iter++; if (tmp->second->DeleteArpRoute()) { diff --git a/src/vnsw/agent/services/test/arp_test.cc b/src/vnsw/agent/services/test/arp_test.cc index 98684a351af..f4899c2e88b 100644 --- a/src/vnsw/agent/services/test/arp_test.cc +++ b/src/vnsw/agent/services/test/arp_test.cc @@ -660,6 +660,14 @@ TEST_F(ArpTest, DISABLED_SubnetResolveWithoutPolicy) { EXPECT_TRUE(VmPortFind(8)); client->Reset(); + AddPhysicalDevice(agent->host_name().c_str(), 1); + AddPhysicalInterface("pi1", 1, "pid1"); + AddLogicalInterface("lp1", 1, "lp1", 1); + AddLink("physical-router", "prouter1", "physical-interface", "pi1"); + AddLink("logical-interface", "lp1", "physical-interface", "pi1"); + AddLink("virtual-machine-interface", "vnet8", "logical-interface", "lp1"); + client->WaitForIdle(); + //Add a link to interface subnet and ensure resolve route is added AddSubnetType("subnet", 1, "8.1.1.0", 24); AddLink("virtual-machine-interface", input1[0].name, @@ -830,6 +838,14 @@ TEST_F(ArpTest, DISABLED_SubnetResolveWithSg) { EXPECT_TRUE(VmPortFind(8)); client->Reset(); + AddPhysicalDevice(agent->host_name().c_str(), 1); + AddPhysicalInterface("pi1", 1, "pid1"); + AddLogicalInterface("lp1", 1, "lp1", 1); + AddLink("physical-router", "prouter1", "physical-interface", "pi1"); + AddLink("logical-interface", "lp1", "physical-interface", "pi1"); + AddLink("virtual-machine-interface", "vnet8", "logical-interface", "lp1"); + client->WaitForIdle(); + AddSg("sg1", 1); AddAcl("acl1", 1); AddLink("security-group", "sg1", "access-control-list", "acl1"); @@ -863,6 +879,7 @@ TEST_F(ArpTest, DISABLED_SubnetResolveWithSg) { DelLink("security-group", "sg1", "access-control-list", "acl1"); DelAcl("acl1"); DelNode("security-group", "sg1"); + DelLink("virtual-machine-interface", "vnet8", "security-group", "sg1"); client->WaitForIdle(); DeleteVmportEnv(input1, 1, true, 1); client->WaitForIdle(); @@ -875,6 +892,121 @@ TEST_F(ArpTest, DISABLED_SubnetResolveWithSg) { client->Reset(); } +//Check leaked routes dont get updated +//when original route changes +TEST_F(ArpTest, DISABLED_SubnetResolveWithSg1) { + struct PortInfo input1[] = { + {"vnet8", 8, "8.1.1.1", "00:00:00:01:01:01", 1, 1}, + {"vnet9", 9, "9.1.1.1", "00:00:00:01:01:02", 2, 2} + }; + + client->Reset(); + //Create VM interface with policy + CreateVmportWithEcmp(input1, 2, 1); + client->WaitForIdle(); + EXPECT_TRUE(VmPortActive(input1, 0)); + EXPECT_TRUE(VmPortFind(8)); + client->Reset(); + + AddPhysicalDevice(agent->host_name().c_str(), 1); + AddPhysicalInterface("pi1", 1, "pid1"); + AddLogicalInterface("lp1", 1, "lp1", 1); + AddLink("physical-router", "prouter1", "physical-interface", "pi1"); + AddLink("logical-interface", "lp1", "physical-interface", "pi1"); + AddLink("virtual-machine-interface", "vnet8", "logical-interface", "lp1"); + client->WaitForIdle(); + + VmInterface *vintf8 = VmInterfaceGet(8); + VmInterface *vintf9 = VmInterfaceGet(9); + + AddSg("sg1", 1); + AddAcl("acl1", 1); + AddLink("security-group", "sg1", "access-control-list", "acl1"); + client->WaitForIdle(); + //Add a link to interface subnet and ensure resolve route is added + AddSubnetType("subnet", 1, "8.1.1.0", 24); + AddLink("virtual-machine-interface", input1[0].name, + "subnet", "subnet"); + client->WaitForIdle(); + EXPECT_TRUE(VmPortActive(input1, 0)); + EXPECT_TRUE(RouteFind("vrf1", "8.1.1.0", 24)); + + VmInterfaceKey key(AgentKey::ADD_DEL_CHANGE, MakeUuid(8), "vnet8"); + Ip4Address subnet = Ip4Address::from_string("8.1.1.0"); + InetUnicastAgentRouteTable::AddResolveRoute(vintf9->peer(), "vrf2", + subnet, 24, key, 0, false, + "vn1", SecurityGroupList()); + client->WaitForIdle(); + + Ip4Address sip = Ip4Address::from_string("9.1.1.1"); + Ip4Address dip = Ip4Address::from_string("8.1.1.2"); + Ip4Address dip1 = Ip4Address::from_string("8.1.1.3"); + SendArpReq(vintf9->id(), vintf9->vrf()->vrf_id(), sip.to_ulong(), dip.to_ulong()); + SendArpReq(vintf9->id(), vintf9->vrf()->vrf_id(), sip.to_ulong(), dip1.to_ulong()); + client->WaitForIdle(); + WAIT_FOR(500, 1000, + Agent::GetInstance()->GetArpProto()->GetArpCacheSize() == 5); + + WAIT_FOR(500, 1000, RouteFind("vrf2", "8.1.1.2", 32) == true); + WAIT_FOR(500, 1000, RouteFind("vrf2", "8.1.1.3", 32) == true); + AddLink("virtual-machine-interface", "vnet8", "security-group", "sg1"); + client->WaitForIdle(); + + //Verify that route update on vrf1 doesnt reevaluate vrf2 arp routes + AgentRoute *rt = RouteGet("vrf2", dip, 32); + EXPECT_TRUE(rt->GetActiveNextHop()->GetType() == NextHop::ARP); + EXPECT_TRUE(rt->GetActivePath()->dest_vn_name() == "vn1"); + EXPECT_TRUE(rt->GetActivePath()->sg_list().size() == 0); + rt = RouteGet("vrf2", dip1, 32); + EXPECT_TRUE(rt->GetActiveNextHop()->GetType() == NextHop::ARP); + EXPECT_TRUE(rt->GetActivePath()->dest_vn_name() == "vn1"); + EXPECT_TRUE(rt->GetActivePath()->sg_list().size() == 0); + + rt = RouteGet("vrf1", dip, 32); + EXPECT_TRUE(rt->GetActivePath()->sg_list().size() == 1); + rt = RouteGet("vrf1", dip1, 32); + EXPECT_TRUE(rt->GetActivePath()->sg_list().size() == 1); + + //Resync the same on leaked vrf + InetUnicastAgentRouteTable::AddResolveRoute(vintf9->peer(), "vrf2", + subnet, 24, key, 0, false, + "vn1", SecurityGroupList(1)); + client->WaitForIdle(); + + rt = RouteGet("vrf2", dip, 32); + EXPECT_TRUE(rt->GetActiveNextHop()->GetType() == NextHop::ARP); + EXPECT_TRUE(rt->GetActivePath()->dest_vn_name() == "vn1"); + EXPECT_TRUE(rt->GetActivePath()->sg_list().size() == 1); + + rt = RouteGet("vrf2", dip1, 32); + EXPECT_TRUE(rt->GetActiveNextHop()->GetType() == NextHop::ARP); + EXPECT_TRUE(rt->GetActivePath()->dest_vn_name() == "vn1"); + EXPECT_TRUE(rt->GetActivePath()->sg_list().size() == 1); + + rt = RouteGet("vrf1", dip, 32); + EXPECT_TRUE(rt->GetActivePath()->sg_list().size() == 1); + rt = RouteGet("vrf1", dip1, 32); + EXPECT_TRUE(rt->GetActivePath()->sg_list().size() == 1); + + DelLink("virtual-machine-interface", input1[0].name, + "subnet", "subnet"); + DelLink("security-group", "sg1", "access-control-list", "acl1"); + DelAcl("acl1"); + DelNode("security-group", "sg1"); + InetUnicastAgentRouteTable::DeleteReq(vintf9->peer(), "vrf2", + subnet, 24, NULL); + client->WaitForIdle(); + DeleteVmportEnv(input1, 2, true, 1); + client->WaitForIdle(); + WAIT_FOR(500, 1000, RouteFind("vrf1", "8.1.1.2", 32) == false); + EXPECT_EQ(1U, Agent::GetInstance()->GetArpProto()->GetArpCacheSize()); + + EXPECT_FALSE(VmPortFind(8)); + WAIT_FOR(100, 1000, (Agent::GetInstance()->interface_table()->Find(&key, true) + == NULL)); + client->Reset(); +} + TEST_F(ArpTest, IntfArpReqTest_1) { struct PortInfo input[] = { {"vnet1", 1, "1.1.1.1", "00:00:00:01:01:01", 1, 1}, diff --git a/src/vnsw/agent/test-xml/test_xml_oper.cc b/src/vnsw/agent/test-xml/test_xml_oper.cc index 27e22a28d08..4a625055902 100644 --- a/src/vnsw/agent/test-xml/test_xml_oper.cc +++ b/src/vnsw/agent/test-xml/test_xml_oper.cc @@ -1270,9 +1270,11 @@ bool AgentUtXmlL2RouteValidate::ReadXml() { bool AgentUtXmlL2RouteValidate::Validate() { Agent *agent = Agent::GetInstance(); + BridgeAgentRouteTable *bridge_table = + static_cast + (agent->vrf_table()->GetBridgeRouteTable(vrf_)); BridgeRouteEntry *rt = - BridgeAgentRouteTable::FindRoute(agent, vrf_, - MacAddress::FromString(mac_)); + bridge_table->FindRoute(MacAddress::FromString(mac_)); if (present() == false) return (rt == NULL); diff --git a/src/vnsw/agent/test/test_cfg.cc b/src/vnsw/agent/test/test_cfg.cc index 025e947c9f4..19bfb731614 100644 --- a/src/vnsw/agent/test/test_cfg.cc +++ b/src/vnsw/agent/test/test_cfg.cc @@ -1858,7 +1858,6 @@ TEST_F(CfgTest, StaleTimeoutDeferList) { TestFoo = static_cast(iter.operator->()); EXPECT_EQ("testfoo", TestFoo->name()); } -#if 1 //Repeat the same with two hanging links sprintf(buff, @@ -1978,11 +1977,219 @@ TEST_F(CfgTest, StaleTimeoutDeferList) { TestFoo = static_cast(iter.operator->()); EXPECT_EQ("testfoo", TestFoo->name()); } -#endif delete cl; } +TEST_F(CfgTest, LinkMetadata) { + char buff[1500]; + sprintf(buff, + "\n" + " \n" + " testfoo\n" + " \n" + " \n" + " testbar\n" + " \n" + " \n" + " \n" + " testfoo\n" + " \n" + " \n" + " testbar\n" + " \n" + " " + " \n" + ""); + + IFMapTable *ftable = IFMapTable::FindTable(&db_, "foo"); + ASSERT_TRUE(ftable!=NULL); + + IFMapTable *btable = IFMapTable::FindTable(&db_, "bar"); + ASSERT_TRUE(btable!=NULL); + + IFMapAgentLinkTable *ltable = static_cast( + db_.FindTable(IFMAP_AGENT_LINK_DB_NAME)); + ASSERT_TRUE(ltable!=NULL); + + pugi::xml_parse_result result = xdoc_.load(buff); + EXPECT_TRUE(result); + parser_->ConfigParse(xdoc_, 0); + WaitForIdle(); + + //Ensure that both nodes are added fine along with attribute + IFMapNode *TestFoo = ftable->FindNode("testfoo"); + ASSERT_TRUE(TestFoo !=NULL); + EXPECT_EQ("testfoo", TestFoo->name()); + + IFMapNode *TestBar = btable->FindNode("testbar"); + ASSERT_TRUE(TestBar !=NULL); + EXPECT_EQ("testbar", TestBar->name()); + + IFMapLink *link = static_cast(graph_.GetEdge(TestFoo, TestBar)); + assert(link); + EXPECT_EQ(link->metadata(), "foo-bar"); +} + +TEST_F(CfgTest, DefLinkMetadata) { + char buff[1500]; + sprintf(buff, + "\n" + " \n" + " \n" + " testfoo\n" + " \n" + " \n" + " testbar\n" + " \n" + " " + " \n" + ""); + + IFMapTable *ftable = IFMapTable::FindTable(&db_, "foo"); + ASSERT_TRUE(ftable!=NULL); + + IFMapTable *btable = IFMapTable::FindTable(&db_, "bar"); + ASSERT_TRUE(btable!=NULL); + + IFMapAgentLinkTable *ltable = static_cast( + db_.FindTable(IFMAP_AGENT_LINK_DB_NAME)); + ASSERT_TRUE(ltable!=NULL); + + pugi::xml_parse_result result = xdoc_.load(buff); + EXPECT_TRUE(result); + parser_->ConfigParse(xdoc_, 0); + WaitForIdle(); + + sprintf(buff, + "\n" + " \n" + " testfoo\n" + " \n" + " \n" + " testbar\n" + " \n" + ""); + + result = xdoc_.load(buff); + EXPECT_TRUE(result); + parser_->ConfigParse(xdoc_, 0); + WaitForIdle(); + + //Ensure that both nodes are added fine along with attribute + IFMapNode *TestFoo = ftable->FindNode("testfoo"); + ASSERT_TRUE(TestFoo !=NULL); + EXPECT_EQ("testfoo", TestFoo->name()); + + IFMapNode *TestBar = btable->FindNode("testbar"); + ASSERT_TRUE(TestBar !=NULL); + EXPECT_EQ("testbar", TestBar->name()); + + IFMapLink *link = static_cast(graph_.GetEdge(TestFoo, TestBar)); + assert(link); + EXPECT_EQ(link->metadata(), "foo-bar"); +} + +TEST_F(CfgTest, NodeDelLinkMetadata) { + char buff[1500]; + sprintf(buff, + "\n" + " \n" + " \n" + " testfoo\n" + " \n" + " \n" + " testbar\n" + " \n" + " " + " \n" + ""); + + IFMapTable *ftable = IFMapTable::FindTable(&db_, "foo"); + ASSERT_TRUE(ftable!=NULL); + + IFMapTable *btable = IFMapTable::FindTable(&db_, "bar"); + ASSERT_TRUE(btable!=NULL); + + IFMapAgentLinkTable *ltable = static_cast( + db_.FindTable(IFMAP_AGENT_LINK_DB_NAME)); + ASSERT_TRUE(ltable!=NULL); + + pugi::xml_parse_result result = xdoc_.load(buff); + EXPECT_TRUE(result); + parser_->ConfigParse(xdoc_, 0); + WaitForIdle(); + + sprintf(buff, + "\n" + " \n" + " testfoo\n" + " \n" + " \n" + " testbar\n" + " \n" + ""); + + result = xdoc_.load(buff); + EXPECT_TRUE(result); + parser_->ConfigParse(xdoc_, 0); + WaitForIdle(); + + //Ensure that both nodes are added fine along with attribute + IFMapNode *TestFoo = ftable->FindNode("testfoo"); + ASSERT_TRUE(TestFoo !=NULL); + EXPECT_EQ("testfoo", TestFoo->name()); + + IFMapNode *TestBar = btable->FindNode("testbar"); + ASSERT_TRUE(TestBar !=NULL); + EXPECT_EQ("testbar", TestBar->name()); + + IFMapLink *link = static_cast(graph_.GetEdge(TestFoo, TestBar)); + assert(link); + EXPECT_EQ(link->metadata(), "foo-bar"); + + sprintf(buff, + "\n" + " \n" + " testfoo\n" + " \n" + "\n"); + + result = xdoc_.load(buff); + EXPECT_TRUE(result); + parser_->ConfigParse(xdoc_, 0); + WaitForIdle(); + + //Ensure that there is no link from Bar to foo as well + int count = 0; + for (DBGraphVertex::adjacency_iterator iter = TestBar->begin(&graph_); + iter != TestBar->end(&graph_); ++iter) { + count++; + } + EXPECT_EQ(count, 0); + + + sprintf(buff, + "\n" + " \n" + " testfoo\n" + " \n" + "\n"); + + result = xdoc_.load(buff); + EXPECT_TRUE(result); + parser_->ConfigParse(xdoc_, 0); + WaitForIdle(); + + TestFoo = ftable->FindNode("testfoo"); + ASSERT_TRUE(TestFoo !=NULL); + EXPECT_EQ("testfoo", TestFoo->name()); + + link = static_cast(graph_.GetEdge(TestFoo, TestBar)); + assert(link); + EXPECT_EQ(link->metadata(), "foo-bar"); +} + int main(int argc, char **argv) { LoggingInit(); ::testing::InitGoogleTest(&argc, argv); diff --git a/src/vnsw/agent/test/test_route.cc b/src/vnsw/agent/test/test_route.cc index cc198688ac5..14c9a77cfb4 100644 --- a/src/vnsw/agent/test/test_route.cc +++ b/src/vnsw/agent/test/test_route.cc @@ -123,7 +123,6 @@ class RouteTest : public ::testing::Test { TestRouteTable table3(3); WAIT_FOR(100, 1000, (table3.Size() == 0)); EXPECT_EQ(table3.Size(), 0U); - VrfDelReq(vrf_name_.c_str()); client->WaitForIdle(); WAIT_FOR(100, 1000, (VrfFind(vrf_name_.c_str()) != true)); @@ -1926,6 +1925,179 @@ TEST_F(RouteTest, NonEcmpToEcmpConversion) { EXPECT_TRUE(VrfFind("vrf8", true) == false); } +TEST_F(RouteTest, Dhcp_enabled_ipam) { + client->Reset(); + struct PortInfo input[] = { + {"vnet1", 1, "1.1.1.1", "00:00:00:01:01:01", 1, 1}, + }; + + IpamInfo ipam_info[] = { + {"1.1.1.0", 24, "1.1.1.200", true}, + }; + client->Reset(); + CreateVmportEnv(input, 1, 0); + client->WaitForIdle(); + AddIPAM("vn1", ipam_info, 1); + client->WaitForIdle(); + + //Find Bridge route + BridgeRouteEntry *rt = + L2RouteGet("vrf1", + MacAddress::FromString("00:00:00:01:01:01"), + Ip4Address::from_string("1.1.1.1")); + const AgentPath *path = rt->FindMacVmBindingPath(); + const MacVmBindingPath *dhcp_path = dynamic_cast(path); + EXPECT_TRUE(dhcp_path != NULL); + EXPECT_TRUE(dhcp_path->vm_interface()->GetUuid() == MakeUuid(1)); + EXPECT_TRUE(dhcp_path->nexthop()->GetType() == NextHop::DISCARD); + EXPECT_TRUE(dhcp_path->flood_dhcp() == false); + + client->Reset(); + DelIPAM("vn1"); + client->WaitForIdle(); + DeleteVmportEnv(input, 1, 1, 0); + client->WaitForIdle(); +} + +TEST_F(RouteTest, Dhcp_disabled_ipam) { + client->Reset(); + struct PortInfo input[] = { + {"vnet1", 1, "1.1.1.1", "00:00:00:01:01:01", 1, 1}, + }; + + IpamInfo ipam_info[] = { + {"1.1.1.0", 24, "1.1.1.200", false}, + }; + client->Reset(); + CreateVmportEnv(input, 1, 0); + client->WaitForIdle(); + AddIPAM("vn1", ipam_info, 1); + client->WaitForIdle(); + + //Find Bridge route + BridgeRouteEntry *rt = + L2RouteGet("vrf1", + MacAddress::FromString("00:00:00:01:01:01"), + Ip4Address::from_string("1.1.1.1")); + const MacVmBindingPath *dhcp_path = + dynamic_cast(rt->FindMacVmBindingPath()); + EXPECT_TRUE(dhcp_path != NULL); + EXPECT_TRUE(dhcp_path->vm_interface()->GetUuid() == MakeUuid(1)); + EXPECT_TRUE(dhcp_path->nexthop()->GetType() == NextHop::DISCARD); + EXPECT_TRUE(dhcp_path->flood_dhcp() == true); + + client->Reset(); + DelIPAM("vn1"); + client->WaitForIdle(); + DeleteVmportEnv(input, 1, 1, 0); + client->WaitForIdle(); +} + +TEST_F(RouteTest, Dhcp_mode_toggled_ipam) { + client->Reset(); + struct PortInfo input[] = { + {"vnet1", 1, "1.1.1.1", "00:00:00:01:01:01", 1, 1}, + {"vnet2", 2, "1.1.1.2", "00:00:00:01:01:02", 1, 1}, + }; + + IpamInfo ipam_info[] = { + {"1.1.1.0", 24, "1.1.1.200", true}, + }; + client->Reset(); + CreateVmportEnv(input, 2, 0); + client->WaitForIdle(); + AddIPAM("vn1", ipam_info, 1); + client->WaitForIdle(); + + //Find Bridge route + BridgeRouteEntry *rt = + L2RouteGet("vrf1", + MacAddress::FromString("00:00:00:01:01:01"), + Ip4Address::from_string("1.1.1.1")); + const AgentPath *path = rt->FindMacVmBindingPath(); + const MacVmBindingPath *dhcp_path = dynamic_cast(path); + EXPECT_TRUE(dhcp_path != NULL); + EXPECT_TRUE(dhcp_path->vm_interface()->GetUuid() == MakeUuid(1)); + EXPECT_TRUE(dhcp_path->nexthop()->GetType() == NextHop::DISCARD); + EXPECT_TRUE(dhcp_path->flood_dhcp() == false); + rt = L2RouteGet("vrf1", + MacAddress::FromString("00:00:00:01:01:02"), + Ip4Address::from_string("1.1.1.2")); + dhcp_path = dynamic_cast(rt->FindMacVmBindingPath()); + EXPECT_TRUE(dhcp_path->vm_interface()->GetUuid() == MakeUuid(2)); + EXPECT_TRUE(dhcp_path->nexthop()->GetType() == NextHop::DISCARD); + EXPECT_TRUE(dhcp_path->flood_dhcp() == false); + + //Toggle to disable + IpamInfo ipam_info_disabled[] = { + {"1.1.1.0", 24, "1.1.1.200", false}, + }; + AddIPAM("vn1", ipam_info_disabled, 1); + client->WaitForIdle(); + rt = L2RouteGet("vrf1", + MacAddress::FromString("00:00:00:01:01:01"), + Ip4Address::from_string("1.1.1.1")); + dhcp_path = dynamic_cast(rt->FindMacVmBindingPath()); + EXPECT_TRUE(dhcp_path->vm_interface()->GetUuid() == MakeUuid(1)); + EXPECT_TRUE(dhcp_path->nexthop()->GetType() == NextHop::DISCARD); + EXPECT_TRUE(dhcp_path->flood_dhcp() == true); + rt = L2RouteGet("vrf1", + MacAddress::FromString("00:00:00:01:01:02"), + Ip4Address::from_string("1.1.1.2")); + dhcp_path = dynamic_cast(rt->FindMacVmBindingPath()); + EXPECT_TRUE(dhcp_path->vm_interface()->GetUuid() == MakeUuid(2)); + EXPECT_TRUE(dhcp_path->nexthop()->GetType() == NextHop::DISCARD); + EXPECT_TRUE(dhcp_path->flood_dhcp() == true); + + //Toggle to enable + AddIPAM("vn1", ipam_info, 1); + client->WaitForIdle(); + rt = L2RouteGet("vrf1", + MacAddress::FromString("00:00:00:01:01:01"), + Ip4Address::from_string("1.1.1.1")); + dhcp_path = dynamic_cast(rt->FindMacVmBindingPath()); + EXPECT_TRUE(dhcp_path != NULL); + EXPECT_TRUE(dhcp_path->vm_interface()->GetUuid() == MakeUuid(1)); + EXPECT_TRUE(dhcp_path->nexthop()->GetType() == NextHop::DISCARD); + EXPECT_TRUE(dhcp_path->flood_dhcp() == false); + rt = L2RouteGet("vrf1", + MacAddress::FromString("00:00:00:01:01:02"), + Ip4Address::from_string("1.1.1.2")); + dhcp_path = dynamic_cast(rt->FindMacVmBindingPath()); + EXPECT_TRUE(dhcp_path->vm_interface()->GetUuid() == MakeUuid(2)); + EXPECT_TRUE(dhcp_path->nexthop()->GetType() == NextHop::DISCARD); + EXPECT_TRUE(dhcp_path->flood_dhcp() == false); + + client->Reset(); + DelIPAM("vn1"); + client->WaitForIdle(); + DeleteVmportEnv(input, 2, 1, 0); + client->WaitForIdle(); +} + +//Double delete ARP route and verify that ARP NH +//get deleted, since we always enqueu RESYNC for arp NH change +//from ARP route deletiong path +TEST_F(RouteTest, ArpRouteDelete) { + ArpNHKey key(Agent::GetInstance()->fabric_vrf_name(), server1_ip_, false); + + AddArp(server1_ip_.to_string().c_str(), "0a:0b:0c:0d:0e:0f", eth_name_.c_str()); + client->WaitForIdle(); + EXPECT_TRUE(FindNH(&key)); + EXPECT_TRUE(GetNH(&key)->IsValid() == true); + + //Delete Remote VM route + DelArp(server1_ip_.to_string(), "0a:0b:0c:0d:0e:0f", eth_name_.c_str()); + client->WaitForIdle(); + EXPECT_FALSE(RouteFind(vrf_name_, server1_ip_, 32)); + + DelArp(server1_ip_.to_string(), "0a:0b:0c:0d:0e:0f", eth_name_.c_str()); + client->WaitForIdle(); + EXPECT_FALSE(RouteFind(vrf_name_, server1_ip_, 32)); + + EXPECT_FALSE(FindNH(&key)); +} + int main(int argc, char *argv[]) { ::testing::InitGoogleTest(&argc, argv); GETUSERARGS(); diff --git a/src/vnsw/agent/test/test_util.cc b/src/vnsw/agent/test/test_util.cc index e71704208db..735c0a458fd 100644 --- a/src/vnsw/agent/test/test_util.cc +++ b/src/vnsw/agent/test/test_util.cc @@ -84,6 +84,15 @@ void DelLinkString(char *buff, int &len, const char *node_name1, len = strlen(buff); } +void AddNodeStringWithoutUuid(char *buff, int &len, const char + *node_name, const char *name) { + sprintf(buff + len, + " \n" + " %s\n" + " \n", node_name, name); + len = strlen(buff); +} + void AddNodeString(char *buff, int &len, const char *node_name, const char *name, int id, const char *attr, bool admin_state) { @@ -308,7 +317,10 @@ void AddNode(const char *node_name, const char *name, int id, int len = 0; AddXmlHdr(buff, len); - AddNodeString(buff, len, node_name, name, id, attr, admin_state); + if (id) + AddNodeString(buff, len, node_name, name, id, attr, admin_state); + else + AddNodeStringWithoutUuid(buff, len, node_name, name); AddXmlTail(buff, len); pugi::xml_document xdoc_; pugi::xml_parse_result result = xdoc_.load(buff); @@ -1077,8 +1089,15 @@ bool RouteFindV6(const string &vrf_name, const string &addr, int plen) { bool L2RouteFind(const string &vrf_name, const MacAddress &mac, const IpAddress &ip_addr) { - BridgeRouteEntry *route = - BridgeAgentRouteTable::FindRoute(Agent::GetInstance(), vrf_name, mac); + if (Agent::GetInstance()->vrf_table() == NULL) { + return false; + } + BridgeAgentRouteTable *bridge_table = + static_cast + (Agent::GetInstance()->vrf_table()->GetBridgeRouteTable(vrf_name)); + if (bridge_table == NULL) + return false; + BridgeRouteEntry *route = bridge_table->FindRoute(mac); return (route != NULL); } diff --git a/src/vnsw/agent/test/test_vn.cc b/src/vnsw/agent/test/test_vn.cc index b97feb8abfc..4d1f9ea2874 100644 --- a/src/vnsw/agent/test/test_vn.cc +++ b/src/vnsw/agent/test/test_vn.cc @@ -837,6 +837,133 @@ TEST_F(CfgTest, RpfEnableDisable) { client->WaitForIdle(); } + +TEST_F(CfgTest, CfgDBStateUuid) { + client->WaitForIdle(); + // Add VN with UUID + AddVn("vn1", 1); + client->WaitForIdle(); + + VnEntry *vn = VnGet(1); + ASSERT_TRUE(vn != NULL); + + //Get the config table + IFMapTable *table = + IFMapTable::FindTable(Agent::GetInstance()->db(),"virtual-network"); + ASSERT_TRUE(table != NULL); + + //Get the config node + IFMapNode *node = table->FindNode("vn1"); + ASSERT_TRUE(node != NULL); + + boost::uuids::uuid id; + EXPECT_TRUE(Agent::GetInstance()->cfg()->cfg_listener()-> + GetCfgDBStateUuid(node, id)); + EXPECT_EQ(id, MakeUuid(1)); + client->WaitForIdle(); + + //Ensure that Oper exists + ASSERT_TRUE(VnFind(1)); + + DelVn("vn1"); + client->WaitForIdle(); + + vn = VnGet(1); + ASSERT_TRUE(vn == NULL); + + //Ensure that Oper also does not exists + ASSERT_FALSE(VnFind(1)); +} + +TEST_F(CfgTest, CfgUuidNullDelete) { + client->WaitForIdle(); + // Add VN with UUID + AddVn("vn1", 1); + client->WaitForIdle(); + + VnEntry *vn = VnGet(1); + ASSERT_TRUE(vn != NULL); + + //Get the config table + IFMapTable *table = + IFMapTable::FindTable(Agent::GetInstance()->db(),"virtual-network"); + ASSERT_TRUE(table != NULL); + + //Get the config node + IFMapNode *node = table->FindNode("vn1"); + ASSERT_TRUE(node != NULL); + + boost::uuids::uuid id; + EXPECT_TRUE(Agent::GetInstance()->cfg()->cfg_listener()-> + GetCfgDBStateUuid(node, id)); + EXPECT_EQ(id, MakeUuid(1)); + + //Ensure that Oper exists + ASSERT_TRUE(VnFind(1)); + + //Send Uuid zero and verify that node is deleted + AddVn("vn1", 0); + client->WaitForIdle(); + + node = table->FindNode("vn1"); + ASSERT_TRUE(node == NULL); + + //Ensure that Oper is deleted + ASSERT_FALSE(VnFind(1)); +} + + +TEST_F(CfgTest, CfgUuidChange) { + client->WaitForIdle(); + // Add VN with UUID + AddVn("vn1", 1); + client->WaitForIdle(); + + VnEntry *vn = VnGet(1); + ASSERT_TRUE(vn != NULL); + + //Get the config table + IFMapTable *table = + IFMapTable::FindTable(Agent::GetInstance()->db(),"virtual-network"); + ASSERT_TRUE(table != NULL); + + //Get the config node + IFMapNode *node = table->FindNode("vn1"); + ASSERT_TRUE(node != NULL); + + boost::uuids::uuid id; + EXPECT_TRUE(Agent::GetInstance()->cfg()->cfg_listener()-> + GetCfgDBStateUuid(node, id)); + EXPECT_EQ(id, MakeUuid(1)); + + //Ensure that Oper exists + ASSERT_TRUE(VnFind(1)); + + //Send different Uuid + AddVn("vn1", 2); + client->WaitForIdle(); + + node = table->FindNode("vn1"); + ASSERT_TRUE(node != NULL); + + //Ensure that Oper exists + ASSERT_TRUE(VnFind(2)); + + //Ensure that Oper exists + ASSERT_TRUE(VnFind(1)); + + DelVn("vn1"); + client->WaitForIdle(); + + node = table->FindNode("vn1"); + ASSERT_TRUE(node != NULL); + + //Ensure that Oper exists for only 1 + ASSERT_TRUE(VnFind(1)); + ASSERT_FALSE(VnFind(2)); + +} + int main(int argc, char **argv) { GETUSERARGS(); diff --git a/src/vnsw/agent/uve/agent_uve.cc b/src/vnsw/agent/uve/agent_uve.cc index e683d47de39..36162f0a630 100644 --- a/src/vnsw/agent/uve/agent_uve.cc +++ b/src/vnsw/agent/uve/agent_uve.cc @@ -19,7 +19,7 @@ #include AgentUve::AgentUve(Agent *agent, uint64_t intvl) - : AgentUveBase(agent, intvl), + : AgentUveBase(agent, intvl, false), stats_manager_(new StatsManager(agent)) { //Override vm_uve_table_ to point to derived class object vn_uve_table_.reset(new VnUveTable(agent)); diff --git a/src/vnsw/agent/uve/agent_uve_base.cc b/src/vnsw/agent/uve/agent_uve_base.cc index 27ac62d67e2..e551d799d7c 100644 --- a/src/vnsw/agent/uve/agent_uve_base.cc +++ b/src/vnsw/agent/uve/agent_uve_base.cc @@ -27,15 +27,18 @@ using process::g_process_info_constants; AgentUveBase *AgentUveBase::singleton_; -AgentUveBase::AgentUveBase(Agent *agent, uint64_t intvl) - : vn_uve_table_(new VnUveTableBase(agent)), - vm_uve_table_(new VmUveTableBase(agent)), - vrouter_uve_entry_(new VrouterUveEntryBase(agent)), +AgentUveBase::AgentUveBase(Agent *agent, uint64_t intvl, bool create_objects) + : vn_uve_table_(NULL), vm_uve_table_(NULL), vrouter_uve_entry_(NULL), prouter_uve_table_(new ProuterUveTable(agent)), agent_(agent), bandwidth_intvl_(intvl), vrouter_stats_collector_(new VrouterStatsCollector( *(agent->event_manager()->io_service()), this)) { + if (create_objects) { + vn_uve_table_.reset(new VnUveTableBase(agent)); + vm_uve_table_.reset(new VmUveTableBase(agent)); + vrouter_uve_entry_.reset(new VrouterUveEntryBase(agent)); + } singleton_ = this; } diff --git a/src/vnsw/agent/uve/agent_uve_base.h b/src/vnsw/agent/uve/agent_uve_base.h index f8654222f4b..309e979a5c9 100644 --- a/src/vnsw/agent/uve/agent_uve_base.h +++ b/src/vnsw/agent/uve/agent_uve_base.h @@ -20,7 +20,7 @@ class VrouterStatsCollector; class AgentUveBase { public: static const uint64_t kBandwidthInterval = (1000000); // time in microseconds - AgentUveBase(Agent *agent, uint64_t intvl); + AgentUveBase(Agent *agent, uint64_t intvl, bool create_object); virtual ~AgentUveBase(); virtual void Shutdown(); diff --git a/src/vnsw/agent/uve/prouter_uve_table.cc b/src/vnsw/agent/uve/prouter_uve_table.cc index 9909d3655b1..a8ad13efb0c 100644 --- a/src/vnsw/agent/uve/prouter_uve_table.cc +++ b/src/vnsw/agent/uve/prouter_uve_table.cc @@ -431,6 +431,9 @@ void ProuterUveTable::RegisterDBClients() { } void ProuterUveTable::Shutdown(void) { - agent_->physical_device_table()->Unregister(physical_device_listener_id_); - agent_->interface_table()->Unregister(interface_listener_id_); + if (physical_device_listener_id_ != DBTableBase::kInvalidId) + agent_->physical_device_table()-> + Unregister(physical_device_listener_id_); + if (interface_listener_id_ != DBTableBase::kInvalidId) + agent_->interface_table()->Unregister(interface_listener_id_); } diff --git a/src/vnsw/agent/uve/test/agent_uve_test.cc b/src/vnsw/agent/uve/test/agent_uve_test.cc index abc40f44792..783c4b4b6a4 100644 --- a/src/vnsw/agent/uve/test/agent_uve_test.cc +++ b/src/vnsw/agent/uve/test/agent_uve_test.cc @@ -15,6 +15,18 @@ AgentUveBaseTest::AgentUveBaseTest(Agent *agent, uint64_t intvl) : AgentUve(agent, intvl) { + if (vn_uve_table_) { + vn_uve_table_->Shutdown(); + } + if (vm_uve_table_) { + vm_uve_table_->Shutdown(); + } + if (vrouter_uve_entry_) { + vrouter_uve_entry_->Shutdown(); + } + if (prouter_uve_table_) { + prouter_uve_table_->Shutdown(); + } vn_uve_table_.reset(new VnUveTableTest(agent)); vm_uve_table_.reset(new VmUveTableTest(agent)); vrouter_uve_entry_.reset(new VrouterUveEntryTest(agent)); diff --git a/src/vnsw/agent/uve/vm_uve_table_base.cc b/src/vnsw/agent/uve/vm_uve_table_base.cc index 4cb0b003fa9..a208d0fbb57 100644 --- a/src/vnsw/agent/uve/vm_uve_table_base.cc +++ b/src/vnsw/agent/uve/vm_uve_table_base.cc @@ -188,8 +188,10 @@ void VmUveTableBase::RegisterDBClients() { } void VmUveTableBase::Shutdown(void) { - agent_->vm_table()->Unregister(vm_listener_id_); - agent_->interface_table()->Unregister(intf_listener_id_); + if (vm_listener_id_ != DBTableBase::kInvalidId) + agent_->vm_table()->Unregister(vm_listener_id_); + if (intf_listener_id_ != DBTableBase::kInvalidId) + agent_->interface_table()->Unregister(intf_listener_id_); } diff --git a/src/vnsw/agent/uve/vn_uve_table_base.cc b/src/vnsw/agent/uve/vn_uve_table_base.cc index 0df8ec7c0af..96700c91b2b 100644 --- a/src/vnsw/agent/uve/vn_uve_table_base.cc +++ b/src/vnsw/agent/uve/vn_uve_table_base.cc @@ -27,8 +27,10 @@ void VnUveTableBase::RegisterDBClients() { } void VnUveTableBase::Shutdown(void) { - agent_->vn_table()->Unregister(vn_listener_id_); - agent_->interface_table()->Unregister(intf_listener_id_); + if (vn_listener_id_ != DBTableBase::kInvalidId) + agent_->vn_table()->Unregister(vn_listener_id_); + if (intf_listener_id_ != DBTableBase::kInvalidId) + agent_->interface_table()->Unregister(intf_listener_id_); } void VnUveTableBase::DispatchVnMsg(const UveVirtualNetworkAgent &uve) { diff --git a/src/vnsw/agent/uve/vrouter_uve_entry_base.cc b/src/vnsw/agent/uve/vrouter_uve_entry_base.cc index 4746c6dbe32..fc5169b70ad 100644 --- a/src/vnsw/agent/uve/vrouter_uve_entry_base.cc +++ b/src/vnsw/agent/uve/vrouter_uve_entry_base.cc @@ -26,12 +26,48 @@ VrouterUveEntryBase::VrouterUveEntryBase(Agent *agent) : agent_(agent), phy_intf_set_(), prev_stats_(), cpu_stats_count_(0), vn_listener_id_(DBTableBase::kInvalidId), vm_listener_id_(DBTableBase::kInvalidId), - intf_listener_id_(DBTableBase::kInvalidId), prev_vrouter_() { + intf_listener_id_(DBTableBase::kInvalidId), prev_vrouter_(), + do_vn_walk_(false), do_vm_walk_(false), do_interface_walk_(false), + timer_(NULL), vn_walk_id_(DBTableWalker::kInvalidWalkerId), + vm_walk_id_(DBTableWalker::kInvalidWalkerId), + interface_walk_id_(DBTableWalker::kInvalidWalkerId) { + if (agent_->tsn_enabled() || agent_->tor_agent_enabled()) { + timer_ = TimerManager::CreateTimer( + *(agent_->event_manager())->io_service(), "UveDBWalkTimer", + TaskScheduler::GetInstance()->GetTaskId("db::DBTable"), 0); + timer_->Start(kDBWalkInterval, + boost::bind(&VrouterUveEntryBase::TimerExpiry, this)); + } } VrouterUveEntryBase::~VrouterUveEntryBase() { } +bool VrouterUveEntryBase::TimerExpiry() { + Run(); + /* Return true to request auto-restart of timer */ + return true; +} + +bool VrouterUveEntryBase::Run() { + if (do_vn_walk_ && vn_walk_id_ == DBTableWalker::kInvalidWalkerId) { + do_vn_walk_ = false; + StartVnWalk(); + } + + if (do_vm_walk_ && vm_walk_id_ == DBTableWalker::kInvalidWalkerId) { + do_vm_walk_ = false; + StartVmWalk(); + } + + if (do_interface_walk_ && + interface_walk_id_ == DBTableWalker::kInvalidWalkerId) { + do_interface_walk_ = false; + StartInterfaceWalk(); + } + return true; +} + void VrouterUveEntryBase::RegisterDBClients() { VnTable *vn_table = agent_->vn_table(); vn_listener_id_ = vn_table->Register @@ -43,13 +79,33 @@ void VrouterUveEntryBase::RegisterDBClients() { InterfaceTable *intf_table = agent_->interface_table(); intf_listener_id_ = intf_table->Register - (boost::bind(&VrouterUveEntryBase::InterfaceNotify, this, _1, _2)); + (boost::bind(&VrouterUveEntryBase::InterfaceNotify, this, _1, _2)); } void VrouterUveEntryBase::Shutdown(void) { - agent_->interface_table()->Unregister(intf_listener_id_); - agent_->vm_table()->Unregister(vm_listener_id_); - agent_->vn_table()->Unregister(vn_listener_id_); + if (intf_listener_id_ != DBTableBase::kInvalidId) + agent_->interface_table()->Unregister(intf_listener_id_); + if (vm_listener_id_ != DBTableBase::kInvalidId) + agent_->vm_table()->Unregister(vm_listener_id_); + if (vn_listener_id_ != DBTableBase::kInvalidId) + agent_->vn_table()->Unregister(vn_listener_id_); + DBTableWalker *walker = agent_->db()->GetWalker(); + if (walker) { + if (vn_walk_id_ != DBTableWalker::kInvalidWalkerId) { + walker->WalkCancel(vn_walk_id_); + } + if (vm_walk_id_ != DBTableWalker::kInvalidWalkerId) { + walker->WalkCancel(vm_walk_id_); + } + if (interface_walk_id_ != DBTableWalker::kInvalidWalkerId) { + walker->WalkCancel(interface_walk_id_); + } + } + if (timer_) { + timer_->Cancel(); + TimerManager::DeleteTimer(timer_); + timer_ = NULL; + } } void VrouterUveEntryBase::DispatchVrouterMsg(const VrouterAgent &uve) { @@ -61,6 +117,7 @@ void VrouterUveEntryBase::VmWalkDone(DBTableBase *base, StringVectorPtr list) { vrouter_agent.set_name(agent_->agent_name()); vrouter_agent.set_virtual_machine_list(*(list.get())); DispatchVrouterMsg(vrouter_agent); + vm_walk_id_ = DBTableWalker::kInvalidWalkerId; } bool VrouterUveEntryBase::AppendVm(DBTablePartBase *part, DBEntryBase *entry, @@ -75,23 +132,29 @@ bool VrouterUveEntryBase::AppendVm(DBTablePartBase *part, DBEntryBase *entry, return true; } -void VrouterUveEntryBase::VmNotifyHandler(const VmEntry *vm) { +void VrouterUveEntryBase::StartVmWalk() { StringVectorPtr list(new vector()); DBTableWalker *walker = agent_->db()->GetWalker(); - walker->WalkTable(agent_->vm_table(), NULL, + vm_walk_id_ = walker->WalkTable(agent_->vm_table(), NULL, boost::bind(&VrouterUveEntryBase::AppendVm, this, _1, _2, list), boost::bind(&VrouterUveEntryBase::VmWalkDone, this, _1, list)); } -void VrouterUveEntryBase::VmNotify(DBTablePartBase *partition, DBEntryBase *e) { - const VmEntry *vm = static_cast(e); +void VrouterUveEntryBase::VmNotifyHandler() { + if (timer_) { + do_vm_walk_ = true; + } else { + StartVmWalk(); + } +} +void VrouterUveEntryBase::VmNotify(DBTablePartBase *partition, DBEntryBase *e) { DBState *state = static_cast (e->GetState(partition->parent(), vm_listener_id_)); if (e->IsDeleted()) { if (state) { - VmNotifyHandler(vm); + VmNotifyHandler(); e->ClearState(partition->parent(), vm_listener_id_); delete state; } @@ -102,7 +165,7 @@ void VrouterUveEntryBase::VmNotify(DBTablePartBase *partition, DBEntryBase *e) { state = new DBState(); e->SetState(partition->parent(), vm_listener_id_, state); //Send vrouter object only for a add/delete - VmNotifyHandler(vm); + VmNotifyHandler(); } } @@ -111,6 +174,7 @@ void VrouterUveEntryBase::VnWalkDone(DBTableBase *base, StringVectorPtr list) { vrouter_agent.set_name(agent_->agent_name()); vrouter_agent.set_connected_networks(*(list.get())); DispatchVrouterMsg(vrouter_agent); + vn_walk_id_ = DBTableWalker::kInvalidWalkerId; } bool VrouterUveEntryBase::AppendVn(DBTablePartBase *part, DBEntryBase *entry, @@ -123,23 +187,29 @@ bool VrouterUveEntryBase::AppendVn(DBTablePartBase *part, DBEntryBase *entry, return true; } -void VrouterUveEntryBase::VnNotifyHandler(const VnEntry *vn) { +void VrouterUveEntryBase::StartVnWalk() { StringVectorPtr list(new vector()); DBTableWalker *walker = agent_->db()->GetWalker(); - walker->WalkTable(agent_->vn_table(), NULL, + vn_walk_id_ = walker->WalkTable(agent_->vn_table(), NULL, boost::bind(&VrouterUveEntryBase::AppendVn, this, _1, _2, list), boost::bind(&VrouterUveEntryBase::VnWalkDone, this, _1, list)); } -void VrouterUveEntryBase::VnNotify(DBTablePartBase *partition, DBEntryBase *e) { - const VnEntry *vn = static_cast(e); +void VrouterUveEntryBase::VnNotifyHandler() { + if (timer_) { + do_vn_walk_ = true; + } else { + StartVnWalk(); + } +} +void VrouterUveEntryBase::VnNotify(DBTablePartBase *partition, DBEntryBase *e) { DBState *state = static_cast (e->GetState(partition->parent(), vn_listener_id_)); if (e->IsDeleted()) { if (state) { - VnNotifyHandler(vn); + VnNotifyHandler(); e->ClearState(partition->parent(), vn_listener_id_); delete state; } @@ -149,7 +219,7 @@ void VrouterUveEntryBase::VnNotify(DBTablePartBase *partition, DBEntryBase *e) { if (!state) { state = new DBState(); e->SetState(partition->parent(), vn_listener_id_, state); - VnNotifyHandler(vn); + VnNotifyHandler(); } } @@ -167,6 +237,7 @@ void VrouterUveEntryBase::InterfaceWalkDone(DBTableBase *base, vrouter_agent.set_down_interface_count((err_if_list.get()->size() + nova_if_list.get()->size())); DispatchVrouterMsg(vrouter_agent); + interface_walk_id_ = DBTableWalker::kInvalidWalkerId; } bool VrouterUveEntryBase::AppendInterface(DBTablePartBase *part, @@ -192,19 +263,27 @@ bool VrouterUveEntryBase::AppendInterface(DBTablePartBase *part, return true; } -void VrouterUveEntryBase::InterfaceNotifyHandler(const Interface *intf) { +void VrouterUveEntryBase::StartInterfaceWalk() { StringVectorPtr intf_list(new std::vector()); StringVectorPtr err_if_list(new std::vector()); StringVectorPtr nova_if_list(new std::vector()); DBTableWalker *walker = agent_->db()->GetWalker(); - walker->WalkTable(agent_->interface_table(), NULL, - boost::bind(&VrouterUveEntryBase::AppendInterface, this, _1, _2, intf_list, - err_if_list, nova_if_list), + interface_walk_id_ = walker->WalkTable(agent_->interface_table(), NULL, + boost::bind(&VrouterUveEntryBase::AppendInterface, this, _1, _2, + intf_list, err_if_list, nova_if_list), boost::bind(&VrouterUveEntryBase::InterfaceWalkDone, this, _1, intf_list, err_if_list, nova_if_list)); } +void VrouterUveEntryBase::InterfaceNotifyHandler() { + if (timer_) { + do_interface_walk_ = true; + } else { + StartInterfaceWalk(); + } +} + void VrouterUveEntryBase::InterfaceNotify(DBTablePartBase *partition, DBEntryBase *e) { const Interface *intf = static_cast(e); @@ -222,19 +301,19 @@ void VrouterUveEntryBase::InterfaceNotify(DBTablePartBase *partition, set_state = true; vmport_ipv4_active = vm_port->ipv4_active(); vmport_l2_active = vm_port->l2_active(); - InterfaceNotifyHandler(intf); + InterfaceNotifyHandler(); } else if (e->IsDeleted()) { if (state) { reset_state = true; - InterfaceNotifyHandler(intf); + InterfaceNotifyHandler(); } } else { if (state && vm_port->ipv4_active() != state->vmport_ipv4_active_) { - InterfaceNotifyHandler(intf); + InterfaceNotifyHandler(); state->vmport_ipv4_active_ = vm_port->ipv4_active(); } if (state && vm_port->l2_active() != state->vmport_l2_active_) { - InterfaceNotifyHandler(intf); + InterfaceNotifyHandler(); state->vmport_l2_active_ = vm_port->l2_active(); } } @@ -408,13 +487,13 @@ bool VrouterUveEntryBase::SendVrouterMsg() { //Set the Agent mode if (agent_->tor_agent_enabled()) { vrouter_agent.set_mode(vnsVrouterType.VrouterAgentTypeMap.at - (VrouterAgentType::VROUTER_AGENT_TOR)); + (VrouterAgentType::VROUTER_AGENT_TOR)); } else if (agent_->tsn_enabled()) { vrouter_agent.set_mode(vnsVrouterType.VrouterAgentTypeMap.at - (VrouterAgentType::VROUTER_AGENT_TSN)); + (VrouterAgentType::VROUTER_AGENT_TSN)); } else { vrouter_agent.set_mode(vnsVrouterType.VrouterAgentTypeMap.at - (VrouterAgentType::VROUTER_AGENT_EMBEDDED)); + (VrouterAgentType::VROUTER_AGENT_EMBEDDED)); } first = false; diff --git a/src/vnsw/agent/uve/vrouter_uve_entry_base.h b/src/vnsw/agent/uve/vrouter_uve_entry_base.h index c7d1e116465..a000d68925c 100644 --- a/src/vnsw/agent/uve/vrouter_uve_entry_base.h +++ b/src/vnsw/agent/uve/vrouter_uve_entry_base.h @@ -35,6 +35,7 @@ class VrouterUveEntryBase { static const uint8_t bandwidth_mod_1min = 2; static const uint8_t bandwidth_mod_5min = 10; static const uint8_t bandwidth_mod_10min = 20; + static const uint32_t kDBWalkInterval = (1000); // time in milliseconds typedef std::set PhysicalInterfaceSet; typedef boost::shared_ptr > StringVectorPtr; @@ -74,9 +75,14 @@ class VrouterUveEntryBase { void InterfaceNotify(DBTablePartBase *partition, DBEntryBase *e); void VmNotify(DBTablePartBase *partition, DBEntryBase *e); void VnNotify(DBTablePartBase *partition, DBEntryBase *e); - void VmNotifyHandler(const VmEntry *vm); - void VnNotifyHandler(const VnEntry *vn); - void InterfaceNotifyHandler(const Interface *intf); + void VmNotifyHandler(); + void VnNotifyHandler(); + void InterfaceNotifyHandler(); + void StartVnWalk(); + void StartVmWalk(); + void StartInterfaceWalk(); + bool TimerExpiry(); + bool Run(); std::string GetMacAddress(const MacAddress &mac) const; void SubnetToStringList(VirtualGatewayConfig::SubnetList &l1, std::vector &l2); @@ -86,6 +92,13 @@ class VrouterUveEntryBase { DBTableBase::ListenerId vm_listener_id_; DBTableBase::ListenerId intf_listener_id_; VrouterAgent prev_vrouter_; + bool do_vn_walk_; + bool do_vm_walk_; + bool do_interface_walk_; + Timer *timer_; + DBTableWalker::WalkId vn_walk_id_; + DBTableWalker::WalkId vm_walk_id_; + DBTableWalker::WalkId interface_walk_id_; DISALLOW_COPY_AND_ASSIGN(VrouterUveEntryBase); }; diff --git a/src/vnsw/agent/vrouter/ksync/interface_ksync.cc b/src/vnsw/agent/vrouter/ksync/interface_ksync.cc index 9f13e9fdddc..4def78d48a7 100644 --- a/src/vnsw/agent/vrouter/ksync/interface_ksync.cc +++ b/src/vnsw/agent/vrouter/ksync/interface_ksync.cc @@ -417,7 +417,8 @@ KSyncEntry *InterfaceKSyncEntry::UnresolvedReference() { return NULL; } -bool IsValidOsIndex(size_t os_index, Interface::Type type, uint16_t vlan_id) { +bool IsValidOsIndex(size_t os_index, Interface::Type type, uint16_t vlan_id, + VmInterface::VmiType vmi_type) { if (os_index != Interface::kInvalidIndex) return true; @@ -426,6 +427,10 @@ bool IsValidOsIndex(size_t os_index, Interface::Type type, uint16_t vlan_id) { return true; } + if (vmi_type == VmInterface::GATEWAY) { + return true; + } + return false; } @@ -434,7 +439,7 @@ int InterfaceKSyncEntry::Encode(sandesh_op::type op, char *buf, int buf_len) { int encode_len, error; // Dont send message if interface index not known - if (IsValidOsIndex(os_index_, type_, rx_vlan_id_) == false) { + if (IsValidOsIndex(os_index_, type_, rx_vlan_id_, vmi_type_) == false) { return 0; } @@ -457,8 +462,17 @@ int InterfaceKSyncEntry::Encode(sandesh_op::type op, char *buf, int buf_len) { MacAddress mac; if (parent_.get() != NULL) { encoder.set_vifr_type(VIF_TYPE_VIRTUAL_VLAN); - encoder.set_vifr_vlan_id(rx_vlan_id_); - encoder.set_vifr_ovlan_id(tx_vlan_id_); + if (vmi_type_ == VmInterface::GATEWAY && + tx_vlan_id_ == VmInterface::kInvalidVlanId) { + //By default in case of gateway, untagged packet + //would be considered as belonging to interface + //at tag 0 + encoder.set_vifr_vlan_id(0); + encoder.set_vifr_ovlan_id(0); + } else { + encoder.set_vifr_vlan_id(rx_vlan_id_); + encoder.set_vifr_ovlan_id(tx_vlan_id_); + } InterfaceKSyncEntry *parent = (static_cast (parent_.get())); encoder.set_vifr_parent_vif_idx(parent->interface_id()); diff --git a/src/vnsw/agent/vrouter/ksync/route_ksync.cc b/src/vnsw/agent/vrouter/ksync/route_ksync.cc index b3d54a595d5..31eee135a78 100644 --- a/src/vnsw/agent/vrouter/ksync/route_ksync.cc +++ b/src/vnsw/agent/vrouter/ksync/route_ksync.cc @@ -85,9 +85,6 @@ RouteKSyncEntry::RouteKSyncEntry(RouteKSyncObject* obj, const AgentRoute *rt) : static_cast(rt); mac_ = l2_rt->mac(); prefix_len_ = 0; - const AgentPath *path = l2_rt->GetActivePath(); - if (path) - flood_dhcp_ = path->flood_dhcp(); break; } default: { @@ -210,7 +207,7 @@ std::string RouteKSyncEntry::ToString() const { // Check if NH points to a service-chain interface or a Gateway interface static bool IsGatewayOrServiceInterface(const NextHop *nh) { if (nh->GetType() != NextHop::INTERFACE && - nh->GetType() != NextHop::VLAN) + nh->GetType() != NextHop::VLAN && nh->GetType() != NextHop::ARP) return false; const Interface *intf = NULL; @@ -220,6 +217,8 @@ static bool IsGatewayOrServiceInterface(const NextHop *nh) { return true; } else if (nh->GetType() == NextHop::VLAN) { intf = (static_cast(nh))->GetInterface(); + } else if (nh->GetType() == NextHop::ARP) { + intf = (static_cast(nh))->GetInterface(); } const VmInterface *vmi = dynamic_cast(intf); @@ -337,7 +336,6 @@ const NextHop *RouteKSyncEntry::GetActiveNextHop(const AgentRoute *route) const const AgentPath *path = GetActivePath(route); if (path == NULL) return NULL; - return path->ComputeNextHop(ksync_obj_->ksync()->agent()); } @@ -355,7 +353,7 @@ bool RouteKSyncEntry::Sync(DBEntry *e) { Agent *agent = ksync_obj_->ksync()->agent(); const AgentRoute *route = static_cast(e); - const AgentPath *path = route->GetActivePath(); + const AgentPath *path = GetActivePath(route); if (path->peer() == agent->local_vm_peer()) local_vm_peer_route_ = true; else @@ -415,14 +413,26 @@ bool RouteKSyncEntry::Sync(DBEntry *e) { mac_ = mac; ret = true; } - } - if (BuildArpFlags(e, path, mac_)) - ret = true; + if (BuildArpFlags(e, path, mac_)) + ret = true; + } - if (flood_dhcp_ != path->flood_dhcp()) { - flood_dhcp_ = path->flood_dhcp(); - ret = true; + if (rt_type_ == Agent::BRIDGE) { + const BridgeRouteEntry *l2_rt = + static_cast(route); + + //First search for v4 + const MacVmBindingPath *dhcp_path = dynamic_cast + (l2_rt->FindMacVmBindingPath()); + bool flood_dhcp = false; + if (dhcp_path) + flood_dhcp = dhcp_path->flood_dhcp(); + + if (flood_dhcp_ != flood_dhcp) { + flood_dhcp_ = flood_dhcp; + ret = true; + } } return ret; diff --git a/src/vnsw/agent/vxlan_agent/linux/linux_vxlan_agent_init.cc b/src/vnsw/agent/vxlan_agent/linux/linux_vxlan_agent_init.cc index ca129dccc13..8b0249bd517 100644 --- a/src/vnsw/agent/vxlan_agent/linux/linux_vxlan_agent_init.cc +++ b/src/vnsw/agent/vxlan_agent/linux/linux_vxlan_agent_init.cc @@ -69,7 +69,8 @@ void LinuxVxlanAgentInit::FactoryInit() { void LinuxVxlanAgentInit::CreateModules() { ksync_vxlan_.reset(new KSyncLinuxVxlan(agent())); - uve_.reset(new AgentUveBase(agent(), AgentUveBase::kBandwidthInterval)); + uve_.reset(new AgentUveBase(agent(), AgentUveBase::kBandwidthInterval, + true)); agent()->set_uve(uve_.get()); }