From 8631919904412b4d84eebbea4814bc1c5c9ef18c Mon Sep 17 00:00:00 2001 From: Naveen N Date: Tue, 19 Apr 2016 14:53:03 +0530 Subject: [PATCH] * Install FIP EVPN routes received from control-node Currently FIP evpn routes points to receive NH, and this path once reflected from control-node were not added to agent oper DB resulting in bridge table route for floating-ip to be wrong in case of active-backup scenario. Closes-bug:#1568960,#1571938 Change-Id: I6759ebd4577505d12b530bb3cc8262d54a703f1a --- src/vnsw/agent/controller/controller_peer.cc | 26 +++---- src/vnsw/agent/controller/controller_peer.h | 5 +- .../agent/controller/controller_route_path.cc | 15 ++++ .../agent/controller/controller_route_path.h | 17 ++++- src/vnsw/agent/oper/agent_path.cc | 12 +++- src/vnsw/agent/oper/evpn_route.cc | 23 +++++++ src/vnsw/agent/oper/evpn_route.h | 6 ++ src/vnsw/agent/test/test_route.cc | 68 ++++++++++++++++++- 8 files changed, 150 insertions(+), 22 deletions(-) diff --git a/src/vnsw/agent/controller/controller_peer.cc b/src/vnsw/agent/controller/controller_peer.cc index 1e0455be069..d09437f3a6f 100644 --- a/src/vnsw/agent/controller/controller_peer.cc +++ b/src/vnsw/agent/controller/controller_peer.cc @@ -907,30 +907,24 @@ void AgentXmppChannel::AddEvpnRoute(const std::string &vrf_name, return; } - // We expect only INTERFACE nexthop for evpn routes - const InterfaceNH *intf_nh = dynamic_cast(nh); - if (nh->GetType() != NextHop::INTERFACE) { - CONTROLLER_INFO_TRACE(Trace, GetBgpPeerName(), vrf_name, - "Invalid nexthop in evpn route"); - return; - } - //In EVPN, if interface IP is not same as IP received in Evpn route //then use receive NH. This is done because this received evpn ip is //a floating IP associated with VM and it shoul be routed. - const VmInterface *vm_intf = - dynamic_cast(intf_nh-> - GetInterface()); - if (vm_intf) { - if (vm_intf->IsFloatingIp(ip_addr)) { - rt_table->AddReceiveRouteReq(bgp_peer_id(), vrf_name, + if (nh->GetType() == NextHop::L2_RECEIVE) { + rt_table->AddControllerReceiveRouteReq(bgp_peer_id(), vrf_name, label, mac, ip_addr, item->entry.nlri.ethernet_tag, item->entry.virtual_network, path_preference); - return; - } + return; + } + // We expect only INTERFACE nexthop for evpn routes + const InterfaceNH *intf_nh = dynamic_cast(nh); + if (nh->GetType() != NextHop::INTERFACE) { + CONTROLLER_INFO_TRACE(Trace, GetBgpPeerName(), vrf_name, + "Invalid nexthop in evpn route"); + return; } SecurityGroupList sg_list = item->entry.security_group_list.security_group; diff --git a/src/vnsw/agent/controller/controller_peer.h b/src/vnsw/agent/controller/controller_peer.h index 1e6539095bc..f5c909fe885 100644 --- a/src/vnsw/agent/controller/controller_peer.h +++ b/src/vnsw/agent/controller/controller_peer.h @@ -161,7 +161,8 @@ class AgentXmppChannel { bool associate, const AgentPath *path, bool assisted_replication); - + void AddEvpnRoute(const std::string &vrf_name, std::string mac_addr, + autogen::EnetItemType *item); protected: virtual void WriteReadyCb(const boost::system::error_code &ec); @@ -174,8 +175,6 @@ class AgentXmppChannel { void AddMulticastEvpnRoute(const std::string &vrf_name, const MacAddress &mac, autogen::EnetItemType *item); - void AddEvpnRoute(const std::string &vrf_name, std::string mac_addr, - autogen::EnetItemType *item); void AddRemoteRoute(std::string vrf_name, IpAddress ip, uint32_t plen, autogen::ItemType *item, const VnListType &vn_list); diff --git a/src/vnsw/agent/controller/controller_route_path.cc b/src/vnsw/agent/controller/controller_route_path.cc index 12a1bc7ba01..d803bd7457c 100644 --- a/src/vnsw/agent/controller/controller_route_path.cc +++ b/src/vnsw/agent/controller/controller_route_path.cc @@ -441,3 +441,18 @@ string ControllerMulticastRoute::PeerInvalidMsg bool ControllerMulticastRoute::IsPeerValid(const AgentRouteKey *key) const { return CheckPeerValidity(channel_, sequence_number_); } + +ControllerL2ReceiveRoute::ControllerL2ReceiveRoute(const std::string &vn_name, + uint32_t vxlan_id, + uint32_t mpls_label, + const PathPreference + &path_preference, + uint64_t sequence_number, + const AgentXmppChannel + *channel): + L2ReceiveRoute(vn_name, vxlan_id, mpls_label, path_preference), + sequence_number_(sequence_number), channel_(channel) { } + +bool ControllerL2ReceiveRoute::IsPeerValid(const AgentRouteKey *key) const { + return CheckPeerValidity(channel_, sequence_number_); +} diff --git a/src/vnsw/agent/controller/controller_route_path.h b/src/vnsw/agent/controller/controller_route_path.h index 6670ddb68be..f065b2b1e74 100644 --- a/src/vnsw/agent/controller/controller_route_path.h +++ b/src/vnsw/agent/controller/controller_route_path.h @@ -265,6 +265,22 @@ class ClonedLocalPath : public AgentRouteData { DISALLOW_COPY_AND_ASSIGN(ClonedLocalPath); }; +class ControllerL2ReceiveRoute : public L2ReceiveRoute { +public: + ControllerL2ReceiveRoute(const std::string &dest_vn_name, uint32_t vxlan_id, + uint32_t mpls_label, + const PathPreference &path_preference, + uint64_t sequence_number, + const AgentXmppChannel *channel); + virtual ~ControllerL2ReceiveRoute() { } + virtual bool IsPeerValid(const AgentRouteKey *key) const; + +private: + uint64_t sequence_number_; + const AgentXmppChannel *channel_; + DISALLOW_COPY_AND_ASSIGN(ControllerL2ReceiveRoute); +}; + class ControllerMulticastRoute : public MulticastRoute { public: ControllerMulticastRoute(const string &vn_name, @@ -284,5 +300,4 @@ class ControllerMulticastRoute : public MulticastRoute { const AgentXmppChannel *channel_; DISALLOW_COPY_AND_ASSIGN(ControllerMulticastRoute); }; - #endif //controller_route_path_hpp diff --git a/src/vnsw/agent/oper/agent_path.cc b/src/vnsw/agent/oper/agent_path.cc index 425a7cc6380..2c06f4edd65 100644 --- a/src/vnsw/agent/oper/agent_path.cc +++ b/src/vnsw/agent/oper/agent_path.cc @@ -526,11 +526,21 @@ bool L2ReceiveRoute::AddChangePath(Agent *agent, AgentPath *path, ret = true; } + if (path->peer() && path->peer()->GetType() == Peer::BGP_PEER) { + //Copy entire path preference for BGP peer path, + //since allowed-address pair config doesn't modify + //preference on BGP path + if (path->path_preference() != path_preference_) { + path->set_path_preference(path_preference_); + ret = true; + } + } + if (path->ChangeNH(agent, agent->nexthop_table()->l2_receive_nh()) == true) ret = true; return ret; -} +} bool InetInterfaceRoute::UpdateRoute(AgentRoute *rt) { bool ret = false; diff --git a/src/vnsw/agent/oper/evpn_route.cc b/src/vnsw/agent/oper/evpn_route.cc index 50b3d3961f0..0a33f627cf5 100644 --- a/src/vnsw/agent/oper/evpn_route.cc +++ b/src/vnsw/agent/oper/evpn_route.cc @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -147,6 +148,28 @@ void EvpnAgentRouteTable::AddOvsPeerMulticastRouteReq(const Peer *peer, AddOvsPeerMulticastRouteInternal(peer, vxlan_id, vn_name, tsn, tor_ip, true); } +void EvpnAgentRouteTable::AddControllerReceiveRouteReq(const Peer *peer, + const string &vrf_name, + uint32_t label, + const MacAddress &mac, + const IpAddress &ip_addr, + uint32_t ethernet_tag, + const string &vn_name, + const PathPreference &path_pref) { + const BgpPeer *bgp_peer = dynamic_cast(peer); + assert(bgp_peer != NULL); + + DBRequest req(DBRequest::DB_ENTRY_ADD_CHANGE); + req.key.reset(new EvpnRouteKey(peer, vrf_name, mac, ip_addr, + ethernet_tag)); + req.data.reset(new ControllerL2ReceiveRoute(vn_name, ethernet_tag, + label, path_pref, + bgp_peer->GetBgpXmppPeerConst()-> + unicast_sequence_number(), + bgp_peer->GetBgpXmppPeerConst())); + agent()->fabric_evpn_table()->Enqueue(&req); +} + void EvpnAgentRouteTable::AddReceiveRouteReq(const Peer *peer, const string &vrf_name, uint32_t label, diff --git a/src/vnsw/agent/oper/evpn_route.h b/src/vnsw/agent/oper/evpn_route.h index 8dfb34820a7..85538e989da 100644 --- a/src/vnsw/agent/oper/evpn_route.h +++ b/src/vnsw/agent/oper/evpn_route.h @@ -47,6 +47,12 @@ class EvpnAgentRouteTable : public AgentRouteTable { const IpAddress &ip_addr, uint32_t ethernet_tag, const std::string &vn_name, const PathPreference &pref); + void AddControllerReceiveRouteReq(const Peer *peer, + const std::string &vrf_name, + uint32_t label, const MacAddress &mac, + const IpAddress &ip_addr, uint32_t ethernet_tag, + const std::string &vn_name, + const PathPreference &pref); void AddLocalVmRouteReq(const Peer *peer, const std::string &vrf_name, const MacAddress &mac, diff --git a/src/vnsw/agent/test/test_route.cc b/src/vnsw/agent/test/test_route.cc index e50889d585e..d8dbd3d16a5 100644 --- a/src/vnsw/agent/test/test_route.cc +++ b/src/vnsw/agent/test/test_route.cc @@ -31,7 +31,7 @@ #include "test_cmn_util.h" #include "kstate/test/test_kstate_util.h" #include "vr_types.h" - +#include "net/bgp_af.h" #include using namespace boost::assign; @@ -2285,6 +2285,72 @@ TEST_F(RouteTest, EcmpTest_1) { client->WaitForIdle(); } +TEST_F(RouteTest, fip_evpn_route_local) { + struct PortInfo input[] = { + {"vnet1", 1, "1.1.1.10", "00:00:01:01:01:10", 1, 1}, + }; + + client->Reset(); + //Creation + CreateVmportFIpEnv(input, 1); + client->WaitForIdle(); + //Create floating IP pool + AddFloatingIpPool("fip-pool1", 1); + AddFloatingIp("fip1", 1, "2.2.2.10"); + AddLink("floating-ip", "fip1", "floating-ip-pool", "fip-pool1"); + AddLink("floating-ip-pool", "fip-pool1", "virtual-network", + "default-project:vn1"); + + //Associate vnet1 with floating IP + AddLink("virtual-machine-interface", "vnet1", "floating-ip", "fip1"); + client->WaitForIdle(); + + //Add a peer + BgpPeer *bgp_peer_ptr = CreateBgpPeer(Ip4Address(1), "BGP Peer1"); + boost::shared_ptr bgp_peer = + bgp_peer_ptr->GetBgpXmppPeer()->bgp_peer_id_ref(); + client->WaitForIdle(); + + //Search our evpn route + EvpnRouteEntry *rt = EvpnRouteGet("default-project:vn1:vn1", + MacAddress::FromString(input[0].mac), + Ip4Address::from_string("2.2.2.10"), 0); + EXPECT_TRUE(rt != NULL); + AgentPath *path = rt->FindLocalVmPortPath(); + EXPECT_TRUE(path != NULL); + EXPECT_TRUE(rt->GetActivePath() == path); + EXPECT_TRUE(rt->GetActiveNextHop()->GetType() == NextHop::L2_RECEIVE); + + //Reflect CN route and see if its added. + stringstream ss_node; + autogen::EnetItemType item; + SecurityGroupList sg; + + item.entry.nlri.af = BgpAf::L2Vpn; + item.entry.nlri.safi = BgpAf::Enet; + item.entry.nlri.address="2.2.2.10/32"; + item.entry.nlri.ethernet_tag = 0; + autogen::EnetNextHopType nh; + nh.af = Address::INET; + nh.address = agent_->router_ip_ptr()->to_string(); + nh.label = rt->GetActiveLabel(); + item.entry.next_hops.next_hop.push_back(nh); + item.entry.med = 0; + + + bgp_peer_ptr->GetBgpXmppPeer()->AddEvpnRoute("default-project:vn1:vn1", + "00:00:01:01:01:10", + &item); + client->WaitForIdle(); + EXPECT_TRUE(rt->GetActivePath() != path); + + client->WaitForIdle(); + DeleteVmportFIpEnv(input, 1, true); + client->WaitForIdle(); + DeleteBgpPeer(bgp_peer.get()); + client->WaitForIdle(); +} + int main(int argc, char *argv[]) { ::testing::InitGoogleTest(&argc, argv); GETUSERARGS();