From 2cbe98abec7b591924244267b3fb53fd8ba90ea8 Mon Sep 17 00:00:00 2001 From: Naveen N Date: Tue, 16 Feb 2016 14:46:23 +0530 Subject: [PATCH] * Resync path preference value upon delete and readd of path In case of L2 evpn route, upon ethernet tag, policy change or preference change agent was deleting and readding local vm path. In this scenario path preference values were lost and bridge table was pointing to backup nexthop due to preference mismatch. Closes-bug:#1541658 Change-Id: I1888a74535b464e2ca7bdb33cea6d3ac97326206 --- src/vnsw/agent/oper/path_preference.cc | 3 ++ src/vnsw/agent/oper/test/test_aap.cc | 44 ++++++++++++++++++++++++++ src/vnsw/agent/oper/vm_interface.cc | 1 + src/vnsw/agent/oper/vm_interface.h | 2 +- src/vnsw/agent/pkt/flow_table.cc | 7 ++++ 5 files changed, 56 insertions(+), 1 deletion(-) diff --git a/src/vnsw/agent/oper/path_preference.cc b/src/vnsw/agent/oper/path_preference.cc index 4ebfcb14765..3860166456f 100644 --- a/src/vnsw/agent/oper/path_preference.cc +++ b/src/vnsw/agent/oper/path_preference.cc @@ -338,6 +338,9 @@ void PathPreferenceSM::Process() { const AgentPath *path = static_cast(it.operator->()); if (path == local_path) { + if (path->path_preference().sequence() < sequence()) { + EnqueuePathChange(); + } continue; } //Get best preference and sequence no from all BGP peer diff --git a/src/vnsw/agent/oper/test/test_aap.cc b/src/vnsw/agent/oper/test/test_aap.cc index df3b48fc039..ae4e467a3cb 100644 --- a/src/vnsw/agent/oper/test/test_aap.cc +++ b/src/vnsw/agent/oper/test/test_aap.cc @@ -309,6 +309,7 @@ TEST_F(TestAap, EvpnRoute_3) { EXPECT_TRUE(path->path_preference().wait_for_traffic() == false); } #endif + //Just add a local path, verify that sequence no gets initialized to 0 TEST_F(TestAap, StateMachine_1) { Ip4Address ip = Ip4Address::from_string("1.1.1.1"); @@ -865,6 +866,49 @@ TEST_F(TestAap, StateMachine_15) { WAIT_FOR(1000, 1000, (path->path_preference().wait_for_traffic() == true)); } +TEST_F(TestAap, StateMachine_16) { + Ip4Address ip = Ip4Address::from_string("10.10.10.10"); + MacAddress mac("0a:0b:0c:0d:0e:0f"); + + VmInterface *vm_intf = static_cast(VmPortGet(1)); + AddAap("intf1", 1, ip, mac.ToString()); + EXPECT_TRUE(RouteFind("vrf1", ip, 32)); + EXPECT_TRUE(EvpnRouteGet("vrf1", mac, ip, 0)); + EXPECT_TRUE(vm_intf->allowed_address_pair_list().list_.size() == 1); + + client->WaitForIdle(); + + EvpnRouteEntry *rt = EvpnRouteGet("vrf1", mac, ip, 0); + const AgentPath *path = rt->FindPath(vm_intf->peer()); + + Agent::GetInstance()->oper_db()->route_preference_module()-> + EnqueueTrafficSeen(ip, 32, vm_intf->id(), vm_intf->vrf()->vrf_id(), + mac); + client->WaitForIdle(); + EXPECT_TRUE(path->path_preference().sequence() == 1); + EXPECT_TRUE(path->path_preference().preference() == PathPreference::HIGH); + EXPECT_TRUE(path->path_preference().ecmp() == false); + EXPECT_TRUE(path->path_preference().wait_for_traffic() == false); + + AddSg("sg1", 1); + AddAcl("acl1", 1); + AddLink("security-group", "sg1", "access-control-list", "acl1"); + AddLink("virtual-machine-interface", "intf1", "security-group", "sg1"); + client->WaitForIdle(); + path = rt->FindPath(vm_intf->peer()); + EXPECT_TRUE(path->path_preference().sequence() == 1); + EXPECT_TRUE(path->path_preference().preference() == PathPreference::HIGH); + EXPECT_TRUE(path->path_preference().ecmp() == false); + EXPECT_TRUE(path->path_preference().wait_for_traffic() == false); + + DelLink("virtual-machine-interface", "vnet1", "security-group", "sg1"); + DelLink("security-group", "sg1", "access-control-list", "acl1"); + DelAcl("acl1"); + DelNode("security-group", "sg1"); + client->WaitForIdle(); +} + + int main(int argc, char *argv[]) { GETUSERARGS(); client = TestInit(init_file, ksync_init); diff --git a/src/vnsw/agent/oper/vm_interface.cc b/src/vnsw/agent/oper/vm_interface.cc index cd30e899f9b..8eac055e474 100644 --- a/src/vnsw/agent/oper/vm_interface.cc +++ b/src/vnsw/agent/oper/vm_interface.cc @@ -3296,6 +3296,7 @@ void VmInterface::InstanceIpList::Insert(const InstanceIp *rhs) { void VmInterface::InstanceIpList::Update(const InstanceIp *lhs, const InstanceIp *rhs) { lhs->set_del_pending(false); + lhs->ecmp_ = rhs->ecmp_; } void VmInterface::InstanceIpList::Remove(InstanceIpSet::iterator &it) { diff --git a/src/vnsw/agent/oper/vm_interface.h b/src/vnsw/agent/oper/vm_interface.h index 677eb363900..d4e8006ddad 100644 --- a/src/vnsw/agent/oper/vm_interface.h +++ b/src/vnsw/agent/oper/vm_interface.h @@ -336,7 +336,7 @@ class VmInterface : public Interface { } const IpAddress ip_; - bool ecmp_; + mutable bool ecmp_; mutable bool l2_installed_; const Ip4Address gw_ip_; mutable bool old_ecmp_; diff --git a/src/vnsw/agent/pkt/flow_table.cc b/src/vnsw/agent/pkt/flow_table.cc index 515085f8565..d67c0bea4d5 100644 --- a/src/vnsw/agent/pkt/flow_table.cc +++ b/src/vnsw/agent/pkt/flow_table.cc @@ -1325,6 +1325,13 @@ bool FlowEntry::SetRpfNHState(FlowTable *ft, const NextHop *nh) { } } + if (data_.nh_state_ && nh) { + if (data_.nh_state_->nh()->GetType() != NextHop::COMPOSITE && + nh->GetType() == NextHop::COMPOSITE) { + set_flags(FlowEntry::Trap); + } + } + if (data_.nh_state_ != nh_state) { data_.nh_state_ = nh_state; return true;