From 0a70be6d79b21e9ad47e41cc2a3ec8fa8b230ad8 Mon Sep 17 00:00:00 2001 From: Nischal Sheth Date: Tue, 30 Dec 2014 14:00:46 -0800 Subject: [PATCH] Prevent loops when re-originating service chain routes Implement a new attribute called OriginVnPath to keep track of VNs from which a given route has been re-originated. The OriginVn of ServiceChain destination routing instance gets prepended to OriginVnPath when adding the ServiceChain route. Further, a route is not re-originated if source routing instance's OriginVn is already in the OriginVnPath. This prevents route re-origination loops even if VNs are mis-configured such that multiple VNs have the same route target and there are transit VNs with mis-configured route targets as well. Change-Id: Iab76ad4b07a69f71383db8e72531fb31bade04bd Closes-Bug: 1401010 --- src/bgp/SConscript | 1 + src/bgp/bgp_attr.cc | 33 +- src/bgp/bgp_attr.h | 15 +- src/bgp/bgp_attr_base.h | 1 + src/bgp/bgp_message_builder.cc | 12 + src/bgp/bgp_origin_vn_path.cc | 96 ++++++ src/bgp/bgp_origin_vn_path.h | 118 +++++++ src/bgp/bgp_peer.sandesh | 1 + src/bgp/bgp_proto.cc | 24 ++ src/bgp/bgp_route.cc | 13 + src/bgp/bgp_server.cc | 1 + src/bgp/bgp_server.h | 3 + src/bgp/routing-instance/service_chaining.cc | 26 +- src/bgp/test/bgp_attr_test.cc | 190 +++++++++++- src/bgp/test/bgp_proto_test.cc | 9 + src/bgp/test/service_chain_test.cc | 288 +++++++++++++----- .../svc_static_route_intergration_test.cc | 109 +++++++ src/bgp/testdata/service_chain_test_1.xml | 2 +- src/bgp/testdata/service_chain_test_2.xml | 2 +- src/bgp/testdata/service_chain_test_3.xml | 53 ++++ 20 files changed, 898 insertions(+), 99 deletions(-) create mode 100644 src/bgp/bgp_origin_vn_path.cc create mode 100644 src/bgp/bgp_origin_vn_path.h create mode 100644 src/bgp/testdata/service_chain_test_3.xml diff --git a/src/bgp/SConscript b/src/bgp/SConscript index d0789b91684..54f538bfbc1 100644 --- a/src/bgp/SConscript +++ b/src/bgp/SConscript @@ -46,6 +46,7 @@ libbgp = env.Library('bgp', 'bgp_log.cc', 'bgp_message_builder.cc', 'bgp_multicast.cc', + 'bgp_origin_vn_path.cc', 'bgp_path.cc', 'bgp_peer.cc', 'bgp_peer_close.cc', diff --git a/src/bgp/bgp_attr.cc b/src/bgp/bgp_attr.cc index 2e5936689de..2f363229dff 100644 --- a/src/bgp/bgp_attr.cc +++ b/src/bgp/bgp_attr.cc @@ -536,6 +536,7 @@ BgpAttr::BgpAttr(const BgpAttr &rhs) as_path_(rhs.as_path_), community_(rhs.community_), ext_community_(rhs.ext_community_), + origin_vn_path_(rhs.origin_vn_path_), pmsi_tunnel_(rhs.pmsi_tunnel_), edge_discovery_(rhs.edge_discovery_), edge_forwarding_(rhs.edge_forwarding_), @@ -563,8 +564,8 @@ void BgpAttr::set_community(const CommunitySpec *comm) { } } -void BgpAttr::set_ext_community(ExtCommunityPtr comm) { - ext_community_ = comm; +void BgpAttr::set_ext_community(ExtCommunityPtr extcomm) { + ext_community_ = extcomm; } void BgpAttr::set_ext_community(const ExtCommunitySpec *extcomm) { @@ -575,6 +576,18 @@ void BgpAttr::set_ext_community(const ExtCommunitySpec *extcomm) { } } +void BgpAttr::set_origin_vn_path(OriginVnPathPtr ovnpath) { + origin_vn_path_ = ovnpath; +} + +void BgpAttr::set_origin_vn_path(const OriginVnPathSpec *spec) { + if (spec) { + origin_vn_path_ = attr_db_->server()->ovnpath_db()->Locate(*spec); + } else { + origin_vn_path_ = NULL; + } +} + void BgpAttr::set_pmsi_tunnel(const PmsiTunnelSpec *pmsi_spec) { if (pmsi_spec) { pmsi_tunnel_.reset(new PmsiTunnel(*pmsi_spec)); @@ -649,6 +662,13 @@ int BgpAttr::CompareTo(const BgpAttr &rhs) const { if (ret != 0) return ret; } + if (origin_vn_path_.get() == NULL || rhs.origin_vn_path_.get() == NULL) { + KEY_COMPARE(origin_vn_path_.get(), rhs.origin_vn_path_.get()); + } else { + int ret = origin_vn_path_->CompareTo(*rhs.origin_vn_path_); + if (ret != 0) return ret; + } + return 0; } @@ -680,6 +700,7 @@ std::size_t hash_value(BgpAttr const &attr) { if (attr.as_path_) boost::hash_combine(hash, *attr.as_path_); if (attr.community_) boost::hash_combine(hash, *attr.community_); if (attr.ext_community_) boost::hash_combine(hash, *attr.ext_community_); + if (attr.origin_vn_path_) boost::hash_combine(hash, *attr.origin_vn_path_); return hash; } @@ -703,6 +724,14 @@ BgpAttrPtr BgpAttrDB::ReplaceExtCommunityAndLocate(const BgpAttr *attr, return Locate(clone); } +// Return a clone of attribute with updated origin vn path. +BgpAttrPtr BgpAttrDB::ReplaceOriginVnPathAndLocate(const BgpAttr *attr, + OriginVnPathPtr ovnpath) { + BgpAttr *clone = new BgpAttr(*attr); + clone->set_origin_vn_path(ovnpath); + return Locate(clone); +} + // Return a clone of attribute with updated local preference. BgpAttrPtr BgpAttrDB::ReplaceLocalPreferenceAndLocate(const BgpAttr *attr, uint32_t local_pref) { diff --git a/src/bgp/bgp_attr.h b/src/bgp/bgp_attr.h index 4956c86bbdf..981aa77eb49 100644 --- a/src/bgp/bgp_attr.h +++ b/src/bgp/bgp_attr.h @@ -17,6 +17,7 @@ #include "base/util.h" #include "bgp/bgp_aspath.h" #include "bgp/bgp_attr_base.h" +#include "bgp/bgp_origin_vn_path.h" #include "bgp/bgp_server.h" #include "bgp/community.h" #include "net/address.h" @@ -159,7 +160,9 @@ struct BgpMpNlri : public BgpAttribute { BgpAttribute(code, ExtendedLength|kFlags), afi(afi), safi(safi) { nexthop.clear(); } - explicit BgpMpNlri(const BgpAttribute &rhs) : BgpAttribute(rhs) {} + explicit BgpMpNlri(const BgpAttribute &rhs) + : BgpAttribute(rhs), afi(0), safi(0) { + } ~BgpMpNlri() { STLDeleteValues(&nlri); } @@ -521,8 +524,10 @@ class BgpAttr { void set_as_path(const AsPathSpec *spec); void set_community(CommunityPtr comm); void set_community(const CommunitySpec *comm); - void set_ext_community(ExtCommunityPtr comm); + void set_ext_community(ExtCommunityPtr extcomm); void set_ext_community(const ExtCommunitySpec *extcomm); + void set_origin_vn_path(OriginVnPathPtr ovnpath); + void set_origin_vn_path(const OriginVnPathSpec *spec); void set_pmsi_tunnel(const PmsiTunnelSpec *pmsi_spec); void set_edge_discovery(const EdgeDiscoverySpec *edspec); void set_edge_forwarding(const EdgeForwardingSpec *efspec); @@ -546,6 +551,7 @@ class BgpAttr { int as_path_count() const { return as_path_ ? as_path_->AsCount() : 0; } const Community *community() const { return community_.get(); } const ExtCommunity *ext_community() const { return ext_community_.get(); } + const OriginVnPath *origin_vn_path() const { return origin_vn_path_.get(); } const PmsiTunnel *pmsi_tunnel() const { return pmsi_tunnel_.get(); } const EdgeDiscovery *edge_discovery() const { return edge_discovery_.get(); @@ -579,6 +585,7 @@ class BgpAttr { AsPathPtr as_path_; CommunityPtr community_; ExtCommunityPtr ext_community_; + OriginVnPathPtr origin_vn_path_; PmsiTunnelPtr pmsi_tunnel_; EdgeDiscoveryPtr edge_discovery_; EdgeForwardingPtr edge_forwarding_; @@ -619,7 +626,9 @@ class BgpAttrDB : public BgpPathAttributeDBorigin_vn_path() && attr->origin_vn_path()->origin_vns().size()) { + OriginVnPathSpec *ovnpath_spec = new OriginVnPathSpec; + const OriginVnPath::OriginVnList &v = + attr->origin_vn_path()->origin_vns(); + for (OriginVnPath::OriginVnList::const_iterator it = v.begin(); + it != v.end(); ++it) { + uint64_t value = get_value(it->data(), it->size()); + ovnpath_spec->origin_vns.push_back(value); + } + update.path_attributes.push_back(ovnpath_spec); + } + if (attr->pmsi_tunnel()) { PmsiTunnelSpec *pmsi_spec = new PmsiTunnelSpec(attr->pmsi_tunnel()->pmsi_tunnel()); diff --git a/src/bgp/bgp_origin_vn_path.cc b/src/bgp/bgp_origin_vn_path.cc new file mode 100644 index 00000000000..8a73112a003 --- /dev/null +++ b/src/bgp/bgp_origin_vn_path.cc @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved. + */ + +#include "bgp/bgp_origin_vn_path.h" + +#include + +#include +#include + +#include "bgp/bgp_proto.h" + +using std::string; +using std::vector; + +string OriginVnPathSpec::ToString() const { + char repr[80]; + snprintf(repr, sizeof(repr), "OriginVnPath : %lu", + code, flags, origin_vns.size()); + return string(repr); +} + +int OriginVnPathSpec::CompareTo(const BgpAttribute &rhs) const { + int ret = BgpAttribute::CompareTo(rhs); + if (ret != 0) + return ret; + KEY_COMPARE(origin_vns, + static_cast(rhs).origin_vns); + return 0; +} + +void OriginVnPathSpec::ToCanonical(BgpAttr *attr) { + attr->set_origin_vn_path(this); +} + +OriginVnPath::OriginVnPath(OriginVnPathDB *ovnpath_db, + const OriginVnPathSpec spec) + : ovnpath_db_(ovnpath_db) { + refcount_ = 0; + for (vector::const_iterator it = spec.origin_vns.begin(); + it < spec.origin_vns.end(); ++it) { + OriginVnValue value; + put_value(value.data(), value.size(), *it); + origin_vns_.push_back(value); + } +} + +void OriginVnPath::Remove() { + ovnpath_db_->Delete(this); +} + +void OriginVnPath::Prepend(const OriginVnValue &value) { + OriginVnList::iterator it = origin_vns_.begin(); + origin_vns_.insert(it, value); +} + +bool OriginVnPath::Contains(const OriginVnValue &val) const { + for (OriginVnList::const_iterator it = origin_vns_.begin(); + it != origin_vns_.end(); ++it) { + if (*it == val) + return true; + } + return false; +} + +int OriginVnPath::CompareTo(const OriginVnPath &rhs) const { + KEY_COMPARE(origin_vns_.size(), rhs.origin_vns_.size()); + + OriginVnList::const_iterator it1, it2; + for (it1 = origin_vns_.begin(), it2 = rhs.origin_vns_.begin(); + it1 < origin_vns_.end(); ++it1, ++it2) { + if (*it1 < *it2) { + return -1; + } + if (*it1 > *it2) { + return 1; + } + } + return 0; +} + +OriginVnPathDB::OriginVnPathDB(BgpServer *server) { +} + +OriginVnPathPtr OriginVnPathDB::PrependAndLocate(const OriginVnPath *ovnpath, + const OriginVnPath::OriginVnValue &value) { + OriginVnPath *clone; + if (ovnpath) { + clone = new OriginVnPath(*ovnpath); + } else { + clone = new OriginVnPath(this); + } + clone->Prepend(value); + return Locate(clone); +} diff --git a/src/bgp/bgp_origin_vn_path.h b/src/bgp/bgp_origin_vn_path.h new file mode 100644 index 00000000000..865f0546619 --- /dev/null +++ b/src/bgp/bgp_origin_vn_path.h @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved. + */ + +#ifndef SRC_BGP_BGP_ORIGIN_VN_PATH_H_ +#define SRC_BGP_BGP_ORIGIN_VN_PATH_H_ + +#include +#include +#include + +#include +#include +#include + +#include "bgp/bgp_attr_base.h" +#include "base/parse_object.h" +#include "base/util.h" + +class BgpAttr; +class OriginVnPathDB; +class BgpServer; + +struct OriginVnPathSpec : public BgpAttribute { + static const int kSize = -1; + static const uint8_t kFlags = Optional | Transitive; + OriginVnPathSpec() : BgpAttribute(OriginVnPath, kFlags) { } + explicit OriginVnPathSpec(const BgpAttribute &rhs) : BgpAttribute(rhs) { } + std::vector origin_vns; + virtual int CompareTo(const BgpAttribute &rhs_attr) const; + virtual void ToCanonical(BgpAttr *attr); + virtual std::string ToString() const; +}; + +class OriginVnPath { +public: + typedef boost::array OriginVnValue; + typedef std::vector OriginVnList; + + explicit OriginVnPath(OriginVnPathDB *ovnpath_db) + : ovnpath_db_(ovnpath_db) { + refcount_ = 0; + } + explicit OriginVnPath(const OriginVnPath &rhs) + : ovnpath_db_(rhs.ovnpath_db_), + origin_vns_(rhs.origin_vns_) { + refcount_ = 0; + } + explicit OriginVnPath(OriginVnPathDB *ovnpath_db, + const OriginVnPathSpec spec); + virtual ~OriginVnPath() { } + + virtual void Remove(); + void Prepend(const OriginVnValue &value); + bool Contains(const OriginVnValue &value) const; + int CompareTo(const OriginVnPath &rhs) const; + + const OriginVnList &origin_vns() const { return origin_vns_; } + + friend std::size_t hash_value(const OriginVnPath &ovnpath) { + size_t hash = 0; + for (OriginVnList::const_iterator it = ovnpath.origin_vns_.begin(); + it != ovnpath.origin_vns_.end(); ++it) { + boost::hash_range(hash, it->begin(), it->end()); + } + return hash; + } + +private: + friend int intrusive_ptr_add_ref(const OriginVnPath *covnpath); + friend int intrusive_ptr_del_ref(const OriginVnPath *covnpath); + friend void intrusive_ptr_release(const OriginVnPath *covnpath); + + mutable tbb::atomic refcount_; + OriginVnPathDB *ovnpath_db_; + OriginVnList origin_vns_; +}; + +inline int intrusive_ptr_add_ref(const OriginVnPath *covnpath) { + return covnpath->refcount_.fetch_and_increment(); +} + +inline int intrusive_ptr_del_ref(const OriginVnPath *covnpath) { + return covnpath->refcount_.fetch_and_decrement(); +} + +inline void intrusive_ptr_release(const OriginVnPath *covnpath) { + int prev = covnpath->refcount_.fetch_and_decrement(); + if (prev == 1) { + OriginVnPath *ovnpath = const_cast(covnpath); + ovnpath->Remove(); + assert(ovnpath->refcount_ == 0); + delete ovnpath; + } +} + +typedef boost::intrusive_ptr OriginVnPathPtr; + +struct OriginVnPathCompare { + bool operator()(const OriginVnPath *lhs, const OriginVnPath *rhs) { + return lhs->CompareTo(*rhs) < 0; + } +}; + +class OriginVnPathDB : public BgpPathAttributeDB { +public: + explicit OriginVnPathDB(BgpServer *server); + OriginVnPathPtr PrependAndLocate(const OriginVnPath *ovnpath, + const OriginVnPath::OriginVnValue &value); + +private: + DISALLOW_COPY_AND_ASSIGN(OriginVnPathDB); +}; + +#endif // SRC_BGP_BGP_ORIGIN_VN_PATH_H_ diff --git a/src/bgp/bgp_peer.sandesh b/src/bgp/bgp_peer.sandesh index f388d1e70ab..f934183aa09 100644 --- a/src/bgp/bgp_peer.sandesh +++ b/src/bgp/bgp_peer.sandesh @@ -139,6 +139,7 @@ struct ShowRoutePath { 14: string primary_table (link="ShowRouteReq"); 15: list communities; 16: string origin_vn; + 20: list origin_vn_path; 19: string sequence_no; 17: u32 flags; } diff --git a/src/bgp/bgp_proto.cc b/src/bgp/bgp_proto.cc index 86bb953bd59..2d7e8757c5a 100644 --- a/src/bgp/bgp_proto.cc +++ b/src/bgp/bgp_proto.cc @@ -869,6 +869,28 @@ class BgpPathAttributeExtendedCommunities : BgpPathAttributeExtendedCommunityList> Sequence; }; +class BgpPathAttributeOriginVnList : + public ProtoElement { +public: + static const int kSize = -1; + static bool Verifier(const OriginVnPathSpec *obj, const uint8_t *data, + size_t size, ParseContext *context) { + return BgpAttributeVerifier::Verifier(obj, data, size, + context); + } + + typedef VectorAccessor Setter; +}; + +class BgpPathAttributeOriginVnPath : + public ProtoSequence { +public: + typedef OriginVnPathSpec ContextType; + typedef BgpContextSwap ContextSwap; + typedef mpl::list Sequence; +}; + class BgpPathAttributePmsiTunnelIdentifier : public ProtoElement { public: @@ -1420,6 +1442,8 @@ class BgpPathAttribute : public ProtoChoice { BgpPathAttributeMpUnreachNlriSequence>, mpl::pair, BgpPathAttributeExtendedCommunities>, + mpl::pair, + BgpPathAttributeOriginVnPath>, mpl::pair, BgpPathAttributePmsiTunnel>, mpl::pair, diff --git a/src/bgp/bgp_route.cc b/src/bgp/bgp_route.cc index 427291a6808..08df585af2d 100644 --- a/src/bgp/bgp_route.cc +++ b/src/bgp/bgp_route.cc @@ -321,6 +321,16 @@ static void FillRoutePathExtCommunityInfo(const BgpTable *table, } } +static void FillOriginVnPathInfo(const OriginVnPath *ovnpath, + ShowRoutePath *show_path) { + const OriginVnPath::OriginVnList &v = ovnpath->origin_vns(); + for (OriginVnPath::OriginVnList::const_iterator it = v.begin(); + it != v.end(); ++it) { + OriginVn origin_vn(*it); + show_path->origin_vn_path.push_back(origin_vn.ToString()); + } +} + void BgpRoute::FillRouteInfo(const BgpTable *table, ShowRoute *show_route) const { const RoutingInstance *ri = table->routing_instance(); @@ -378,6 +388,9 @@ void BgpRoute::FillRouteInfo(const BgpTable *table, if (!table->IsVpnTable() && path->IsVrfOriginated()) { srp.set_origin_vn(ri->GetVirtualNetworkName()); } + if (attr->origin_vn_path()) { + FillOriginVnPathInfo(attr->origin_vn_path(), &srp); + } show_route_paths.push_back(srp); } show_route->set_paths(show_route_paths); diff --git a/src/bgp/bgp_server.cc b/src/bgp/bgp_server.cc index fae0448264d..251300861f1 100644 --- a/src/bgp/bgp_server.cc +++ b/src/bgp/bgp_server.cc @@ -224,6 +224,7 @@ BgpServer::BgpServer(EventManager *evm) aspath_db_(new AsPathDB(this)), comm_db_(new CommunityDB(this)), extcomm_db_(new ExtCommunityDB(this)), + ovnpath_db_(new OriginVnPathDB(this)), attr_db_(new BgpAttrDB(this)), session_mgr_(BgpObjectFactory::Create(evm, this)), sched_mgr_(new SchedulingGroupManager), diff --git a/src/bgp/bgp_server.h b/src/bgp/bgp_server.h index b94394a1ccb..f0e02c38c2b 100644 --- a/src/bgp/bgp_server.h +++ b/src/bgp/bgp_server.h @@ -30,6 +30,7 @@ class CommunityDB; class ExtCommunityDB; class LifetimeActor; class LifetimeManager; +class OriginVnPathDB; class PeerRibMembershipManager; class RoutePathReplicator; class RoutingInstanceMgr; @@ -94,6 +95,7 @@ class BgpServer { BgpAttrDB *attr_db() { return attr_db_.get(); } CommunityDB *comm_db() { return comm_db_.get(); } ExtCommunityDB *extcomm_db() { return extcomm_db_.get(); } + OriginVnPathDB *ovnpath_db() { return ovnpath_db_.get(); } bool IsDeleted() const; bool IsReadyForDeletion(); @@ -166,6 +168,7 @@ class BgpServer { boost::scoped_ptr aspath_db_; boost::scoped_ptr comm_db_; boost::scoped_ptr extcomm_db_; + boost::scoped_ptr ovnpath_db_; boost::scoped_ptr attr_db_; // sessions and state managers diff --git a/src/bgp/routing-instance/service_chaining.cc b/src/bgp/routing-instance/service_chaining.cc index 76a37711795..5f2288fc656 100644 --- a/src/bgp/routing-instance/service_chaining.cc +++ b/src/bgp/routing-instance/service_chaining.cc @@ -18,6 +18,7 @@ #include "bgp/bgp_condition_listener.h" #include "bgp/bgp_config.h" #include "bgp/bgp_log.h" +#include "bgp/bgp_origin_vn_path.h" #include "bgp/bgp_path.h" #include "bgp/bgp_peer.h" #include "bgp/bgp_peer_membership.h" @@ -154,6 +155,15 @@ bool ServiceChain::Match(BgpServer *server, BgpTable *table, if (!dest_vn_index) deleted = true; } + + OriginVn src_origin_vn( + server->autonomous_system(), src_vn_index); + const OriginVnPath *ovnpath = + attr ? attr->origin_vn_path() : NULL; + if (ovnpath && + ovnpath->Contains(src_origin_vn.GetExtCommunity())) { + deleted = true; + } } } @@ -310,6 +320,7 @@ void ServiceChain::AddServiceChainRoute(Ip4Prefix prefix, SiteOfOrigin soo; ExtCommunity::ExtCommunityList sgid_list; const Community *orig_community = NULL; + const OriginVnPath *orig_ovnpath = NULL; if (orig_route) { const BgpPath *orig_path = orig_route->BestPath(); const BgpAttr *orig_attr = NULL; @@ -319,6 +330,7 @@ void ServiceChain::AddServiceChainRoute(Ip4Prefix prefix, if (orig_attr) { orig_community = orig_attr->community(); ext_community = orig_attr->ext_community(); + orig_ovnpath = orig_attr->origin_vn_path(); } if (ext_community) { BOOST_FOREACH(const ExtCommunity::ExtCommunityValue &comm, @@ -331,9 +343,13 @@ void ServiceChain::AddServiceChainRoute(Ip4Prefix prefix, } } - BgpAttrDB *attr_db = src_->server()->attr_db(); - ExtCommunityDB *extcomm_db = src_->server()->extcomm_db(); - PeerRibMembershipManager *membership_mgr = src_->server()->membership_mgr(); + BgpAttrDB *attr_db = server->attr_db(); + ExtCommunityDB *extcomm_db = server->extcomm_db(); + PeerRibMembershipManager *membership_mgr = server->membership_mgr(); + OriginVnPathDB *ovnpath_db = server->ovnpath_db(); + OriginVnPathPtr new_ovnpath = + ovnpath_db->PrependAndLocate(orig_ovnpath, origin_vn.GetExtCommunity()); + ConnectedPathIdList new_path_ids; for (Route::PathList::iterator it = connected_route()->GetPathList().begin(); @@ -380,13 +396,15 @@ void ServiceChain::AddServiceChainRoute(Ip4Prefix prefix, new_ext_community = extcomm_db->ReplaceOriginVnAndLocate( new_ext_community.get(), origin_vn.GetExtCommunity()); - // Replace extended community and community values. + // Replace extended community, community and origin vn path. BgpAttrPtr new_attr = attr_db->ReplaceExtCommunityAndLocate( attr, new_ext_community); if (orig_community) { new_attr = attr_db->ReplaceCommunityAndLocate(new_attr.get(), orig_community); } + new_attr = attr_db->ReplaceOriginVnPathAndLocate(new_attr.get(), + new_ovnpath); // If the connected path is learnt via XMPP, construct RD based on // the id registered with source table instead of connected table. diff --git a/src/bgp/test/bgp_attr_test.cc b/src/bgp/test/bgp_attr_test.cc index 7530e4be6d8..3e8d6fca41b 100644 --- a/src/bgp/test/bgp_attr_test.cc +++ b/src/bgp/test/bgp_attr_test.cc @@ -13,6 +13,7 @@ #include "base/test/task_test_util.h" #include "bgp/bgp_log.h" #include "bgp/bgp_server.h" +#include "bgp/origin-vn/origin_vn.h" #include "control-node/control_node.h" #include "io/event_manager.h" #include "testing/gunit.h" @@ -26,7 +27,8 @@ class BgpAttrTest : public ::testing::Test { attr_db_(server_.attr_db()), aspath_db_(server_.aspath_db()), comm_db_(server_.comm_db()), - extcomm_db_(server_.extcomm_db()) { + extcomm_db_(server_.extcomm_db()), + ovnpath_db_(server_.ovnpath_db()) { } void TearDown() { @@ -40,6 +42,7 @@ class BgpAttrTest : public ::testing::Test { AsPathDB *aspath_db_; CommunityDB *comm_db_; ExtCommunityDB *extcomm_db_; + OriginVnPathDB *ovnpath_db_; }; TEST_F(BgpAttrTest, UnknownCode) { @@ -329,6 +332,166 @@ TEST_F(BgpAttrTest, ExtCommunityAppend2) { EXPECT_EQ(0, extcomm1.CompareTo(extcomm2)); } +TEST_F(BgpAttrTest, OriginVnPathToString) { + OriginVnPathSpec spec; + for (int idx = 1; idx < 5; idx++) + spec.origin_vns.push_back(100 * idx); + EXPECT_EQ("OriginVnPath : 4", spec.ToString()); +} + +TEST_F(BgpAttrTest, OriginVnPathCompare1) { + OriginVnPathSpec spec1; + for (int idx = 1; idx < 5; idx++) { + OriginVn origin_vn(64512, 100 * idx); + spec1.origin_vns.push_back(origin_vn.GetExtCommunityValue()); + } + OriginVnPath ovnpath1(ovnpath_db_, spec1); + + OriginVnPathSpec spec2; + for (int idx = 4; idx >= 1; idx--) { + OriginVn origin_vn(64512, 100 * idx); + spec2.origin_vns.push_back(origin_vn.GetExtCommunityValue()); + } + OriginVnPath ovnpath2(ovnpath_db_, spec2); + + EXPECT_NE(0, ovnpath1.CompareTo(ovnpath2)); + EXPECT_NE(0, ovnpath2.CompareTo(ovnpath1)); +} + +TEST_F(BgpAttrTest, OriginVnPathCompare2) { + OriginVnPathSpec spec1; + for (int idx = 1; idx < 5; idx++) { + OriginVn origin_vn(64512, 100 * idx); + spec1.origin_vns.push_back(origin_vn.GetExtCommunityValue()); + } + OriginVnPath ovnpath1(ovnpath_db_, spec1); + + OriginVnPathSpec spec2; + for (int idx = 1; idx < 5; idx++) { + OriginVn origin_vn(64512, 100 * idx); + spec2.origin_vns.push_back(origin_vn.GetExtCommunityValue()); + } + OriginVnPath ovnpath2(ovnpath_db_, spec2); + + EXPECT_EQ(0, ovnpath1.CompareTo(ovnpath2)); + EXPECT_EQ(0, ovnpath2.CompareTo(ovnpath1)); +} + +TEST_F(BgpAttrTest, OriginVnPathPrepend) { + OriginVnPathSpec spec1; + for (int idx = 5; idx < 9; idx++) { + OriginVn origin_vn(64512, 100 * idx); + spec1.origin_vns.push_back(origin_vn.GetExtCommunityValue()); + } + OriginVnPath ovnpath1(ovnpath_db_, spec1); + + for (int idx = 4; idx >= 1; idx--) { + OriginVn origin_vn(64512, 100 * idx); + ovnpath1.Prepend(origin_vn.GetExtCommunity()); + } + + OriginVnPathSpec spec2; + for (int idx = 1; idx < 9; idx++) { + OriginVn origin_vn(64512, 100 * idx); + spec2.origin_vns.push_back(origin_vn.GetExtCommunityValue()); + } + OriginVnPath ovnpath2(ovnpath_db_, spec2); + + EXPECT_EQ(0, ovnpath1.CompareTo(ovnpath2)); + EXPECT_EQ(0, ovnpath2.CompareTo(ovnpath1)); +} + +TEST_F(BgpAttrTest, OriginVnPathContains) { + OriginVnPathSpec spec; + for (int idx = 9; idx >= 1; idx -= 2) { + OriginVn origin_vn(64512, 100 * idx); + spec.origin_vns.push_back(origin_vn.GetExtCommunityValue()); + } + OriginVnPath ovnpath(ovnpath_db_, spec); + + for (int idx = 1; idx <= 9; idx++) { + OriginVn origin_vn(64512, 100 * idx); + if (idx % 2 == 1) { + EXPECT_TRUE(ovnpath.Contains(origin_vn.GetExtCommunity())); + } else { + EXPECT_FALSE(ovnpath.Contains(origin_vn.GetExtCommunity())); + } + } + + for (int idx = 8; idx > 0; idx -= 2) { + OriginVn origin_vn(64512, 100 * idx); + ovnpath.Prepend(origin_vn.GetExtCommunity()); + } + + for (int idx = 1; idx <= 9; idx++) { + OriginVn origin_vn(64512, 100 * idx); + EXPECT_TRUE(ovnpath.Contains(origin_vn.GetExtCommunity())); + } +} + +TEST_F(BgpAttrTest, OriginVnPathLocate) { + OriginVnPathSpec spec1; + for (int idx = 1; idx < 5; idx++) { + OriginVn origin_vn(64512, 100 * idx); + spec1.origin_vns.push_back(origin_vn.GetExtCommunityValue()); + } + OriginVnPathPtr ovnpath1 = ovnpath_db_->Locate(spec1); + EXPECT_EQ(1, ovnpath_db_->Size()); + + OriginVnPathSpec spec2; + for (int idx = 4; idx >= 1; idx--) { + OriginVn origin_vn(64512, 100 * idx); + spec2.origin_vns.push_back(origin_vn.GetExtCommunityValue()); + } + OriginVnPathPtr ovnpath2 = ovnpath_db_->Locate(spec2); + EXPECT_EQ(2, ovnpath_db_->Size()); + + EXPECT_NE(0, ovnpath1->CompareTo(*ovnpath2)); + EXPECT_NE(0, ovnpath2->CompareTo(*ovnpath1)); +} + +TEST_F(BgpAttrTest, OriginVnPathPrependAndLocate) { + OriginVnPathSpec spec; + for (int idx = 2; idx < 5; idx++) { + OriginVn origin_vn(64512, 100 * idx); + spec.origin_vns.push_back(origin_vn.GetExtCommunityValue()); + } + OriginVnPathPtr ovnpath1 = ovnpath_db_->Locate(spec); + EXPECT_EQ(1, ovnpath_db_->Size()); + + OriginVn origin_vn(64512, 100 * 1); + OriginVnPathPtr ovnpath2 = ovnpath_db_->PrependAndLocate(ovnpath1.get(), + origin_vn.GetExtCommunity()); + EXPECT_EQ(2, ovnpath_db_->Size()); + + EXPECT_NE(0, ovnpath1->CompareTo(*ovnpath2)); + EXPECT_NE(0, ovnpath2->CompareTo(*ovnpath1)); + + EXPECT_FALSE(ovnpath1->Contains(origin_vn.GetExtCommunity())); + EXPECT_TRUE(ovnpath2->Contains(origin_vn.GetExtCommunity())); +} + +TEST_F(BgpAttrTest, OriginVnPathReplace) { + OriginVnPathSpec spec; + for (int idx = 2; idx < 5; idx++) { + OriginVn origin_vn(64512, 100 * idx); + spec.origin_vns.push_back(origin_vn.GetExtCommunityValue()); + } + BgpAttrSpec attr_spec; + attr_spec.push_back(&spec); + BgpAttrPtr ptr1 = attr_db_->Locate(attr_spec); + EXPECT_EQ(1, ovnpath_db_->Size()); + EXPECT_EQ(1, attr_db_->Size()); + + OriginVn origin_vn(64512, 100 * 1); + OriginVnPathPtr ovnpath = ovnpath_db_->PrependAndLocate( + ptr1->origin_vn_path(), origin_vn.GetExtCommunity()); + BgpAttrPtr ptr2 = + attr_db_->ReplaceOriginVnPathAndLocate(ptr1.get(), ovnpath); + EXPECT_EQ(2, ovnpath_db_->Size()); + EXPECT_EQ(2, attr_db_->Size()); +} + TEST_F(BgpAttrTest, OriginatorId1) { BgpAttrSpec attr_spec; error_code ec; @@ -1085,6 +1248,10 @@ TEST_F(BgpAttrTest, BgpAttrDB) { ext_community->communities.push_back(0x1020304050607080); spec.push_back(ext_community); + OriginVnPathSpec *ovnpath = new OriginVnPathSpec; + ovnpath->origin_vns.push_back(0x1020304050607080); + spec.push_back(ovnpath); + BgpAttrPtr ptr1 = attr_db_->Locate(spec); BgpAttrPtr ptr2 = attr_db_->Locate(spec); @@ -1092,6 +1259,7 @@ TEST_F(BgpAttrTest, BgpAttrDB) { EXPECT_EQ(1, aspath_db_->Size()); EXPECT_EQ(1, comm_db_->Size()); EXPECT_EQ(1, extcomm_db_->Size()); + EXPECT_EQ(1, ovnpath_db_->Size()); agg->address = 0xcafed00d; BgpAttrPtr ptr3 = attr_db_->Locate(spec); @@ -1100,30 +1268,35 @@ TEST_F(BgpAttrTest, BgpAttrDB) { EXPECT_EQ(1, aspath_db_->Size()); EXPECT_EQ(1, comm_db_->Size()); EXPECT_EQ(1, extcomm_db_->Size()); + EXPECT_EQ(1, ovnpath_db_->Size()); ptr1.reset(); EXPECT_EQ(2, attr_db_->Size()); EXPECT_EQ(1, aspath_db_->Size()); EXPECT_EQ(1, comm_db_->Size()); EXPECT_EQ(1, extcomm_db_->Size()); + EXPECT_EQ(1, ovnpath_db_->Size()); ptr2.reset(); EXPECT_EQ(1, attr_db_->Size()); EXPECT_EQ(1, aspath_db_->Size()); EXPECT_EQ(1, comm_db_->Size()); EXPECT_EQ(1, extcomm_db_->Size()); + EXPECT_EQ(1, ovnpath_db_->Size()); ptr3.reset(); EXPECT_EQ(0, attr_db_->Size()); EXPECT_EQ(0, aspath_db_->Size()); EXPECT_EQ(0, comm_db_->Size()); EXPECT_EQ(0, extcomm_db_->Size()); + EXPECT_EQ(0, ovnpath_db_->Size()); ptr1 = attr_db_->Locate(spec); EXPECT_EQ(1, attr_db_->Size()); EXPECT_EQ(1, aspath_db_->Size()); EXPECT_EQ(1, comm_db_->Size()); EXPECT_EQ(1, extcomm_db_->Size()); + EXPECT_EQ(1, ovnpath_db_->Size()); STLDeleteValues(&spec); } @@ -1179,14 +1352,16 @@ static void ConcurrencyTest(TypeDB *db) { } // Instantiate the template functions. -template void ConcurrencyTest( - BgpAttrDB *); -template void ConcurrencyTest( - AsPathDB *); +template void ConcurrencyTest(BgpAttrDB *); +template void ConcurrencyTest(AsPathDB *); template void ConcurrencyTest(CommunityDB *); template void ConcurrencyTest(ExtCommunityDB *); +template void ConcurrencyTest(OriginVnPathDB *); TEST_F(BgpAttrTest, BgpAttrDBConcurrency) { ConcurrencyTest(attr_db_); @@ -1206,6 +1381,11 @@ TEST_F(BgpAttrTest, ExtCommunityDBConcurrency) { ExtCommunitySpec>(extcomm_db_); } +TEST_F(BgpAttrTest, OriginVnPathDBConcurrency) { + ConcurrencyTest(ovnpath_db_); +} + static void SetUp() { bgp_log_test::init(); ControlNode::SetDefaultSchedulingPolicy(); diff --git a/src/bgp/test/bgp_proto_test.cc b/src/bgp/test/bgp_proto_test.cc index 104a9791fd5..c0a2db0624f 100644 --- a/src/bgp/test/bgp_proto_test.cc +++ b/src/bgp/test/bgp_proto_test.cc @@ -202,6 +202,14 @@ class BuildUpdateMessage { msg->path_attributes.push_back(efspec); } + static void AddOriginVnPath(BgpProto::Update *msg) { + OriginVnPathSpec *ovnpath = new OriginVnPathSpec; + for (int i = rand() % 10; i > 0; i--) { + ovnpath->origin_vns.push_back(rand()); + } + msg->path_attributes.push_back(ovnpath); + } + static void AddUnknown(BgpProto::Update *msg) { BgpAttrUnknown *unk = new BgpAttrUnknown; unk->flags = BgpAttribute::Optional; @@ -228,6 +236,7 @@ std::vector BuildUpdateMessage::build_para (std::make_pair(&BuildUpdateMessage::AddPmsiTunnel, 5)) (std::make_pair(&BuildUpdateMessage::AddEdgeDiscovery, 5)) (std::make_pair(&BuildUpdateMessage::AddEdgeForwarding, 5)) + (std::make_pair(&BuildUpdateMessage::AddOriginVnPath, 5)) (std::make_pair(&BuildUpdateMessage::AddUnknown, 5)); diff --git a/src/bgp/test/service_chain_test.cc b/src/bgp/test/service_chain_test.cc index 05377a67a98..334d498a9c5 100644 --- a/src/bgp/test/service_chain_test.cc +++ b/src/bgp/test/service_chain_test.cc @@ -547,7 +547,8 @@ class ServiceChainTest : public ::testing::Test { bool MatchInetPathAttributes(const BgpPath *path, const string &path_id, const string &origin_vn, uint32_t label, const vector sg_ids, const set tunnel_encaps, - const SiteOfOrigin &soo, const vector &commlist) { + const SiteOfOrigin &soo, const vector &commlist, + const vector &origin_vn_path) { BgpAttrPtr attr = path->GetAttr(); if (attr->nexthop().to_v4().to_string() != path_id) return false; @@ -577,6 +578,10 @@ class ServiceChainTest : public ::testing::Test { if (path_soo != soo) return false; } + if (origin_vn_path.size() && + GetOriginVnPathFromRoute(path) != origin_vn_path) { + return false; + } vector path_commlist = GetCommunityListFromRoute(path); if (path_commlist != commlist) @@ -588,7 +593,8 @@ class ServiceChainTest : public ::testing::Test { bool CheckInetPathAttributes(const string &instance, const string &prefix, const string &path_id, const string &origin_vn, int label, const vector sg_ids, const set tunnel_encaps, - const SiteOfOrigin &soo, const vector &commlist) { + const SiteOfOrigin &soo, const vector &commlist, + const vector &origin_vn_path) { task_util::TaskSchedulerLock lock; BgpRoute *route = InetRouteLookup(instance, prefix); if (!route) @@ -599,7 +605,7 @@ class ServiceChainTest : public ::testing::Test { if (BgpPath::PathIdString(path->GetPathId()) != path_id) continue; if (MatchInetPathAttributes(path, path_id, origin_vn, label, - sg_ids, tunnel_encaps, soo, commlist)) { + sg_ids, tunnel_encaps, soo, commlist, origin_vn_path)) { return true; } return false; @@ -614,13 +620,14 @@ class ServiceChainTest : public ::testing::Test { task_util::WaitForIdle(); TASK_UTIL_EXPECT_TRUE(CheckInetPathAttributes(instance, prefix, path_id, origin_vn, 0, vector(), tunnel_encaps, - SiteOfOrigin(), vector())); + SiteOfOrigin(), vector(), vector())); } bool CheckInetRouteAttributes(const string &instance, const string &prefix, const vector &path_ids, const string &origin_vn, int label, const vector sg_ids, const set tunnel_encap, - const SiteOfOrigin &soo, const vector &commlist) { + const SiteOfOrigin &soo, const vector &commlist, + const vector &origin_vn_path) { task_util::TaskSchedulerLock lock; BgpRoute *route = InetRouteLookup(instance, prefix); if (!route) @@ -636,7 +643,7 @@ class ServiceChainTest : public ::testing::Test { continue; found = true; if (MatchInetPathAttributes(path, path_id, origin_vn, label, - sg_ids, tunnel_encap, soo, commlist)) { + sg_ids, tunnel_encap, soo, commlist, origin_vn_path)) { break; } return false; @@ -655,7 +662,8 @@ class ServiceChainTest : public ::testing::Test { vector path_ids = list_of(path_id); TASK_UTIL_EXPECT_TRUE(CheckInetRouteAttributes( instance, prefix, path_ids, origin_vn, label, vector(), - set(), SiteOfOrigin(), vector())); + set(), SiteOfOrigin(), vector(), + vector())); } void VerifyInetRouteAttributes(const string &instance, const string &prefix, @@ -663,7 +671,8 @@ class ServiceChainTest : public ::testing::Test { task_util::WaitForIdle(); TASK_UTIL_EXPECT_TRUE(CheckInetRouteAttributes( instance, prefix, path_ids, origin_vn, 0, vector(), - set(), SiteOfOrigin(), vector())); + set(), SiteOfOrigin(), vector(), + vector())); } void VerifyInetRouteAttributes(const string &instance, @@ -673,7 +682,7 @@ class ServiceChainTest : public ::testing::Test { vector path_ids = list_of(path_id); TASK_UTIL_EXPECT_TRUE(CheckInetRouteAttributes( instance, prefix, path_ids, origin_vn, 0, sg_ids, set(), - SiteOfOrigin(), vector())); + SiteOfOrigin(), vector(), vector())); } void VerifyInetRouteAttributes(const string &instance, @@ -683,7 +692,8 @@ class ServiceChainTest : public ::testing::Test { vector path_ids = list_of(path_id); TASK_UTIL_EXPECT_TRUE(CheckInetRouteAttributes( instance, prefix, path_ids, origin_vn, 0, vector(), - tunnel_encaps, SiteOfOrigin(), vector())); + tunnel_encaps, SiteOfOrigin(), vector(), + vector())); } void VerifyInetRouteAttributes(const string &instance, @@ -693,7 +703,7 @@ class ServiceChainTest : public ::testing::Test { vector path_ids = list_of(path_id); TASK_UTIL_EXPECT_TRUE(CheckInetRouteAttributes( instance, prefix, path_ids, origin_vn, 0, vector(), - set(), soo, vector())); + set(), soo, vector(), vector())); } void VerifyInetRouteAttributes(const string &instance, @@ -703,7 +713,18 @@ class ServiceChainTest : public ::testing::Test { vector path_ids = list_of(path_id); TASK_UTIL_EXPECT_TRUE(CheckInetRouteAttributes( instance, prefix, path_ids, origin_vn, 0, vector(), - set(), SiteOfOrigin(), commspec.communities)); + set(), SiteOfOrigin(), commspec.communities, + vector())); + } + + void VerifyInetRouteAttributes(const string &instance, + const string &prefix, const string &path_id, const string &origin_vn, + const vector &origin_vn_path) { + task_util::WaitForIdle(); + vector path_ids = list_of(path_id); + TASK_UTIL_EXPECT_TRUE(CheckInetRouteAttributes( + instance, prefix, path_ids, origin_vn, 0, vector(), + set(), SiteOfOrigin(), vector(), origin_vn_path)); } string FileRead(const string &filename) { @@ -834,6 +855,21 @@ class ServiceChainTest : public ::testing::Test { return "unresolved"; } + vector GetOriginVnPathFromRoute(const BgpPath *path) { + const OriginVnPath *ovnpath = path->GetAttr()->origin_vn_path(); + assert(ovnpath); + vector result; + BOOST_FOREACH(const ExtCommunity::ExtCommunityValue &comm, + ovnpath->origin_vns()) { + assert(ExtCommunity::is_origin_vn(comm)); + OriginVn origin_vn(comm); + string vn_name = + ri_mgr_->GetVirtualNetworkByVnIndex(origin_vn.vn_index()); + result.push_back(vn_name); + } + return result; + } + SiteOfOrigin GetSiteOfOriginFromRoute(const BgpPath *path) { const ExtCommunity *ext_comm = path->GetAttr()->ext_community(); assert(ext_comm); @@ -2772,8 +2808,10 @@ TEST_P(ServiceChainParamTest, TransitNetworkRemoteVMRoutes) { AddConnectedRoute(2, NULL, "192.168.2.253/32", 100, "20.1.1.2"); // Check for Aggregate route in blue - BgpRoute *aggregate_rt = VerifyInetRouteExists("blue", "192.168.3.0/24"); - EXPECT_EQ(GetOriginVnFromRoute(aggregate_rt->BestPath()), "core-vn"); + vector origin_vn_path = list_of("core-vn")("red-vn"); + VerifyInetRouteExists("blue", "192.168.3.0/24"); + VerifyInetRouteAttributes("blue", "192.168.3.0/24", "20.1.1.1", "core-vn", + origin_vn_path); // Delete more specific routes and connected routes DeleteInetRoute(NULL, "red", "192.168.3.101/32"); @@ -2800,8 +2838,10 @@ TEST_P(ServiceChainParamTest, TransitNetworkLocalVMRoutes) { AddConnectedRoute(1, NULL, "192.168.1.253/32", 100, "20.1.1.1"); // Check for Aggregate route in blue - BgpRoute *aggregate_rt = VerifyInetRouteExists("blue", "192.168.2.0/24"); - EXPECT_EQ(GetOriginVnFromRoute(aggregate_rt->BestPath()), "core-vn"); + vector origin_vn_path = list_of("core-vn"); + VerifyInetRouteExists("blue", "192.168.2.0/24"); + VerifyInetRouteAttributes("blue", "192.168.2.0/24", "20.1.1.1", "core-vn", + origin_vn_path); // Delete more specific routes and connected routes DeleteInetRoute(NULL, "core", "192.168.2.101/32"); @@ -2829,12 +2869,16 @@ TEST_P(ServiceChainParamTest, TransitNetworkRemoteExtConnectRoute) { // Check for ExtConnect route in blue BgpRoute *ext_rt; - ext_rt = VerifyInetRouteExists("blue", "10.1.3.1/32"); - EXPECT_EQ(GetOriginVnFromRoute(ext_rt->BestPath()), "core-vn"); - ext_rt = VerifyInetRouteExists("blue", "10.1.3.2/32"); - EXPECT_EQ(GetOriginVnFromRoute(ext_rt->BestPath()), "core-vn"); - ext_rt = VerifyInetRouteExists("blue", "10.1.3.3/32"); - EXPECT_EQ(GetOriginVnFromRoute(ext_rt->BestPath()), "core-vn"); + vector origin_vn_path = list_of("core-vn")("red-vn"); + VerifyInetRouteExists("blue", "10.1.3.1/32"); + VerifyInetRouteAttributes("blue", "10.1.3.1/32", "20.1.1.1", "core-vn", + origin_vn_path); + VerifyInetRouteExists("blue", "10.1.3.2/32"); + VerifyInetRouteAttributes("blue", "10.1.3.2/32", "20.1.1.1", "core-vn", + origin_vn_path); + VerifyInetRouteExists("blue", "10.1.3.3/32"); + VerifyInetRouteAttributes("blue", "10.1.3.3/32", "20.1.1.1", "core-vn", + origin_vn_path); // Delete Ext connect routes and connected routes DeleteInetRoute(NULL, "red", "10.1.3.1/32"); @@ -2859,12 +2903,16 @@ TEST_P(ServiceChainParamTest, TransitNetworkLocalExtConnectRoute) { // Check for ExtConnect route in blue BgpRoute *ext_rt; - ext_rt = VerifyInetRouteExists("blue", "10.1.2.1/32"); - EXPECT_EQ(GetOriginVnFromRoute(ext_rt->BestPath()), "core-vn"); - ext_rt = VerifyInetRouteExists("blue", "10.1.2.1/32"); - EXPECT_EQ(GetOriginVnFromRoute(ext_rt->BestPath()), "core-vn"); - ext_rt = VerifyInetRouteExists("blue", "10.1.2.1/32"); - EXPECT_EQ(GetOriginVnFromRoute(ext_rt->BestPath()), "core-vn"); + vector origin_vn_path = list_of("core-vn"); + VerifyInetRouteExists("blue", "10.1.2.1/32"); + VerifyInetRouteAttributes("blue", "10.1.2.1/32", "20.1.1.1", "core-vn", + origin_vn_path); + VerifyInetRouteExists("blue", "10.1.2.2/32"); + VerifyInetRouteAttributes("blue", "10.1.2.2/32", "20.1.1.1", "core-vn", + origin_vn_path); + VerifyInetRouteExists("blue", "10.1.2.3/32"); + VerifyInetRouteAttributes("blue", "10.1.2.3/32", "20.1.1.1", "core-vn", + origin_vn_path); // Delete Ext connect routes and connected routes DeleteInetRoute(NULL, "core", "10.1.2.1/32"); @@ -2894,16 +2942,18 @@ TEST_P(ServiceChainParamTest, TransitNetworkAddDeleteConnectedRoute1) { AddConnectedRoute(2, NULL, "192.168.2.253/32", 100, "20.1.1.2"); // Check for Aggregate route in blue - BgpRoute *aggregate_rt; - aggregate_rt = VerifyInetRouteExists("blue", "192.168.3.0/24"); - EXPECT_EQ(GetOriginVnFromRoute(aggregate_rt->BestPath()), "core-vn"); + vector origin_vn_path = list_of("core-vn")("red-vn"); + VerifyInetRouteExists("blue", "192.168.3.0/24"); + VerifyInetRouteAttributes("blue", "192.168.3.0/24", "20.1.1.1", "core-vn", + origin_vn_path); // Check for ExtConnect routes in blue - BgpRoute *ext_rt; - ext_rt = VerifyInetRouteExists("blue", "10.1.3.1/32"); - EXPECT_EQ(GetOriginVnFromRoute(ext_rt->BestPath()), "core-vn"); - ext_rt = VerifyInetRouteExists("blue", "10.1.3.2/32"); - EXPECT_EQ(GetOriginVnFromRoute(ext_rt->BestPath()), "core-vn"); + VerifyInetRouteExists("blue", "10.1.3.1/32"); + VerifyInetRouteAttributes("blue", "10.1.3.1/32", "20.1.1.1", "core-vn", + origin_vn_path); + VerifyInetRouteExists("blue", "10.1.3.2/32"); + VerifyInetRouteAttributes("blue", "10.1.3.2/32", "20.1.1.1", "core-vn", + origin_vn_path); // Remove connected route for blue-core chain. DeleteConnectedRoute(1, NULL, "192.168.1.253/32"); @@ -2919,14 +2969,17 @@ TEST_P(ServiceChainParamTest, TransitNetworkAddDeleteConnectedRoute1) { AddConnectedRoute(1, NULL, "192.168.1.253/32", 100, "20.1.1.1"); // Check for Aggregate route in blue - aggregate_rt = VerifyInetRouteExists("blue", "192.168.3.0/24"); - EXPECT_EQ(GetOriginVnFromRoute(aggregate_rt->BestPath()), "core-vn"); + VerifyInetRouteExists("blue", "192.168.3.0/24"); + VerifyInetRouteAttributes("blue", "192.168.3.0/24", "20.1.1.1", "core-vn", + origin_vn_path); // Check for ExtConnect routes in blue - ext_rt = VerifyInetRouteExists("blue", "10.1.3.1/32"); - EXPECT_EQ(GetOriginVnFromRoute(ext_rt->BestPath()), "core-vn"); - ext_rt = VerifyInetRouteExists("blue", "10.1.3.2/32"); - EXPECT_EQ(GetOriginVnFromRoute(ext_rt->BestPath()), "core-vn"); + VerifyInetRouteExists("blue", "10.1.3.1/32"); + VerifyInetRouteAttributes("blue", "10.1.3.1/32", "20.1.1.1", "core-vn", + origin_vn_path); + VerifyInetRouteExists("blue", "10.1.3.2/32"); + VerifyInetRouteAttributes("blue", "10.1.3.2/32", "20.1.1.1", "core-vn", + origin_vn_path); // Delete Ext connect routes and connected routes DeleteInetRoute(NULL, "red", "192.168.3.101/32"); @@ -2958,16 +3011,18 @@ TEST_P(ServiceChainParamTest, TransitNetworkAddDeleteConnectedRoute2) { AddConnectedRoute(2, NULL, "192.168.2.253/32", 100, "20.1.1.2"); // Check for Aggregate route in blue - BgpRoute *aggregate_rt; - aggregate_rt = VerifyInetRouteExists("blue", "192.168.3.0/24"); - EXPECT_EQ(GetOriginVnFromRoute(aggregate_rt->BestPath()), "core-vn"); + vector origin_vn_path = list_of("core-vn")("red-vn"); + VerifyInetRouteExists("blue", "192.168.3.0/24"); + VerifyInetRouteAttributes("blue", "192.168.3.0/24", "20.1.1.1", "core-vn", + origin_vn_path); // Check for ExtConnect routes in blue - BgpRoute *ext_rt; - ext_rt = VerifyInetRouteExists("blue", "10.1.3.1/32"); - EXPECT_EQ(GetOriginVnFromRoute(ext_rt->BestPath()), "core-vn"); - ext_rt = VerifyInetRouteExists("blue", "10.1.3.2/32"); - EXPECT_EQ(GetOriginVnFromRoute(ext_rt->BestPath()), "core-vn"); + VerifyInetRouteExists("blue", "10.1.3.1/32"); + VerifyInetRouteAttributes("blue", "10.1.3.1/32", "20.1.1.1", "core-vn", + origin_vn_path); + VerifyInetRouteExists("blue", "10.1.3.2/32"); + VerifyInetRouteAttributes("blue", "10.1.3.2/32", "20.1.1.1", "core-vn", + origin_vn_path); // Remove connected route for core-red chain. DeleteConnectedRoute(2, NULL, "192.168.2.253/32"); @@ -2983,14 +3038,17 @@ TEST_P(ServiceChainParamTest, TransitNetworkAddDeleteConnectedRoute2) { AddConnectedRoute(2, NULL, "192.168.2.253/32", 100, "20.1.1.1"); // Check for Aggregate route in blue - aggregate_rt = VerifyInetRouteExists("blue", "192.168.3.0/24"); - EXPECT_EQ(GetOriginVnFromRoute(aggregate_rt->BestPath()), "core-vn"); + VerifyInetRouteExists("blue", "192.168.3.0/24"); + VerifyInetRouteAttributes("blue", "192.168.3.0/24", "20.1.1.1", "core-vn", + origin_vn_path); // Check for ExtConnect routes in blue - ext_rt = VerifyInetRouteExists("blue", "10.1.3.1/32"); - EXPECT_EQ(GetOriginVnFromRoute(ext_rt->BestPath()), "core-vn"); - ext_rt = VerifyInetRouteExists("blue", "10.1.3.2/32"); - EXPECT_EQ(GetOriginVnFromRoute(ext_rt->BestPath()), "core-vn"); + VerifyInetRouteExists("blue", "10.1.3.1/32"); + VerifyInetRouteAttributes("blue", "10.1.3.1/32", "20.1.1.1", "core-vn", + origin_vn_path); + VerifyInetRouteExists("blue", "10.1.3.2/32"); + VerifyInetRouteAttributes("blue", "10.1.3.2/32", "20.1.1.1", "core-vn", + origin_vn_path); // Delete Ext connect routes and connected routes DeleteInetRoute(NULL, "red", "192.168.3.101/32"); @@ -3023,16 +3081,18 @@ TEST_P(ServiceChainParamTest, TransitNetworkToggleAllowTransit) { AddConnectedRoute(2, NULL, "192.168.2.253/32", 100, "20.1.1.2"); // Check for Aggregate route in blue - BgpRoute *aggregate_rt; - aggregate_rt = VerifyInetRouteExists("blue", "192.168.3.0/24"); - EXPECT_EQ(GetOriginVnFromRoute(aggregate_rt->BestPath()), "core-vn"); + vector origin_vn_path = list_of("core-vn")("red-vn"); + VerifyInetRouteExists("blue", "192.168.3.0/24"); + VerifyInetRouteAttributes("blue", "192.168.3.0/24", "20.1.1.1", "core-vn", + origin_vn_path); // Check for ExtConnect routes in blue - BgpRoute *ext_rt; - ext_rt = VerifyInetRouteExists("blue", "10.1.3.1/32"); - EXPECT_EQ(GetOriginVnFromRoute(ext_rt->BestPath()), "core-vn"); - ext_rt = VerifyInetRouteExists("blue", "10.1.3.2/32"); - EXPECT_EQ(GetOriginVnFromRoute(ext_rt->BestPath()), "core-vn"); + VerifyInetRouteExists("blue", "10.1.3.1/32"); + VerifyInetRouteAttributes("blue", "10.1.3.1/32", "20.1.1.1", "core-vn", + origin_vn_path); + VerifyInetRouteExists("blue", "10.1.3.2/32"); + VerifyInetRouteAttributes("blue", "10.1.3.2/32", "20.1.1.1", "core-vn", + origin_vn_path); // Disable allow-transit boost::replace_all(content, @@ -3054,14 +3114,17 @@ TEST_P(ServiceChainParamTest, TransitNetworkToggleAllowTransit) { ParseConfigString(content); // Check for Aggregate route in blue - aggregate_rt = VerifyInetRouteExists("blue", "192.168.3.0/24"); - EXPECT_EQ(GetOriginVnFromRoute(aggregate_rt->BestPath()), "core-vn"); + VerifyInetRouteExists("blue", "192.168.3.0/24"); + VerifyInetRouteAttributes("blue", "192.168.3.0/24", "20.1.1.1", "core-vn", + origin_vn_path); // Check for ExtConnect routes in blue - ext_rt = VerifyInetRouteExists("blue", "10.1.3.1/32"); - EXPECT_EQ(GetOriginVnFromRoute(ext_rt->BestPath()), "core-vn"); - ext_rt = VerifyInetRouteExists("blue", "10.1.3.2/32"); - EXPECT_EQ(GetOriginVnFromRoute(ext_rt->BestPath()), "core-vn"); + VerifyInetRouteExists("blue", "10.1.3.1/32"); + VerifyInetRouteAttributes("blue", "10.1.3.1/32", "20.1.1.1", "core-vn", + origin_vn_path); + VerifyInetRouteExists("blue", "10.1.3.2/32"); + VerifyInetRouteAttributes("blue", "10.1.3.2/32", "20.1.1.1", "core-vn", + origin_vn_path); // Delete Ext connect routes and connected routes DeleteInetRoute(NULL, "red", "192.168.3.101/32"); @@ -3100,22 +3163,29 @@ TEST_P(ServiceChainParamTest, TransitNetworkMultipleNetworks) { AddConnectedRoute(3, NULL, "192.168.2.252/32", 100, "20.1.1.3"); // Check for Aggregate routes in blue - BgpRoute *aggregate_rt; - aggregate_rt = VerifyInetRouteExists("blue", "192.168.3.0/24"); - EXPECT_EQ(GetOriginVnFromRoute(aggregate_rt->BestPath()), "core-vn"); - aggregate_rt = VerifyInetRouteExists("blue", "192.168.4.0/24"); - EXPECT_EQ(GetOriginVnFromRoute(aggregate_rt->BestPath()), "core-vn"); + vector origin_vn_path_red = list_of("core-vn")("red-vn"); + vector origin_vn_path_green = list_of("core-vn")("green-vn"); + VerifyInetRouteExists("blue", "192.168.3.0/24"); + VerifyInetRouteAttributes("blue", "192.168.3.0/24", "20.1.1.1", "core-vn", + origin_vn_path_red); + VerifyInetRouteExists("blue", "192.168.4.0/24"); + VerifyInetRouteAttributes("blue", "192.168.4.0/24", "20.1.1.1", "core-vn", + origin_vn_path_green); // Check for ExtConnect routes in blue BgpRoute *ext_rt; - ext_rt = VerifyInetRouteExists("blue", "10.1.3.1/32"); - EXPECT_EQ(GetOriginVnFromRoute(ext_rt->BestPath()), "core-vn"); - ext_rt = VerifyInetRouteExists("blue", "10.1.3.2/32"); - EXPECT_EQ(GetOriginVnFromRoute(ext_rt->BestPath()), "core-vn"); - ext_rt = VerifyInetRouteExists("blue", "10.1.4.1/32"); - EXPECT_EQ(GetOriginVnFromRoute(ext_rt->BestPath()), "core-vn"); - ext_rt = VerifyInetRouteExists("blue", "10.1.4.2/32"); - EXPECT_EQ(GetOriginVnFromRoute(ext_rt->BestPath()), "core-vn"); + VerifyInetRouteExists("blue", "10.1.3.1/32"); + VerifyInetRouteAttributes("blue", "10.1.3.1/32", "20.1.1.1", "core-vn", + origin_vn_path_red); + VerifyInetRouteExists("blue", "10.1.3.2/32"); + VerifyInetRouteAttributes("blue", "10.1.3.2/32", "20.1.1.1", "core-vn", + origin_vn_path_red); + VerifyInetRouteExists("blue", "10.1.4.1/32"); + VerifyInetRouteAttributes( "blue", "10.1.4.1/32", "20.1.1.1", "core-vn", + origin_vn_path_green); + VerifyInetRouteExists("blue", "10.1.4.2/32"); + VerifyInetRouteAttributes("blue", "10.1.4.2/32", "20.1.1.1", "core-vn", + origin_vn_path_green); // Delete Ext connect routes and connected routes DeleteInetRoute(NULL, "red", "192.168.3.101/32"); @@ -3131,6 +3201,58 @@ TEST_P(ServiceChainParamTest, TransitNetworkMultipleNetworks) { DeleteConnectedRoute(3, NULL, "192.168.2.252/32"); } +// +// Instances are (blue)(blue-i1)(core-i2)(core)(core-i3)(red-i4)(red) +// VN index for blue and red is same. +// +TEST_P(ServiceChainParamTest, TransitNetworkOriginVnLoop) { + string content = + ParseConfigFile("controller/src/bgp/testdata/service_chain_test_3.xml"); + AddConnection("blue", "blue-i1"); + AddConnection("core", "core-i3"); + + // Add more specific routes to red + AddInetRoute(NULL, "red", "192.168.3.101/32", 100); + AddInetRoute(NULL, "red", "192.168.3.102/32", 100); + + // Add Ext connect routes to red + AddInetRoute(NULL, "red", "10.1.3.1/32", 100); + AddInetRoute(NULL, "red", "10.1.3.2/32", 100); + + // Add Connected routes for the 2 chains + AddConnectedRoute(1, NULL, "192.168.1.253/32", 100, "20.1.1.1"); + AddConnectedRoute(2, NULL, "192.168.2.253/32", 100, "20.1.1.2"); + + // Check for Aggregate route in core + vector origin_vn_path = list_of("red-vn"); + VerifyInetRouteExists("core", "192.168.3.0/24"); + VerifyInetRouteAttributes("core", "192.168.3.0/24", "20.1.1.2", "red-vn", + origin_vn_path); + + // Check for ExtConnect routes in core + VerifyInetRouteExists("core", "10.1.3.1/32"); + VerifyInetRouteAttributes("core", "10.1.3.1/32", "20.1.1.2", "red-vn", + origin_vn_path); + VerifyInetRouteExists("core", "10.1.3.2/32"); + VerifyInetRouteAttributes("core", "10.1.3.2/32", "20.1.1.2", "red-vn", + origin_vn_path); + + // Check for Aggregate route in blue + VerifyInetRouteNoExists("blue", "192.168.3.0/24"); + + // Check for ExtConnect routes in blue + VerifyInetRouteNoExists("blue", "10.1.3.1/32"); + VerifyInetRouteNoExists("blue", "10.1.3.2/32"); + + // Delete Ext connect routes and connected routes + DeleteInetRoute(NULL, "red", "192.168.3.101/32"); + DeleteInetRoute(NULL, "red", "192.168.3.102/32"); + DeleteInetRoute(NULL, "red", "10.1.3.1/32"); + DeleteInetRoute(NULL, "red", "10.1.3.2/32"); + DeleteConnectedRoute(1, NULL, "192.168.1.253/32"); + DeleteConnectedRoute(2, NULL, "192.168.2.253/32"); +} + INSTANTIATE_TEST_CASE_P(Instance, ServiceChainParamTest, ::testing::Combine(::testing::Bool(), ::testing::Bool())); diff --git a/src/bgp/test/svc_static_route_intergration_test.cc b/src/bgp/test/svc_static_route_intergration_test.cc index 0baea30da82..251290dd4e5 100644 --- a/src/bgp/test/svc_static_route_intergration_test.cc +++ b/src/bgp/test/svc_static_route_intergration_test.cc @@ -759,6 +759,30 @@ class ServiceChainTest : public ::testing::Test { TASK_UTIL_EXPECT_TRUE(MatchResult(server, instance, prefix, verify)); } + bool CheckServiceChainRouteOriginVnPath(BgpServerTest *server, + const string &instance, const string &prefix, + const vector &origin_vn_path) { + task_util::TaskSchedulerLock lock; + BgpRoute *route = InetRouteLookup(server, instance, prefix); + if (!route) + return false; + for (Route::PathList::const_iterator it = route->GetPathList().begin(); + it != route->GetPathList().end(); ++it) { + const BgpPath *path = static_cast(it.operator->()); + const BgpAttr *attr = path->GetAttr(); + if (GetOriginVnPathFromRoute(server, path) != origin_vn_path) + return false; + } + return true; + } + + void VerifyServiceChainRouteOriginVnPath(BgpServerTest *server, + const string &instance, const string &prefix, + const vector &origin_vn_path) { + TASK_UTIL_EXPECT_TRUE(CheckServiceChainRouteOriginVnPath( + server, instance, prefix, origin_vn_path)); + } + string FileRead(const string &filename) { ifstream file(filename.c_str()); string content((istreambuf_iterator(file)), @@ -861,6 +885,23 @@ class ServiceChainTest : public ::testing::Test { return "unresolved"; } + vector GetOriginVnPathFromRoute(BgpServerTest *server, + const BgpPath *path) { + const OriginVnPath *ovnpath = path->GetAttr()->origin_vn_path(); + assert(ovnpath); + vector result; + RoutingInstanceMgr *ri_mgr = server->routing_instance_mgr(); + BOOST_FOREACH(const ExtCommunity::ExtCommunityValue &comm, + ovnpath->origin_vns()) { + assert(ExtCommunity::is_origin_vn(comm)); + OriginVn origin_vn(comm); + string vn_name = + ri_mgr->GetVirtualNetworkByVnIndex(origin_vn.vn_index()); + result.push_back(vn_name); + } + return result; + } + SiteOfOrigin GetSiteOfOriginFromRoute(const BgpPath *path) { const ExtCommunity *ext_comm = path->GetAttr()->ext_community(); assert(ext_comm); @@ -939,14 +980,23 @@ TEST_P(ServiceIntergrationParamTest, Basic) { path_list.push_back(verify_2); } + vector origin_vn_path = list_of("red"); if (aggregate_enable_) { // Check for aggregated route VerifyServiceChainRoute(cn1_.get(), "192.168.1.0/24", path_list); VerifyServiceChainRoute(cn2_.get(), "192.168.1.0/24", path_list); + VerifyServiceChainRouteOriginVnPath( + cn1_.get(), "blue", "192.168.1.0/24", origin_vn_path); + VerifyServiceChainRouteOriginVnPath( + cn2_.get(), "blue", "192.168.1.0/24", origin_vn_path); } else { // Check for aggregated route VerifyServiceChainRoute(cn1_.get(), "192.168.1.1/32", path_list); VerifyServiceChainRoute(cn2_.get(), "192.168.1.1/32", path_list); + VerifyServiceChainRouteOriginVnPath( + cn1_.get(), "blue", "192.168.1.1/32", origin_vn_path); + VerifyServiceChainRouteOriginVnPath( + cn2_.get(), "blue", "192.168.1.1/32", origin_vn_path); } agent_a_1_->DeleteRoute("red", "192.168.1.1/32"); @@ -992,14 +1042,23 @@ TEST_P(ServiceIntergrationParamTest, ECMP) { path_list.push_back(verify_4); } + vector origin_vn_path = list_of("red"); if (aggregate_enable_) { // Check for aggregated route VerifyServiceChainRoute(cn1_.get(), "192.168.1.0/24", path_list); VerifyServiceChainRoute(cn2_.get(), "192.168.1.0/24", path_list); + VerifyServiceChainRouteOriginVnPath( + cn1_.get(), "blue", "192.168.1.0/24", origin_vn_path); + VerifyServiceChainRouteOriginVnPath( + cn2_.get(), "blue", "192.168.1.0/24", origin_vn_path); } else { // Check for aggregated route VerifyServiceChainRoute(cn1_.get(), "192.168.1.1/32", path_list); VerifyServiceChainRoute(cn2_.get(), "192.168.1.1/32", path_list); + VerifyServiceChainRouteOriginVnPath( + cn1_.get(), "blue", "192.168.1.1/32", origin_vn_path); + VerifyServiceChainRouteOriginVnPath( + cn2_.get(), "blue", "192.168.1.1/32", origin_vn_path); } agent_a_1_->DeleteRoute("red", "192.168.1.1/32"); @@ -1051,6 +1110,11 @@ TEST_P(ServiceIntergrationParamTest, ExtRoute) { // Check for ServiceChain route VerifyServiceChainRoute(cn1_.get(), "10.1.1.0/24", path_list); VerifyServiceChainRoute(cn2_.get(), "10.1.1.0/24", path_list); + vector origin_vn_path = list_of("red"); + VerifyServiceChainRouteOriginVnPath( + cn1_.get(), "blue", "10.1.1.0/24", origin_vn_path); + VerifyServiceChainRouteOriginVnPath( + cn2_.get(), "blue", "10.1.1.0/24", origin_vn_path); DeleteInetRoute(mx_.get(), NULL, "public", "10.1.1.0/24"); @@ -1106,6 +1170,11 @@ TEST_P(ServiceIntergrationParamTest, SiteOfOrigin) { // Check for ServiceChain route VerifyServiceChainRoute(cn1_.get(), "10.1.1.0/24", path_list); VerifyServiceChainRoute(cn2_.get(), "10.1.1.0/24", path_list); + vector origin_vn_path = list_of("red"); + VerifyServiceChainRouteOriginVnPath( + cn1_.get(), "blue", "10.1.1.0/24", origin_vn_path); + VerifyServiceChainRouteOriginVnPath( + cn2_.get(), "blue", "10.1.1.0/24", origin_vn_path); DeleteInetRoute(mx_.get(), NULL, "public", "10.1.1.0/24"); @@ -1485,16 +1554,36 @@ TEST_P(ServiceIntergrationParamTest3, BidirectionalChain) { pl_red.push_back(verify_red1); pl_red.push_back(verify_red2); + vector origin_vn_path_blue = list_of("blue"); + vector origin_vn_path_red = list_of("red"); if (aggregate_enable_) { VerifyServiceChainRoute(cn1_.get(), "blue", "192.168.1.0/24", pl_blue); VerifyServiceChainRoute(cn2_.get(), "blue", "192.168.1.0/24", pl_blue); + VerifyServiceChainRouteOriginVnPath( + cn1_.get(), "blue", "192.168.1.0/24", origin_vn_path_red); + VerifyServiceChainRouteOriginVnPath( + cn2_.get(), "blue", "192.168.1.0/24", origin_vn_path_red); + VerifyServiceChainRoute(cn1_.get(), "red", "192.168.0.0/24", pl_red); VerifyServiceChainRoute(cn2_.get(), "red", "192.168.0.0/24", pl_red); + VerifyServiceChainRouteOriginVnPath( + cn1_.get(), "red", "192.168.0.0/24", origin_vn_path_blue); + VerifyServiceChainRouteOriginVnPath( + cn2_.get(), "red", "192.168.0.0/24", origin_vn_path_blue); } else { VerifyServiceChainRoute(cn1_.get(), "blue", "192.168.1.1/32", pl_blue); VerifyServiceChainRoute(cn2_.get(), "blue", "192.168.1.1/32", pl_blue); + VerifyServiceChainRouteOriginVnPath( + cn1_.get(), "blue", "192.168.1.1/32", origin_vn_path_red); + VerifyServiceChainRouteOriginVnPath( + cn2_.get(), "blue", "192.168.1.1/32", origin_vn_path_red); + VerifyServiceChainRoute(cn1_.get(), "red", "192.168.0.1/32", pl_red); VerifyServiceChainRoute(cn2_.get(), "red", "192.168.0.1/32", pl_red); + VerifyServiceChainRouteOriginVnPath( + cn1_.get(), "red", "192.168.0.1/32", origin_vn_path_blue); + VerifyServiceChainRouteOriginVnPath( + cn2_.get(), "red", "192.168.0.1/32", origin_vn_path_blue); } // Delete Connected routes @@ -1550,16 +1639,36 @@ TEST_P(ServiceIntergrationParamTest3, BidirectionalChainWithTransitNetwork) { pl_red.push_back(verify_red1); pl_red.push_back(verify_red2); + vector origin_vn_path_blue = list_of("blue"); + vector origin_vn_path_red = list_of("red"); if (aggregate_enable_) { VerifyServiceChainRoute(cn1_.get(), "blue", "192.168.1.0/24", pl_blue); VerifyServiceChainRoute(cn2_.get(), "blue", "192.168.1.0/24", pl_blue); + VerifyServiceChainRouteOriginVnPath( + cn1_.get(), "blue", "192.168.1.0/24", origin_vn_path_red); + VerifyServiceChainRouteOriginVnPath( + cn2_.get(), "blue", "192.168.1.0/24", origin_vn_path_red); + VerifyServiceChainRoute(cn1_.get(), "red", "192.168.0.0/24", pl_red); VerifyServiceChainRoute(cn2_.get(), "red", "192.168.0.0/24", pl_red); + VerifyServiceChainRouteOriginVnPath( + cn1_.get(), "red", "192.168.0.0/24", origin_vn_path_blue); + VerifyServiceChainRouteOriginVnPath( + cn2_.get(), "red", "192.168.0.0/24", origin_vn_path_blue); } else { VerifyServiceChainRoute(cn1_.get(), "blue", "192.168.1.1/32", pl_blue); VerifyServiceChainRoute(cn2_.get(), "blue", "192.168.1.1/32", pl_blue); + VerifyServiceChainRouteOriginVnPath( + cn1_.get(), "blue", "192.168.1.1/32", origin_vn_path_red); + VerifyServiceChainRouteOriginVnPath( + cn2_.get(), "blue", "192.168.1.1/32", origin_vn_path_red); + VerifyServiceChainRoute(cn1_.get(), "red", "192.168.0.1/32", pl_red); VerifyServiceChainRoute(cn2_.get(), "red", "192.168.0.1/32", pl_red); + VerifyServiceChainRouteOriginVnPath( + cn1_.get(), "red", "192.168.0.1/32", origin_vn_path_blue); + VerifyServiceChainRouteOriginVnPath( + cn2_.get(), "red", "192.168.0.1/32", origin_vn_path_blue); } // Delete Connected routes diff --git a/src/bgp/testdata/service_chain_test_1.xml b/src/bgp/testdata/service_chain_test_1.xml index 223e1947372..6e80edcd7cd 100644 --- a/src/bgp/testdata/service_chain_test_1.xml +++ b/src/bgp/testdata/service_chain_test_1.xml @@ -50,4 +50,4 @@ red-vn target:1:107 - \ No newline at end of file + diff --git a/src/bgp/testdata/service_chain_test_2.xml b/src/bgp/testdata/service_chain_test_2.xml index 8b60fca25e3..ed65d7a1cb7 100644 --- a/src/bgp/testdata/service_chain_test_2.xml +++ b/src/bgp/testdata/service_chain_test_2.xml @@ -71,4 +71,4 @@ green-vn target:1:110 - \ No newline at end of file + diff --git a/src/bgp/testdata/service_chain_test_3.xml b/src/bgp/testdata/service_chain_test_3.xml new file mode 100644 index 00000000000..924dd572c23 --- /dev/null +++ b/src/bgp/testdata/service_chain_test_3.xml @@ -0,0 +1,53 @@ + + + + 3000 + + + 2000 + true + + + 3000 + + + blue-vn + target:1:101 + + + blue-vn + target:1:102 + + core + blue + 192.168.2.0/24 + 192.168.1.253 + + + + core-vn + target:1:103 + + + core-vn + target:1:104 + + + core-vn + target:1:105 + + red + core + 192.168.3.0/24 + 192.168.2.253 + + + + red-vn + target:1:106 + + + red-vn + target:1:107 + +