diff --git a/src/vnsw/agent/oper/vm_interface.cc b/src/vnsw/agent/oper/vm_interface.cc index dbcba764bd8..c91e3615127 100644 --- a/src/vnsw/agent/oper/vm_interface.cc +++ b/src/vnsw/agent/oper/vm_interface.cc @@ -1190,7 +1190,8 @@ void VmInterface::UpdateL3(bool old_ipv4_active, VrfEntry *old_vrf, policy_change, old_vrf, old_dhcp_addr); } - UpdateIpv4InstanceIp(force_update, policy_change, false, old_ethernet_tag); + UpdateIpv4InstanceIp(force_update, policy_change, false, + old_ethernet_tag, old_vrf); UpdateMetadataRoute(old_ipv4_active, old_vrf); UpdateFloatingIp(force_update, policy_change, false, old_ethernet_tag); UpdateServiceVlan(force_update, policy_change); @@ -1277,7 +1278,8 @@ void VmInterface::UpdateL2(bool old_l2_active, VrfEntry *old_vrf, old_layer3_forwarding, policy_change, Ip4Address(), Ip6Address(), MacAddress::FromString(vm_mac_)); - UpdateIpv4InstanceIp(force_update, policy_change, true, old_ethernet_tag); + UpdateIpv4InstanceIp(force_update, policy_change, true, old_ethernet_tag, + old_vrf); UpdateIpv6InstanceIp(force_update, policy_change, true, old_ethernet_tag); UpdateFloatingIp(force_update, policy_change, true, old_ethernet_tag); UpdateAllowedAddressPair(force_update, policy_change, true, old_l2_active, @@ -1341,7 +1343,7 @@ void VmInterface::ApplyConfigCommon(const VrfEntry *old_vrf, void VmInterface::ApplyMacVmBindingConfig(const VrfEntry *old_vrf, bool old_active, bool old_dhcp_enable) { - if (!IsActive()) { + if (!IsActive() || old_vrf != vrf()) { DeleteMacVmBinding(old_vrf); return; } @@ -2951,6 +2953,10 @@ void VmInterface::UpdateL2InterfaceRoute(bool old_l2_active, bool force_update, force_update = true; } + if (old_vrf && old_vrf != vrf()) { + force_update = true; + } + //Encap change will result in force update of l2 routes. if (force_update) { DeleteL2InterfaceRoute(true, old_vrf, old_v4_addr, @@ -4412,8 +4418,8 @@ bool VmInterface::CopyIp6Address(const Ip6Address &addr) { } void VmInterface::UpdateIpv4InstanceIp(bool force_update, bool policy_change, - bool l2, - uint32_t old_ethernet_tag) { + bool l2, uint32_t old_ethernet_tag, + VrfEntry *old_vrf) { if (l2 && old_ethernet_tag != ethernet_tag()) { force_update = true; } @@ -4427,6 +4433,9 @@ void VmInterface::UpdateIpv4InstanceIp(bool force_update, bool policy_change, instance_ipv4_list_.list_.erase(prev); } } else { + if (old_vrf && (old_vrf != vrf())) { + prev->DeActivate(this, l2, old_vrf, old_ethernet_tag); + } prev->Activate(this, force_update||policy_change, l2, old_ethernet_tag); } diff --git a/src/vnsw/agent/oper/vm_interface.h b/src/vnsw/agent/oper/vm_interface.h index be06b886449..1db7251da41 100644 --- a/src/vnsw/agent/oper/vm_interface.h +++ b/src/vnsw/agent/oper/vm_interface.h @@ -697,12 +697,11 @@ class VmInterface : public Interface { int old_ethernet_tag, const MacAddress &mac) const; - void DeleteL2Route(const std::string &vrf_name, - const MacAddress &mac); void UpdateVrfAssignRule(); void DeleteVrfAssignRule(); void UpdateIpv4InstanceIp(bool force_update, bool policy_change, - bool l2, uint32_t old_ethernet_tag); + bool l2, uint32_t old_ethernet_tag, + VrfEntry *old_vrf); void DeleteIpv4InstanceIp(bool l2, uint32_t old_ethernet_tag, VrfEntry *old_vrf); void UpdateIpv6InstanceIp(bool force_update, bool policy_change, diff --git a/src/vnsw/agent/uve/test/test_vn_uve.cc b/src/vnsw/agent/uve/test/test_vn_uve.cc index 273ddddf452..fbd5b97e7f4 100644 --- a/src/vnsw/agent/uve/test/test_vn_uve.cc +++ b/src/vnsw/agent/uve/test/test_vn_uve.cc @@ -53,6 +53,7 @@ class UveVnUveTest : public ::testing::Test { public: UveVnUveTest() : util_() { peer_ = CreateBgpPeer("127.0.0.1", "Bgp Peer"); + agent_ = Agent::GetInstance(); } virtual ~UveVnUveTest() { DeleteBgpPeer(peer_); @@ -60,7 +61,7 @@ class UveVnUveTest : public ::testing::Test { bool InterVnStatsMatch(const string &svn, const string &dvn, uint32_t pkts, uint32_t bytes, bool out) { VnUveTableTest *vut = static_cast - (Agent::GetInstance()->uve()->vn_uve_table()); + (agent_->uve()->vn_uve_table()); const VnUveEntry::VnStatsSet *stats_set = vut->FindInterVnStats(svn); if (!stats_set) { @@ -82,7 +83,7 @@ class UveVnUveTest : public ::testing::Test { return false; } void FlowSetUp() { - EXPECT_EQ(0U, Agent::GetInstance()->pkt()->flow_table()->Size()); + EXPECT_EQ(0U, agent_->pkt()->flow_table()->Size()); client->Reset(); CreateVmportEnv(input, 2, 1); client->WaitForIdle(5); @@ -106,27 +107,28 @@ class UveVnUveTest : public ::testing::Test { client->WaitForIdle(3); WAIT_FOR(1000, 1000, (VmPortFind(input, 0) == false)); WAIT_FOR(1000, 1000, (VmPortFind(input, 1) == false)); - EXPECT_EQ(0U, Agent::GetInstance()->pkt()->flow_table()->Size()); + EXPECT_EQ(0U, agent_->pkt()->flow_table()->Size()); } void AclAdd(int id) { char acl_name[80]; sprintf(acl_name, "acl%d", id); - uint32_t count = Agent::GetInstance()->acl_table()->Size(); + uint32_t count = agent_->acl_table()->Size(); client->Reset(); AddAcl(acl_name, id); EXPECT_TRUE(client->AclNotifyWait(1)); - EXPECT_EQ((count + 1), Agent::GetInstance()->acl_table()->Size()); + EXPECT_EQ((count + 1), agent_->acl_table()->Size()); } TestUveUtil util_; BgpPeer *peer_; + Agent *agent_; }; TEST_F(UveVnUveTest, VnAddDel_1) { VnUveTableTest *vnut = static_cast - (Agent::GetInstance()->uve()->vn_uve_table()); + (agent_->uve()->vn_uve_table()); //Add VN util_.VnAdd(1); client->WaitForIdle(); @@ -160,7 +162,7 @@ TEST_F(UveVnUveTest, VnIntfAddDel_1) { }; VnUveTableTest *vnut = static_cast - (Agent::GetInstance()->uve()->vn_uve_table()); + (agent_->uve()->vn_uve_table()); //Add VN util_.VnAdd(input[0].vn_id); client->WaitForIdle(); @@ -210,7 +212,7 @@ TEST_F(UveVnUveTest, VnIntfAddDel_1) { util_.EnqueueSendVnUveTask(); client->WaitForIdle(); - //Verify UVE + //Verify UVE WAIT_FOR(1000, 500, (vnut->send_count() >= 2U)); EXPECT_EQ(1U, uve1->get_virtualmachine_list().size()); EXPECT_EQ(1U, uve1->get_interface_list().size()); @@ -242,7 +244,7 @@ TEST_F(UveVnUveTest, VnIntfAddDel_1) { client->WaitForIdle(); WAIT_FOR(1000, 500, (vnut->VnUveCount() == 2U)); - //Verify UVE + //Verify UVE EXPECT_EQ(1U, vnut->delete_count()); //other cleanup @@ -273,7 +275,7 @@ TEST_F(UveVnUveTest, VnIntfAddDel_1) { TEST_F(UveVnUveTest, VnChange_1) { VnUveTableTest *vnut = static_cast - (Agent::GetInstance()->uve()->vn_uve_table()); + (agent_->uve()->vn_uve_table()); //Add VN util_.VnAdd(1); client->WaitForIdle(); @@ -354,7 +356,7 @@ TEST_F(UveVnUveTest, VnUVE_2) { }; VnUveTableTest *vnut = static_cast - (Agent::GetInstance()->uve()->vn_uve_table()); + (agent_->uve()->vn_uve_table()); //Create VM, VN, VRF and Vmport CreateVmportEnv(input, 2); client->WaitForIdle(); @@ -431,7 +433,7 @@ TEST_F(UveVnUveTest, VnUVE_3) { }; VnUveTableTest *vnut = static_cast - (Agent::GetInstance()->uve()->vn_uve_table()); + (agent_->uve()->vn_uve_table()); vnut->ClearCount(); //Create VM, VN, VRF and Vmport CreateVmportEnv(input, 2); @@ -530,7 +532,7 @@ TEST_F(UveVnUveTest, FlowCount_1) { KSyncSockTypeMap *ksock = KSyncSockTypeMap::GetKSyncSockTypeMap(); EXPECT_EQ(0U, ksock->flow_map.size()); VnUveTableTest *vnut = static_cast - (Agent::GetInstance()->uve()->vn_uve_table()); + (agent_->uve()->vn_uve_table()); vnut->ClearCount(); FlowSetUp(); TestFlow flow[] = { @@ -553,13 +555,13 @@ TEST_F(UveVnUveTest, FlowCount_1) { }; CreateFlow(flow, 2); - EXPECT_EQ(4U, Agent::GetInstance()->pkt()->flow_table()->Size()); + EXPECT_EQ(4U, agent_->pkt()->flow_table()->Size()); //Verify the ingress and egress flow counts uint32_t in_count, out_count; const FlowEntry *fe = flow[0].pkt_.FlowFetch(); const VnEntry *vn = fe->data().vn_entry.get(); - Agent::GetInstance()->pkt()->flow_table()->VnFlowCounters(vn, &in_count, &out_count); + agent_->pkt()->flow_table()->VnFlowCounters(vn, &in_count, &out_count); EXPECT_EQ(4U, in_count); EXPECT_EQ(4U, out_count); @@ -574,7 +576,7 @@ TEST_F(UveVnUveTest, FlowCount_1) { DeleteFlow(flow, 1); WAIT_FOR(1000, 1000, - ((Agent::GetInstance()->pkt()->flow_table()->Size() == 2U))); + ((agent_->pkt()->flow_table()->Size() == 2U))); vnut->SendVnStats(false); EXPECT_EQ(2U, uve1->get_ingress_flow_count()); EXPECT_EQ(2U, uve1->get_egress_flow_count()); @@ -598,7 +600,7 @@ TEST_F(UveVnUveTest, FlowCount_2) { KSyncSockTypeMap *ksock = KSyncSockTypeMap::GetKSyncSockTypeMap(); EXPECT_EQ(0U, ksock->flow_map.size()); VnUveTableTest *vnut = static_cast - (Agent::GetInstance()->uve()->vn_uve_table()); + (agent_->uve()->vn_uve_table()); vnut->ClearCount(); FlowSetUp(); @@ -633,7 +635,7 @@ TEST_F(UveVnUveTest, FlowCount_2) { uint32_t in_count, out_count; const FlowEntry *fe = flow[0].pkt_.FlowFetch(); const VnEntry *vn = fe->data().vn_entry.get(); - Agent::GetInstance()->pkt()->flow_table()->VnFlowCounters(vn, &in_count, &out_count); + agent_->pkt()->flow_table()->VnFlowCounters(vn, &in_count, &out_count); EXPECT_EQ(2U, in_count); EXPECT_EQ(2U, out_count); @@ -652,7 +654,7 @@ TEST_F(UveVnUveTest, FlowCount_2) { //Delete a flow DeleteFlow(flow, 1); WAIT_FOR(1000, 1000, - ((Agent::GetInstance()->pkt()->flow_table()->Size() == 2U))); + ((agent_->pkt()->flow_table()->Size() == 2U))); //Trigger VN UVE send vnut->SendVnStats(false); @@ -685,7 +687,7 @@ TEST_F(UveVnUveTest, FipCount) { }; VnUveTableTest *vnut = static_cast - (Agent::GetInstance()->uve()->vn_uve_table()); + (agent_->uve()->vn_uve_table()); //Add VN util_.VnAdd(input[0].vn_id); // Nova Port add message @@ -871,7 +873,7 @@ TEST_F(UveVnUveTest, VnVrfAssoDisassoc_1) { }; VnUveTableTest *vnut = static_cast - (Agent::GetInstance()->uve()->vn_uve_table()); + (agent_->uve()->vn_uve_table()); //Add VN util_.VnAdd(input[0].vn_id); client->WaitForIdle(); @@ -940,7 +942,7 @@ TEST_F(UveVnUveTest, LinkLocalVn_Xen) { {"vnet1", 1, "1.1.1.1", "00:00:00:01:01:01", 1, 1}, }; - Agent *agent = Agent::GetInstance(); + Agent *agent = agent_; VnUveTableTest *vnut = static_cast (agent->uve()->vn_uve_table()); //Add VN @@ -1060,7 +1062,7 @@ TEST_F(UveVnUveTest, InterVnStats_1) { EXPECT_EQ(0U, ksock->flow_map.size()); VnUveTableTest *vnut = static_cast - (Agent::GetInstance()->uve()->vn_uve_table()); + (agent_->uve()->vn_uve_table()); vnut->ClearCount(); FlowSetUp(); TestFlow flow[] = { @@ -1083,7 +1085,7 @@ TEST_F(UveVnUveTest, InterVnStats_1) { }; CreateFlow(flow, 2); - EXPECT_EQ(4U, Agent::GetInstance()->pkt()->flow_table()->Size()); + EXPECT_EQ(4U, agent_->pkt()->flow_table()->Size()); //Invoke FlowStatsCollector to update the stats util_.EnqueueFlowStatsCollectorTask(); @@ -1159,7 +1161,7 @@ TEST_F(UveVnUveTest, VnBandwidth) { EXPECT_EQ(0U, ksock->flow_map.size()); VnUveTableTest *vnut = static_cast - (Agent::GetInstance()->uve()->vn_uve_table()); + (agent_->uve()->vn_uve_table()); vnut->ClearCount(); FlowSetUp(); TestFlow flow[] = { @@ -1182,7 +1184,7 @@ TEST_F(UveVnUveTest, VnBandwidth) { }; CreateFlow(flow, 2); - EXPECT_EQ(4U, Agent::GetInstance()->pkt()->flow_table()->Size()); + EXPECT_EQ(4U, agent_->pkt()->flow_table()->Size()); //Invoke FlowStatsCollector to update the stats util_.EnqueueFlowStatsCollectorTask(); @@ -1232,6 +1234,149 @@ TEST_F(UveVnUveTest, VnBandwidth) { EXPECT_EQ(0U, ksock->flow_map.size()); } +/* Change Vn for an Interface. To verify VN change is handled as part of + interface notification */ +TEST_F(UveVnUveTest, VnChangeForIntf_1) { + struct PortInfo input[] = { + {"vnet1", 1, "1.1.1.1", "00:00:00:01:01:01", 1, 1}, + }; + + VnUveTableTest *vnut = static_cast + (agent_->uve()->vn_uve_table()); + int old_vn_uve_count = vnut->VnUveCount(); + //Add VN + util_.VnAdd(input[0].vn_id); + client->WaitForIdle(); + WAIT_FOR(1000, 500, (VnGet(1) != NULL)); + WAIT_FOR(1000, 500, (vnut->VnUveCount() == (old_vn_uve_count + 1))); + + util_.EnqueueSendVnUveTask(); + client->WaitForIdle(); + WAIT_FOR(1000, 500, (vnut->VnUveObject("vn1") != NULL)); + + UveVirtualNetworkAgent *uve1 = vnut->VnUveObject("vn1"); + + // Nova Port add message + util_.NovaPortAdd(input); + + // Config Port add + util_.ConfigPortAdd(input); + + //Verify that the port is inactive + EXPECT_TRUE(VmPortInactive(input, 0)); + + //Add necessary objects and links to make vm-intf active + util_.VmAdd(input[0].vm_id); + util_.VrfAdd(input[0].vn_id); + AddLink("virtual-network", "vn1", "routing-instance", "vrf1"); + client->WaitForIdle(); + AddLink("virtual-network", "vn1", "virtual-machine-interface", "vnet1"); + client->WaitForIdle(); + AddLink("virtual-machine", "vm1", "virtual-machine-interface", "vnet1"); + client->WaitForIdle(); + AddVmPortVrf("vnet1", "", 0); + client->WaitForIdle(); + AddInstanceIp("instance0", input[0].vm_id, input[0].addr); + AddLink("virtual-machine-interface", input[0].name, + "instance-ip", "instance0"); + client->WaitForIdle(); + AddLink("virtual-machine-interface-routing-instance", "vnet1", + "routing-instance", "vrf1"); + client->WaitForIdle(); + AddLink("virtual-machine-interface-routing-instance", "vnet1", + "virtual-machine-interface", "vnet1"); + client->WaitForIdle(); + EXPECT_TRUE(VmPortActive(input, 0)); + + /* Create a new VN and associate it with existing VMI. This should + * trigger change of VN for the VMI */ + util_.VnAdd(2); + client->WaitForIdle(); + WAIT_FOR(1000, 500, (VnGet(2) != NULL)); + util_.VrfAdd(2); + client->WaitForIdle(); + + agent_->db()->SetQueueDisable(true); + DelLink("virtual-network", "vn1", "virtual-machine-interface", "vnet1"); + DelLink("virtual-machine-interface-routing-instance", "vnet1", + "routing-instance", "vrf1"); + client->WaitForIdle(); + AddLink("virtual-network", "vn2", "routing-instance", "vrf2"); + AddLink("virtual-network", "vn2", "virtual-machine-interface", "vnet1"); + AddLink("virtual-machine-interface-routing-instance", "vnet1", + "routing-instance", "vrf2"); + agent_->db()->SetQueueDisable(false); + client->WaitForIdle(); + WAIT_FOR(1000, 5000, (vnut->GetVnUveEntry("vn2") != NULL)); + + VmInterface *vmi = VmInterfaceGet(input[0].intf_id); + EXPECT_TRUE(vmi != NULL); + VnEntry *vn = VnGet(2); + EXPECT_TRUE(vn != NULL); + WAIT_FOR(1000, 5000, (vmi->vn() == vn)); + + util_.EnqueueSendVnUveTask(); + client->WaitForIdle(); + //Verify UVE + WAIT_FOR(1000, 500, (vnut->send_count() >= 2U)); + EXPECT_EQ(0U, uve1->get_interface_list().size()); + + UveVirtualNetworkAgent *uve2 = vnut->VnUveObject("vn2"); + EXPECT_EQ(1U, uve2->get_interface_list().size()); + + // Delete virtual-machine-interface to vrf link attribute + DelLink("virtual-machine-interface-routing-instance", "vnet1", + "routing-instance", "vrf1"); + DelLink("virtual-machine-interface-routing-instance", "vnet1", + "virtual-machine-interface", "vnet1"); + client->WaitForIdle(); + + DelLink("virtual-network", "vn2", "virtual-machine-interface", "vnet1"); + DelLink("virtual-machine-interface-routing-instance", "vnet1", + "routing-instance", "vrf2"); + DelLink("virtual-network", "vn2", "routing-instance", "vrf2"); + DelNode("virtual-network", "vn2"); + DelNode("routing-instance", "vrf2"); + client->WaitForIdle(); + WAIT_FOR(1000, 5000, (VrfFind("vrf2") == false)); + + //Delete VN + util_.VnDelete(input[0].vn_id); + + util_.EnqueueSendVnUveTask(); + client->WaitForIdle(); + WAIT_FOR(1000, 500, (vnut->VnUveCount() == old_vn_uve_count)); + + //Verify UVE + EXPECT_EQ(2U, vnut->delete_count()); + + //other cleanup + DelLink("virtual-machine-interface", input[0].name, + "instance-ip", "instance0"); + DelLink("virtual-machine", "vm1", "virtual-machine-interface", "vnet1"); + DelLink("virtual-network", "vn1", "virtual-machine-interface", "vnet1"); + client->WaitForIdle(); + EXPECT_TRUE(VmPortInactive(input, 0)); + + DelLink("virtual-network", "vn1", "routing-instance", "vrf1"); + DelNode("virtual-machine-interface-routing-instance", "vnet1"); + DelNode("virtual-machine", "vm1"); + DelNode("routing-instance", "vrf1"); + DelNode("virtual-network", "vn1"); + DelNode("virtual-machine-interface", "vnet1"); + DelInstanceIp("instance0"); + client->WaitForIdle(); + IntfCfgDel(input, 0); + client->WaitForIdle(); + WAIT_FOR(1000, 5000, (VrfFind("vrf1") == false)); + WAIT_FOR(1000, 5000, (vnut->GetVnUveEntry("vn1") == NULL)); + WAIT_FOR(1000, 5000, (vnut->GetVnUveEntry("vn2") == NULL)); + + //clear counters at the end of test case + client->Reset(); + vnut->ClearCount(); +} + int main(int argc, char **argv) { GETUSERARGS(); /* Sent AgentStatsCollector and FlowStatsCollector timer intervals to 10 diff --git a/src/vnsw/agent/uve/vn_uve_table_base.cc b/src/vnsw/agent/uve/vn_uve_table_base.cc index ee0935b4f0b..00ea5cd8562 100644 --- a/src/vnsw/agent/uve/vn_uve_table_base.cc +++ b/src/vnsw/agent/uve/vn_uve_table_base.cc @@ -277,8 +277,14 @@ void VnUveTableBase::InterfaceNotify(DBTablePartBase *partition, DBEntryBase *e) e->SetState(partition->parent(), intf_listener_id_, state); InterfaceAddHandler(vn, vm_port, vm_name, state); } else { - /* Change in VN name is not supported now */ - assert(state->vn_name_.compare(vn->GetName()) == 0); + if (state->vn_name_.compare(vn->GetName()) != 0) { + InterfaceDeleteHandler(state->vm_name_, state->vn_name_, + vm_port); + state->vm_name_ = vm_name; + state->vn_name_ = vn->GetName(); + InterfaceAddHandler(vn, vm_port, vm_name, state); + return; + } if (state->vm_name_.compare(vm_name) != 0) { InterfaceAddHandler(vn, vm_port, vm_name, state); state->vm_name_ = vm_name;