From 3824962b7f802b06b3d3601d8d60a959588f5a0f Mon Sep 17 00:00:00 2001 From: Nischal Sheth Date: Tue, 28 Mar 2017 14:10:12 -0700 Subject: [PATCH] Add end to end support for L3 label in EVPN Type 2 routes This includes the following: - Add l3-label to xmpp_enet schema - Encode and decode l3-label in xmpp messages - Add l3-label to BgpPath and RibOutAttr Change-Id: I81261683fd7082e9fd041e6fbbbbcb4ceeaf1d58 Partial-Bug: 1636654 --- src/bgp/bgp_message_builder.cc | 2 +- src/bgp/bgp_path.cc | 22 +-- src/bgp/bgp_path.h | 14 +- src/bgp/bgp_peer.cc | 6 +- src/bgp/bgp_ribout.cc | 28 +-- src/bgp/bgp_ribout.h | 24 ++- src/bgp/bgp_table.cc | 16 +- src/bgp/bgp_table.h | 37 +++- src/bgp/bgp_xmpp_channel.cc | 22 ++- src/bgp/bgp_xmpp_rtarget_manager.cc | 2 +- src/bgp/evpn/evpn_table.cc | 6 +- src/bgp/peer_close_manager.cc | 4 +- src/bgp/test/bgp_msg_builder_test.cc | 2 +- src/bgp/test/bgp_update_test.cc | 4 +- src/bgp/test/bgp_xmpp_evpn_test.cc | 180 ++++++++++++++++++++ src/bgp/test/graceful_restart_test.cc | 8 +- src/bgp/xmpp_message_builder.cc | 1 + src/control-node/test/network_agent_mock.cc | 1 + src/control-node/test/network_agent_mock.h | 17 +- src/schema/xmpp_enet.xsd | 1 + 20 files changed, 320 insertions(+), 77 deletions(-) diff --git a/src/bgp/bgp_message_builder.cc b/src/bgp/bgp_message_builder.cc index dc59f0428ba..f8d92ad310f 100644 --- a/src/bgp/bgp_message_builder.cc +++ b/src/bgp/bgp_message_builder.cc @@ -130,7 +130,7 @@ bool BgpMessage::StartReach(const RibOut *ribout, const RibOutAttr *roattr, update.path_attributes.push_back(nlri); BgpProtoPrefix *prefix = new BgpProtoPrefix; - route->BuildProtoPrefix(prefix, attr, roattr->label()); + route->BuildProtoPrefix(prefix, attr, roattr->label(), roattr->l3_label()); nlri->nlri.push_back(prefix); int result = diff --git a/src/bgp/bgp_path.cc b/src/bgp/bgp_path.cc index a0218bb350c..79d081e5187 100644 --- a/src/bgp/bgp_path.cc +++ b/src/bgp/bgp_path.cc @@ -19,27 +19,28 @@ string BgpPath::PathIdString(uint32_t path_id) { } BgpPath::BgpPath(const IPeer *peer, uint32_t path_id, PathSource src, - const BgpAttrPtr ptr, uint32_t flags, uint32_t label) + const BgpAttrPtr ptr, uint32_t flags, uint32_t label, + uint32_t l3_label) : peer_(peer), path_id_(path_id), source_(src), attr_(ptr), - original_attr_(ptr), flags_(flags), label_(label) { + original_attr_(ptr), flags_(flags), label_(label), l3_label_(l3_label) { } BgpPath::BgpPath(const IPeer *peer, PathSource src, const BgpAttrPtr ptr, - uint32_t flags, uint32_t label) + uint32_t flags, uint32_t label, uint32_t l3_label) : peer_(peer), path_id_(0), source_(src), attr_(ptr), original_attr_(ptr), - flags_(flags), label_(label) { + flags_(flags), label_(label), l3_label_(l3_label) { } BgpPath::BgpPath(uint32_t path_id, PathSource src, const BgpAttrPtr ptr, - uint32_t flags, uint32_t label) + uint32_t flags, uint32_t label, uint32_t l3_label) : peer_(NULL), path_id_(path_id), source_(src), attr_(ptr), - original_attr_(ptr), flags_(flags), label_(label) { + original_attr_(ptr), flags_(flags), label_(label), l3_label_(l3_label) { } BgpPath::BgpPath(PathSource src, const BgpAttrPtr ptr, - uint32_t flags, uint32_t label) + uint32_t flags, uint32_t label, uint32_t l3_label) : peer_(NULL), path_id_(0), source_(src), attr_(ptr), original_attr_(ptr), - flags_(flags), label_(label) { + flags_(flags), label_(label), l3_label_(l3_label) { } // True is better @@ -267,8 +268,9 @@ string BgpPath::GetSourceString(bool combine_bgp_and_xmpp) const { } BgpSecondaryPath::BgpSecondaryPath(const IPeer *peer, uint32_t path_id, - PathSource src, const BgpAttrPtr ptr, uint32_t flags, uint32_t label) - : BgpPath(peer, path_id, src, ptr, flags, label) { + PathSource src, const BgpAttrPtr ptr, uint32_t flags, uint32_t label, + uint32_t l3_label) + : BgpPath(peer, path_id, src, ptr, flags, label, l3_label) { } RouteDistinguisher BgpSecondaryPath::GetPrimaryRouteDistinguisher() const { diff --git a/src/bgp/bgp_path.h b/src/bgp/bgp_path.h index 653be290730..df1fb0e0872 100644 --- a/src/bgp/bgp_path.h +++ b/src/bgp/bgp_path.h @@ -47,13 +47,14 @@ class BgpPath : public Path { static std::string PathIdString(uint32_t path_id); BgpPath(const IPeer *peer, uint32_t path_id, PathSource src, - const BgpAttrPtr ptr, uint32_t flags, uint32_t label); + const BgpAttrPtr ptr, uint32_t flags, uint32_t label, + uint32_t l3_label = 0); BgpPath(const IPeer *peer, PathSource src, const BgpAttrPtr attr, - uint32_t flags, uint32_t label); + uint32_t flags, uint32_t label, uint32_t l3_label = 0); BgpPath(uint32_t path_id, PathSource src, const BgpAttrPtr attr, - uint32_t flags = 0, uint32_t label = 0); + uint32_t flags = 0, uint32_t label = 0, uint32_t l3_label = 0); BgpPath(PathSource src, const BgpAttrPtr attr, - uint32_t flags = 0, uint32_t label = 0); + uint32_t flags = 0, uint32_t label = 0, uint32_t l3_label = 0); virtual ~BgpPath() { } @@ -81,6 +82,7 @@ class BgpPath : public Path { const BgpAttr *GetAttr() const { return attr_.get(); } const BgpAttr *GetOriginalAttr() const { return original_attr_.get(); } uint32_t GetLabel() const { return label_; } + uint32_t GetL3Label() const { return l3_label_; } virtual bool IsReplicated() const { return false; } bool IsFeasible() const { return ((flags_ & INFEASIBLE_MASK) == 0); } @@ -139,12 +141,14 @@ class BgpPath : public Path { BgpAttrPtr original_attr_; uint32_t flags_; uint32_t label_; + uint32_t l3_label_; }; class BgpSecondaryPath : public BgpPath { public: BgpSecondaryPath(const IPeer *peer, uint32_t path_id, PathSource src, - const BgpAttrPtr attr, uint32_t flags, uint32_t label); + const BgpAttrPtr attr, uint32_t flags, uint32_t label, + uint32_t l3_label = 0); virtual bool IsReplicated() const { return true; diff --git a/src/bgp/bgp_peer.cc b/src/bgp/bgp_peer.cc index 42adf8e4300..4eba5328593 100644 --- a/src/bgp/bgp_peer.cc +++ b/src/bgp/bgp_peer.cc @@ -1601,8 +1601,8 @@ void BgpPeer::ProcessNlri(Address::Family family, DBRequest::DBOperation oper, DBRequest req; req.oper = oper; if (oper == DBRequest::DB_ENTRY_ADD_CHANGE) { - req.data.reset( - new typename TableT::RequestData(new_attr, flags, label)); + req.data.reset(new typename TableT::RequestData( + new_attr, flags, label, l3_label, 0)); } req.key.reset(new typename TableT::RequestKey(prefix, this)); table->Enqueue(&req); @@ -1686,7 +1686,7 @@ void BgpPeer::ProcessUpdate(const BgpProto::Update *msg, size_t msgsize) { DBRequest req; req.oper = DBRequest::DB_ENTRY_ADD_CHANGE; - req.data.reset(new InetTable::RequestData(attr, flags, 0)); + req.data.reset(new InetTable::RequestData(attr, flags, 0, 0, 0)); req.key.reset(new InetTable::RequestKey(prefix, this)); table->Enqueue(&req); } diff --git a/src/bgp/bgp_ribout.cc b/src/bgp/bgp_ribout.cc index 41bbc3e07b8..b9ea80d079e 100644 --- a/src/bgp/bgp_ribout.cc +++ b/src/bgp/bgp_ribout.cc @@ -27,10 +27,11 @@ using std::find; RibOutAttr::NextHop::NextHop(const BgpTable *table, IpAddress address, - uint32_t label, const ExtCommunity *ext_community, - bool vrf_originated) + uint32_t label, uint32_t l3_label, const ExtCommunity *ext_community, + bool vrf_originated) : address_(address), label_(label), + l3_label_(l3_label), origin_vn_index_(-1) { if (ext_community) { encap_ = ext_community->GetTunnelEncap(); @@ -47,6 +48,8 @@ int RibOutAttr::NextHop::CompareTo(const NextHop &rhs) const { if (address_ > rhs.address_) return 1; if (label_ < rhs.label_) return -1; if (label_ > rhs.label_) return 1; + if (l3_label_ < rhs.l3_label_) return -1; + if (l3_label_ > rhs.l3_label_) return 1; if (origin_vn_index_ < rhs.origin_vn_index_) return -1; if (origin_vn_index_ > rhs.origin_vn_index_) return 1; if (encap_.size() < rhs.encap_.size()) return -1; @@ -78,12 +81,12 @@ RibOutAttr::RibOutAttr(const RibOutAttr &rhs) { } RibOutAttr::RibOutAttr(const BgpTable *table, const BgpAttr *attr, - uint32_t label) + uint32_t label, uint32_t l3_label) : attr_out_(attr), is_xmpp_(false), vrf_originated_(false) { if (attr) { - nexthop_list_.push_back(NextHop(table, attr->nexthop(), label, + nexthop_list_.push_back(NextHop(table, attr->nexthop(), label, l3_label, attr->ext_community(), false)); } } @@ -94,7 +97,7 @@ RibOutAttr::RibOutAttr(const BgpTable *table, const BgpRoute *route, is_xmpp_(is_xmpp), vrf_originated_(route->BestPath()->IsVrfOriginated()) { if (attr && include_nh) { - nexthop_list_.push_back(NextHop(table, attr->nexthop(), label, + nexthop_list_.push_back(NextHop(table, attr->nexthop(), label, 0, attr->ext_community(), vrf_originated_)); } } @@ -108,14 +111,15 @@ RibOutAttr::RibOutAttr(const BgpRoute *route, const BgpAttr *attr, // Always encode best path's attributes (including it's nexthop) and label. if (!is_xmpp) { - set_attr(table, attr, route->BestPath()->GetLabel(), false); + set_attr(table, attr, route->BestPath()->GetLabel(), + route->BestPath()->GetL3Label(), false); return; } // Encode ECMP NextHops only for XMPP peers. // Vrf Origination matters only for XMPP peers. set_attr(table, attr, route->BestPath()->GetLabel(), - route->BestPath()->IsVrfOriginated()); + route->BestPath()->GetL3Label(), route->BestPath()->IsVrfOriginated()); for (Route::PathList::const_iterator it = route->GetPathList().begin(); it != route->GetPathList().end(); ++it) { @@ -135,8 +139,8 @@ RibOutAttr::RibOutAttr(const BgpRoute *route, const BgpAttr *attr, // determine if VRF's VN name can be used as the origin VN for the // nexthop. NextHop nexthop(table, path->GetAttr()->nexthop(), path->GetLabel(), - path->GetAttr()->ext_community(), - path->IsVrfOriginated()); + path->GetL3Label(), path->GetAttr()->ext_community(), + path->IsVrfOriginated()); // Skip if we have already encoded this next-hop if (find(nexthop_list_.begin(), nexthop_list_.end(), nexthop) != @@ -186,12 +190,12 @@ int RibOutAttr::CompareTo(const RibOutAttr &rhs) const { } void RibOutAttr::set_attr(const BgpTable *table, const BgpAttrPtr &attrp, - uint32_t label, bool vrf_originated) { + uint32_t label, uint32_t l3_label, bool vrf_originated) { if (!attr_out_) { attr_out_ = attrp; assert(nexthop_list_.empty()); - NextHop nexthop(table, attrp->nexthop(), label, attrp->ext_community(), - vrf_originated); + NextHop nexthop(table, attrp->nexthop(), label, l3_label, + attrp->ext_community(), vrf_originated); nexthop_list_.push_back(nexthop); return; } diff --git a/src/bgp/bgp_ribout.h b/src/bgp/bgp_ribout.h index 5ef86cb5ae4..bf8023c1a2c 100644 --- a/src/bgp/bgp_ribout.h +++ b/src/bgp/bgp_ribout.h @@ -49,10 +49,12 @@ class RibOutAttr { class NextHop { public: NextHop(const BgpTable *table, IpAddress address, uint32_t label, - const ExtCommunity *ext_community, bool vrf_originated); + uint32_t l3_label, const ExtCommunity *ext_community, + bool vrf_originated); const IpAddress address() const { return address_; } uint32_t label() const { return label_; } + uint32_t l3_label() const { return l3_label_; } int origin_vn_index() const { return origin_vn_index_; } std::vector encap() const { return encap_; } @@ -62,7 +64,8 @@ class RibOutAttr { private: IpAddress address_; - uint32_t label_; + uint32_t label_; + uint32_t l3_label_; int origin_vn_index_; std::vector encap_; }; @@ -71,11 +74,12 @@ class RibOutAttr { RibOutAttr(const RibOutAttr &rhs); RibOutAttr() : attr_out_(NULL), is_xmpp_(false), vrf_originated_(false) { } - RibOutAttr(const BgpTable *table, const BgpAttr *attr, uint32_t label); + RibOutAttr(const BgpRoute *route, const BgpAttr *attr, bool is_xmpp); + RibOutAttr(const BgpTable *table, const BgpAttr *attr, uint32_t label, + uint32_t l3_label = 0); RibOutAttr(const BgpTable *table, const BgpRoute *route, const BgpAttr *attr, uint32_t label, bool include_nh = true, bool is_xmpp = false); - RibOutAttr(const BgpRoute *route, const BgpAttr *attr, bool is_xmpp); RibOutAttr &operator=(const RibOutAttr &rhs); bool operator==(const RibOutAttr &rhs) const { return CompareTo(rhs) == 0; } @@ -84,8 +88,15 @@ class RibOutAttr { const NextHopList &nexthop_list() const { return nexthop_list_; } const BgpAttr *attr() const { return attr_out_.get(); } + void set_attr(const BgpTable *table, const BgpAttrPtr &attrp) { + set_attr(table, attrp, 0, 0, false); + } void set_attr(const BgpTable *table, const BgpAttrPtr &attrp, - uint32_t label = 0, bool vrf_originated = false); + uint32_t label) { + set_attr(table, attrp, label, 0, false); + } + void set_attr(const BgpTable *table, const BgpAttrPtr &attrp, + uint32_t label, uint32_t l3_label, bool vrf_originated); void clear() { attr_out_.reset(); @@ -94,6 +105,9 @@ class RibOutAttr { uint32_t label() const { return nexthop_list_.empty() ? 0 : nexthop_list_.at(0).label(); } + uint32_t l3_label() const { + return nexthop_list_.empty() ? 0 : nexthop_list_.at(0).l3_label(); + } bool is_xmpp() const { return is_xmpp_; } bool vrf_originated() const { return vrf_originated_; } const std::string &repr() const { return repr_; } diff --git a/src/bgp/bgp_table.cc b/src/bgp/bgp_table.cc index 61c79146a5a..372f639c0eb 100644 --- a/src/bgp/bgp_table.cc +++ b/src/bgp/bgp_table.cc @@ -398,13 +398,14 @@ bool BgpTable::PathSelection(const Path &path1, const Path &path2) { bool BgpTable::DeletePath(DBTablePartBase *root, BgpRoute *rt, BgpPath *path) { return InputCommon(root, rt, path, path->GetPeer(), NULL, - DBRequest::DB_ENTRY_DELETE, NULL, path->GetPathId(), 0, 0); + DBRequest::DB_ENTRY_DELETE, NULL, path->GetPathId(), 0, 0, 0); } bool BgpTable::InputCommon(DBTablePartBase *root, BgpRoute *rt, BgpPath *path, const IPeer *peer, DBRequest *req, DBRequest::DBOperation oper, BgpAttrPtr attrs, - uint32_t path_id, uint32_t flags, uint32_t label) { + uint32_t path_id, uint32_t flags, uint32_t label, + uint32_t l3_label) { bool notify_rt = false; switch (oper) { @@ -420,7 +421,8 @@ bool BgpTable::InputCommon(DBTablePartBase *root, BgpRoute *rt, BgpPath *path, if (path != NULL) { if ((path->GetAttr() != attrs.get()) || (path->GetFlags() != flags) || - (path->GetLabel() != label)) { + (path->GetLabel() != label) || + (path->GetL3Label() != l3_label)) { // Update Attributes and notify (if needed) if (path->NeedsResolution()) path_resolver_->StopPathResolution(root->index(), path); @@ -432,8 +434,8 @@ bool BgpTable::InputCommon(DBTablePartBase *root, BgpRoute *rt, BgpPath *path, } BgpPath *new_path; - new_path = - new BgpPath(peer, path_id, BgpPath::BGP_XMPP, attrs, flags, label); + new_path = new BgpPath( + peer, path_id, BgpPath::BGP_XMPP, attrs, flags, label, l3_label); if (new_path->NeedsResolution()) { Address::Family family = new_path->GetAttr()->nexthop_family(); @@ -581,7 +583,7 @@ void BgpTable::Input(DBTablePartition *root, DBClient *client, notify_rt |= InputCommon(root, rt, path, peer, req, req->oper, attr, path_id, nexthop.flags_, - nexthop.label_); + nexthop.label_, nexthop.l3_label_); } } @@ -591,7 +593,7 @@ void BgpTable::Input(DBTablePartition *root, DBClient *client, BgpPath *path = it->first; notify_rt |= InputCommon(root, rt, path, peer, req, DBRequest::DB_ENTRY_DELETE, NULL, - path->GetPathId(), 0, 0); + path->GetPathId(), 0, 0, 0); } InputCommonPostProcess(root, rt, notify_rt); diff --git a/src/bgp/bgp_table.h b/src/bgp/bgp_table.h index 9a462ad6577..9f9565cab7e 100644 --- a/src/bgp/bgp_table.h +++ b/src/bgp/bgp_table.h @@ -41,12 +41,24 @@ class BgpTable : public RouteTable { struct RequestData : DBRequestData { struct NextHop { - NextHop() : flags_(0), address_(Ip4Address(0)), label_(0) { } - NextHop(uint32_t flags, IpAddress address, uint32_t label) : - flags_(flags), address_(address), label_(label) { } + NextHop() + : flags_(0), + address_(Ip4Address(0)), + label_(0), + l3_label_(0) { + } + NextHop(uint32_t flags, IpAddress address, uint32_t label, + uint32_t l3_label = 0) + : flags_(flags), + address_(address), + label_(label), + l3_label_(l3_label) { + } + uint32_t flags_; IpAddress address_; uint32_t label_; + uint32_t l3_label_; RouteDistinguisher source_rd_; ExtCommunity::ExtCommunityList tunnel_encapsulations_; }; @@ -54,11 +66,19 @@ class BgpTable : public RouteTable { typedef std::vector NextHops; RequestData(const BgpAttrPtr &attrs, uint32_t flags, uint32_t label, - uint64_t subscription_gen_id = 0) + uint32_t l3_label, uint64_t subscription_gen_id) : attrs_(attrs), subscription_gen_id_(subscription_gen_id) { - nexthops_.push_back(NextHop(flags, - attrs ? attrs->nexthop() : Ip4Address(0), - label)); + nexthops_.push_back( + NextHop(flags, attrs ? attrs->nexthop() : Ip4Address(0), + label, l3_label)); + } + + RequestData(const BgpAttrPtr &attrs, uint32_t flags, uint32_t label, + uint32_t l3_label = 0) + : attrs_(attrs), subscription_gen_id_(0) { + nexthops_.push_back( + NextHop(flags, attrs ? attrs->nexthop() : Ip4Address(0), + label, l3_label)); } RequestData(const BgpAttrPtr &attrs, NextHops nexthops, @@ -155,7 +175,8 @@ class BgpTable : public RouteTable { bool InputCommon(DBTablePartBase *root, BgpRoute *rt, BgpPath *path, const IPeer *peer, DBRequest *req, DBRequest::DBOperation oper, BgpAttrPtr attrs, - uint32_t path_id, uint32_t flags, uint32_t label); + uint32_t path_id, uint32_t flags, uint32_t label, + uint32_t l3_label); void InputCommonPostProcess(DBTablePartBase *root, BgpRoute *rt, bool notify_rt); diff --git a/src/bgp/bgp_xmpp_channel.cc b/src/bgp/bgp_xmpp_channel.cc index 4683e3e7642..62360b75cdd 100644 --- a/src/bgp/bgp_xmpp_channel.cc +++ b/src/bgp/bgp_xmpp_channel.cc @@ -916,8 +916,8 @@ bool BgpXmppChannel::ProcessMcastItem(string vrf_name, attrs.push_back(&ext); BgpAttrPtr attr = bgp_server_->attr_db()->Locate(attrs); - req.data.reset(new ErmVpnTable::RequestData(attr, flags, - 0, subscription_gen_id)); + req.data.reset(new ErmVpnTable::RequestData( + attr, flags, 0, 0, subscription_gen_id)); stats_[RX].reach++; } else { req.oper = DBRequest::DB_ENTRY_DELETE; @@ -1194,8 +1194,8 @@ bool BgpXmppChannel::ProcessItem(string vrf_name, attrs.push_back(&ext); BgpAttrPtr attr = bgp_server_->attr_db()->Locate(attrs); - req.data.reset(new BgpTable::RequestData(attr, nexthops, - subscription_gen_id)); + req.data.reset( + new BgpTable::RequestData(attr, nexthops, subscription_gen_id)); } else { req.oper = DBRequest::DB_ENTRY_DELETE; } @@ -1493,8 +1493,8 @@ bool BgpXmppChannel::ProcessInet6Item(string vrf_name, attrs.push_back(&ext); BgpAttrPtr attr = bgp_server_->attr_db()->Locate(attrs); - req.data.reset(new BgpTable::RequestData(attr, nexthops, - subscription_gen_id)); + req.data.reset( + new BgpTable::RequestData(attr, nexthops, subscription_gen_id)); } else { req.oper = DBRequest::DB_ENTRY_DELETE; } @@ -1630,6 +1630,7 @@ bool BgpXmppChannel::ProcessEnetItem(string vrf_name, IpAddress nh_address(Ip4Address(0)); uint32_t label = 0; + uint32_t l3_label = 0; uint32_t flags = 0; bool label_is_vni = false; @@ -1660,6 +1661,7 @@ bool BgpXmppChannel::ProcessEnetItem(string vrf_name, if (first_nh) { nh_address = nhop_address; label = nit->label; + l3_label = nit->l3_label; } // Process tunnel encapsulation list. @@ -1702,6 +1704,7 @@ bool BgpXmppChannel::ProcessEnetItem(string vrf_name, nexthop.flags_ = flags; nexthop.address_ = nhop_address; nexthop.label_ = nit->label; + nexthop.l3_label_ = nit->l3_label; nexthop.source_rd_ = RouteDistinguisher( nhop_address.to_v4().to_ulong(), instance_id); nexthops.push_back(nexthop); @@ -1787,8 +1790,8 @@ bool BgpXmppChannel::ProcessEnetItem(string vrf_name, BgpAttrPtr attr = bgp_server_->attr_db()->Locate(attrs); - req.data.reset(new EvpnTable::RequestData(attr, nexthops, - subscription_gen_id)); + req.data.reset( + new EvpnTable::RequestData(attr, nexthops, subscription_gen_id)); stats_[RX].reach++; } else { req.oper = DBRequest::DB_ENTRY_DELETE; @@ -1810,7 +1813,8 @@ bool BgpXmppChannel::ProcessEnetItem(string vrf_name, BGP_LOG_PEER_INSTANCE(Peer(), vrf_name, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_TRACE, "Enet route " << evpn_prefix.ToXmppIdString() << - " with next-hop " << nh_address << " and label " << label << + " with next-hop " << nh_address << + " label " << label << " l3-label " << l3_label << " enqueued for " << (add_change ? "add/change" : "delete")); table->Enqueue(&req); return true; diff --git a/src/bgp/bgp_xmpp_rtarget_manager.cc b/src/bgp/bgp_xmpp_rtarget_manager.cc index b3b7c8e1148..2b8650cc24b 100644 --- a/src/bgp/bgp_xmpp_rtarget_manager.cc +++ b/src/bgp/bgp_xmpp_rtarget_manager.cc @@ -112,7 +112,7 @@ void BgpXmppRTargetManager::RTargetRouteOp(as4_t asn, // Find correct rtarget route flags if not already known. if (!flags) flags = GetRTargetRouteFlag(rtarget); - req.data.reset(new RTargetTable::RequestData(attr, flags , 0)); + req.data.reset(new RTargetTable::RequestData(attr, flags, 0, 0, 0)); req.oper = DBRequest::DB_ENTRY_ADD_CHANGE; } else { req.oper = DBRequest::DB_ENTRY_DELETE; diff --git a/src/bgp/evpn/evpn_table.cc b/src/bgp/evpn/evpn_table.cc index 648aa85cd0e..5362e89e231 100644 --- a/src/bgp/evpn/evpn_table.cc +++ b/src/bgp/evpn/evpn_table.cc @@ -190,7 +190,8 @@ BgpRoute *EvpnTable::RouteReplicate(BgpServer *server, if (dest_path != NULL) { if ((new_attr != dest_path->GetOriginalAttr()) || (src_path->GetFlags() != dest_path->GetFlags()) || - (src_path->GetLabel() != dest_path->GetLabel())) { + (src_path->GetLabel() != dest_path->GetLabel()) || + (src_path->GetL3Label() != dest_path->GetL3Label())) { bool success = dest_route->RemoveSecondaryPath(src_rt, src_path->GetSource(), src_path->GetPeer(), src_path->GetPathId()); @@ -204,7 +205,8 @@ BgpRoute *EvpnTable::RouteReplicate(BgpServer *server, BgpSecondaryPath *replicated_path = new BgpSecondaryPath(src_path->GetPeer(), src_path->GetPathId(), src_path->GetSource(), new_attr, - src_path->GetFlags(), src_path->GetLabel()); + src_path->GetFlags(), src_path->GetLabel(), + src_path->GetL3Label()); replicated_path->SetReplicateInfo(src_table, src_rt); dest_route->InsertPath(replicated_path); diff --git a/src/bgp/peer_close_manager.cc b/src/bgp/peer_close_manager.cc index fd012e08b9f..91b1e3e84da 100644 --- a/src/bgp/peer_close_manager.cc +++ b/src/bgp/peer_close_manager.cc @@ -739,8 +739,8 @@ bool PeerCloseManager::MembershipPathCallback(DBTablePartBase *root, // Feed the route modify/delete request to the table input process. return table->InputCommon(root, rt, path, peer_close_->peer(), NULL, oper, - attrs, path->GetPathId(), - path->GetFlags() | stale, path->GetLabel()); + attrs, path->GetPathId(), path->GetFlags() | stale, path->GetLabel(), + path->GetL3Label()); } // diff --git a/src/bgp/test/bgp_msg_builder_test.cc b/src/bgp/test/bgp_msg_builder_test.cc index 5054b39d351..31122498a37 100644 --- a/src/bgp/test/bgp_msg_builder_test.cc +++ b/src/bgp/test/bgp_msg_builder_test.cc @@ -96,7 +96,7 @@ TEST_F(BgpMsgBuilderTest, Build) { attr.push_back(ext_community); RibOutAttr rib_out_attr; - rib_out_attr.set_attr(NULL, server_.attr_db()->Locate(attr)); + rib_out_attr.set_attr(NULL, server_.attr_db()->Locate(attr), 0, 0, false); InetVpnPrefix p1 = InetVpnPrefix::FromString("12345:2:1.1.1.1/24"); InetVpnRoute route(p1); diff --git a/src/bgp/test/bgp_update_test.cc b/src/bgp/test/bgp_update_test.cc index 4d689b51f4a..bc1b3e71c4a 100644 --- a/src/bgp/test/bgp_update_test.cc +++ b/src/bgp/test/bgp_update_test.cc @@ -128,8 +128,8 @@ static RouteUpdate *BuildUpdate(BgpRoute *route, const RibOut *ribout, RouteUpdate *update = new RouteUpdate(route, RibOutUpdates::QUPDATE); UpdateInfoSList ulist; UpdateInfo *info = new UpdateInfo(); - info->roattr.set_attr(static_cast(route->get_table()), - attrp); + info->roattr.set_attr( + static_cast(route->get_table()), attrp, 0, 0, false); info->target = ribout->PeerSet(); ulist->push_front(*info); update->SetUpdateInfo(ulist); diff --git a/src/bgp/test/bgp_xmpp_evpn_test.cc b/src/bgp/test/bgp_xmpp_evpn_test.cc index da31afaaecb..ac349effe13 100644 --- a/src/bgp/test/bgp_xmpp_evpn_test.cc +++ b/src/bgp/test/bgp_xmpp_evpn_test.cc @@ -1414,6 +1414,20 @@ class BgpXmppEvpnTest2 : public ::testing::Test { return true; } + bool CheckRouteLabels(test::NetworkAgentMockPtr agent, + const string &network, const string &prefix, int label, int l3_label) { + task_util::TaskSchedulerLock lock; + const autogen::EnetItemType *rt = + agent->EnetRouteLookup(network, prefix); + if (!rt) + return false; + if (label && rt->entry.next_hops.next_hop[0].label != label) + return false; + if (l3_label && rt->entry.next_hops.next_hop[0].l3_label != l3_label) + return false; + return true; + } + bool CheckRouteSecurityGroup(test::NetworkAgentMockPtr agent, const string &network, const string &prefix, vector &sg) { task_util::TaskSchedulerLock lock; @@ -1450,6 +1464,12 @@ class BgpXmppEvpnTest2 : public ::testing::Test { TASK_UTIL_EXPECT_TRUE(CheckRouteExists(agent, network, prefix)); } + void VerifyRouteLabels(test::NetworkAgentMockPtr agent, + const string &network, const string &prefix, int label, int l3_label) { + TASK_UTIL_EXPECT_TRUE( + CheckRouteLabels(agent, network, prefix, label, l3_label)); + } + void VerifyRouteSecurityGroup(test::NetworkAgentMockPtr agent, const string &network, const string &prefix, vector &sg) { TASK_UTIL_EXPECT_TRUE( @@ -2011,6 +2031,166 @@ TEST_F(BgpXmppEvpnTest2, RouteUpdate) { agent_b_->SessionDown(); } +// +// Routes from 2 agents are advertised with L3 label. +// +TEST_F(BgpXmppEvpnTest2, RouteAddL3Label) { + Configure(); + task_util::WaitForIdle(); + + // Create XMPP Agent A connected to XMPP server X. + agent_a_.reset( + new test::NetworkAgentMock(&evm_, "agent-a", xs_x_->GetPort(), + "127.0.0.1", "127.0.0.1")); + TASK_UTIL_EXPECT_TRUE(agent_a_->IsEstablished()); + + // Create XMPP Agent B connected to XMPP server Y. + agent_b_.reset( + new test::NetworkAgentMock(&evm_, "agent-b", xs_y_->GetPort(), + "127.0.0.2", "127.0.0.2")); + TASK_UTIL_EXPECT_TRUE(agent_b_->IsEstablished()); + + // Register to blue instance + agent_a_->EnetSubscribe("blue", 1); + agent_b_->EnetSubscribe("blue", 1); + task_util::WaitForIdle(); + + // Add route from agent A with label 101 and l3-label 200. + stringstream eroute_a; + eroute_a << "aa:00:00:00:00:01,10.1.1.1/32"; + test::NextHop nh_a("192.168.1.1", 101, 200); + agent_a_->AddEnetRoute("blue", eroute_a.str(), nh_a); + task_util::WaitForIdle(); + + // Add route from agent B with label 102 and l3-label 200.. + stringstream eroute_b; + eroute_b << "bb:00:00:00:00:01,10.1.2.1/32"; + test::NextHop nh_b("192.168.2.1", 102, 200); + agent_b_->AddEnetRoute("blue", eroute_b.str(), nh_b); + task_util::WaitForIdle(); + + // Verify that routes showed up on the agents. + TASK_UTIL_EXPECT_EQ(2, agent_a_->EnetRouteCount()); + TASK_UTIL_EXPECT_EQ(2, agent_a_->EnetRouteCount("blue")); + TASK_UTIL_EXPECT_EQ(2, agent_b_->EnetRouteCount()); + TASK_UTIL_EXPECT_EQ(2, agent_b_->EnetRouteCount("blue")); + + // Verify label and l3-label values. + VerifyRouteLabels(agent_a_, "blue", eroute_a.str(), 101, 200); + VerifyRouteLabels(agent_a_, "blue", eroute_b.str(), 102, 200); + VerifyRouteLabels(agent_b_, "blue", eroute_a.str(), 101, 200); + VerifyRouteLabels(agent_b_, "blue", eroute_b.str(), 102, 200); + + // Delete route from agent A. + agent_a_->DeleteEnetRoute("blue", eroute_a.str()); + task_util::WaitForIdle(); + + // Delete route from agent B. + agent_b_->DeleteEnetRoute("blue", eroute_b.str()); + task_util::WaitForIdle(); + + // Verify that there are no routes on the agents. + TASK_UTIL_EXPECT_EQ(0, agent_a_->EnetRouteCount()); + TASK_UTIL_EXPECT_EQ(0, agent_a_->EnetRouteCount("blue")); + TASK_UTIL_EXPECT_EQ(0, agent_b_->EnetRouteCount()); + TASK_UTIL_EXPECT_EQ(0, agent_b_->EnetRouteCount("blue")); + + // Close the sessions. + agent_a_->SessionDown(); + agent_b_->SessionDown(); +} + +// +// Routes from 2 agents are updated when L3 label is updated. +// +TEST_F(BgpXmppEvpnTest2, RouteUpdateL3Label) { + Configure(); + task_util::WaitForIdle(); + + // Create XMPP Agent A connected to XMPP server X. + agent_a_.reset( + new test::NetworkAgentMock(&evm_, "agent-a", xs_x_->GetPort(), + "127.0.0.1", "127.0.0.1")); + TASK_UTIL_EXPECT_TRUE(agent_a_->IsEstablished()); + + // Create XMPP Agent B connected to XMPP server Y. + agent_b_.reset( + new test::NetworkAgentMock(&evm_, "agent-b", xs_y_->GetPort(), + "127.0.0.2", "127.0.0.2")); + TASK_UTIL_EXPECT_TRUE(agent_b_->IsEstablished()); + + // Register to blue instance + agent_a_->EnetSubscribe("blue", 1); + agent_b_->EnetSubscribe("blue", 1); + task_util::WaitForIdle(); + + // Add route from agent A with label 101 and l3-label 200. + stringstream eroute_a; + eroute_a << "aa:00:00:00:00:01,10.1.1.1/32"; + test::NextHop nh_a("192.168.1.1", 101, 200); + agent_a_->AddEnetRoute("blue", eroute_a.str(), nh_a); + task_util::WaitForIdle(); + + // Add route from agent B with label 102 and l3-label 200.. + stringstream eroute_b; + eroute_b << "bb:00:00:00:00:01,10.1.2.1/32"; + test::NextHop nh_b("192.168.2.1", 102, 200); + agent_b_->AddEnetRoute("blue", eroute_b.str(), nh_b); + task_util::WaitForIdle(); + + // Verify that routes showed up on the agents. + TASK_UTIL_EXPECT_EQ(2, agent_a_->EnetRouteCount()); + TASK_UTIL_EXPECT_EQ(2, agent_a_->EnetRouteCount("blue")); + TASK_UTIL_EXPECT_EQ(2, agent_b_->EnetRouteCount()); + TASK_UTIL_EXPECT_EQ(2, agent_b_->EnetRouteCount("blue")); + + // Verify label and l3-label values. + VerifyRouteLabels(agent_a_, "blue", eroute_a.str(), 101, 200); + VerifyRouteLabels(agent_a_, "blue", eroute_b.str(), 102, 200); + VerifyRouteLabels(agent_b_, "blue", eroute_a.str(), 101, 200); + VerifyRouteLabels(agent_b_, "blue", eroute_b.str(), 102, 200); + + // Update l3-label of route from agent A to 300. + nh_a = test::NextHop("192.168.1.1", 101, 300); + agent_a_->AddEnetRoute("blue", eroute_a.str(), nh_a); + task_util::WaitForIdle(); + + // Update l3-label of route from agent B to 300. + nh_b = test::NextHop("192.168.2.1", 102, 300); + agent_b_->AddEnetRoute("blue", eroute_b.str(), nh_b); + task_util::WaitForIdle(); + + // Verify that routes showed up on the agents. + TASK_UTIL_EXPECT_EQ(2, agent_a_->EnetRouteCount()); + TASK_UTIL_EXPECT_EQ(2, agent_a_->EnetRouteCount("blue")); + TASK_UTIL_EXPECT_EQ(2, agent_b_->EnetRouteCount()); + TASK_UTIL_EXPECT_EQ(2, agent_b_->EnetRouteCount("blue")); + + // Verify label and l3-label values. + VerifyRouteLabels(agent_a_, "blue", eroute_a.str(), 101, 300); + VerifyRouteLabels(agent_a_, "blue", eroute_b.str(), 102, 300); + VerifyRouteLabels(agent_b_, "blue", eroute_a.str(), 101, 300); + VerifyRouteLabels(agent_b_, "blue", eroute_b.str(), 102, 300); + + // Delete route from agent A. + agent_a_->DeleteEnetRoute("blue", eroute_a.str()); + task_util::WaitForIdle(); + + // Delete route from agent B. + agent_b_->DeleteEnetRoute("blue", eroute_b.str()); + task_util::WaitForIdle(); + + // Verify that there are no routes on the agents. + TASK_UTIL_EXPECT_EQ(0, agent_a_->EnetRouteCount()); + TASK_UTIL_EXPECT_EQ(0, agent_a_->EnetRouteCount("blue")); + TASK_UTIL_EXPECT_EQ(0, agent_b_->EnetRouteCount()); + TASK_UTIL_EXPECT_EQ(0, agent_b_->EnetRouteCount("blue")); + + // Close the sessions. + agent_a_->SessionDown(); + agent_b_->SessionDown(); +} + // // Add/Delete routes from 2 agents with only MAC. // Address field is null. diff --git a/src/bgp/test/graceful_restart_test.cc b/src/bgp/test/graceful_restart_test.cc index a7382a8e376..d19d6a5ffe1 100644 --- a/src/bgp/test/graceful_restart_test.cc +++ b/src/bgp/test/graceful_restart_test.cc @@ -947,8 +947,8 @@ void GracefulRestartTest::ProcessInetVpnRoute(BgpPeerTest *peer, int instance, attr_spec.push_back(commspec.get()); BgpAttrPtr attr = peer->server()->attr_db()->Locate(attr_spec); - req.data.reset(new InetTable::RequestData(attr, 0, - 1000*instance + rt)); + req.data.reset( + new InetTable::RequestData(attr, 0, 1000 * instance + rt)); table->Enqueue(&req); } WaitForIdle(); @@ -1000,8 +1000,8 @@ void GracefulRestartTest::ProcessInet6VpnRoute(BgpPeerTest *peer, int instance, attr_spec.push_back(commspec.get()); BgpAttrPtr attr = peer->server()->attr_db()->Locate(attr_spec); - req.data.reset(new Inet6Table::RequestData(attr, 0, - 1000*instance + rt)); + req.data.reset( + new Inet6Table::RequestData(attr, 0, 1000 * instance + rt)); table->Enqueue(&req); } WaitForIdle(); diff --git a/src/bgp/xmpp_message_builder.cc b/src/bgp/xmpp_message_builder.cc index 9ceaef6c4c0..690a44180a6 100644 --- a/src/bgp/xmpp_message_builder.cc +++ b/src/bgp/xmpp_message_builder.cc @@ -279,6 +279,7 @@ void BgpXmppMessage::EncodeEnetNextHop(const BgpRoute *route, item_nexthop.af = BgpAf::IPv4; item_nexthop.address = nexthop.address().to_v4().to_string(); item_nexthop.label = nexthop.label(); + item_nexthop.l3_label = nexthop.l3_label(); // If encap list is empty use mpls over gre as default encap. vector &encap_list = diff --git a/src/control-node/test/network_agent_mock.cc b/src/control-node/test/network_agent_mock.cc index 114aa2f71f1..dbcadbae15a 100644 --- a/src/control-node/test/network_agent_mock.cc +++ b/src/control-node/test/network_agent_mock.cc @@ -660,6 +660,7 @@ pugi::xml_document *XmppDocumentMock::RouteEnetAddDeleteXmlDoc( item_nexthop.address = nexthop.address_; item_nexthop.label = nexthop.label_ ? nexthop.label_ : label_alloc_++; + item_nexthop.l3_label = nexthop.l3_label_; item_nexthop.tunnel_encapsulation_list.tunnel_encapsulation = nexthop.tunnel_encapsulations_; rt_entry.entry.next_hops.next_hop.push_back(item_nexthop); diff --git a/src/control-node/test/network_agent_mock.h b/src/control-node/test/network_agent_mock.h index 7b4d39bd42a..a02f86035a0 100644 --- a/src/control-node/test/network_agent_mock.h +++ b/src/control-node/test/network_agent_mock.h @@ -183,18 +183,18 @@ struct RouteAttributes { }; struct NextHop { - NextHop() : no_label_(false), label_(0) { } + NextHop() : no_label_(false), label_(0), l3_label_(0) { } NextHop(std::string address) : - address_(address), no_label_(false), label_(0) { + address_(address), no_label_(false), label_(0), l3_label_(0) { tunnel_encapsulations_.push_back("gre"); } NextHop(bool no_label, std::string address) : - address_(address), no_label_(no_label), label_(0) { + address_(address), no_label_(no_label), label_(0), l3_label_(0) { } NextHop(std::string address, uint32_t label, std::string tunnel, const std::string virtual_network = "") : - address_(address), no_label_(false), label_(label), - virtual_network_(virtual_network) { + address_(address), no_label_(false), label_(label), l3_label_(0), + virtual_network_(virtual_network) { if (tunnel.empty()) { tunnel_encapsulations_.push_back("gre"); } else if (tunnel == "all") { @@ -207,6 +207,12 @@ struct NextHop { tunnel_encapsulations_.push_back(tunnel); } } + NextHop(std::string address, uint32_t label, uint32_t l3_label, + const std::string virtual_network = "") : + address_(address), no_label_(false), label_(label), + l3_label_(l3_label), virtual_network_(virtual_network) { + tunnel_encapsulations_.push_back("vxlan"); + } bool operator==(NextHop other) { if (address_ != other.address_) return false; @@ -233,6 +239,7 @@ struct NextHop { std::string address_; bool no_label_; int label_; + int l3_label_; std::vector tunnel_encapsulations_; std::string virtual_network_; }; diff --git a/src/schema/xmpp_enet.xsd b/src/schema/xmpp_enet.xsd index f830d020981..0e41248c1ae 100644 --- a/src/schema/xmpp_enet.xsd +++ b/src/schema/xmpp_enet.xsd @@ -23,6 +23,7 @@ xsd:targetNamespace="http://www.contrailsystems.com/xmpp-enet-cfg.xsd"> +