From a2298b79102e26a6f47ac00c4bdbfa729690eb00 Mon Sep 17 00:00:00 2001 From: Prakash M Bailkeri Date: Mon, 26 Oct 2015 10:04:04 -0700 Subject: [PATCH] Community attribute to avoid re-orignating the routes Refer to https://bugs.launchpad.net/juniperopenstack/+bug/1500698 Changes made: 1. Schema changes to add new property for community list and add this property to static routes 2. XMPP message schema changes to add community to route entry 3. Handling community in Rx/Tx on bgp_xmpp_channel 4. Introduce new type for Community. 5. Avoid service chaining routes which are tagged with "no-reoriginate" community 6. UT for CommunityType, Rx/Tx of community in Xmpp messages and service chain Change-Id: If57c005fd0e6c0b9705491db2f1da81bb0920000 Related-bug:#1500698 --- src/bgp/bgp_table.cc | 7 +- src/bgp/bgp_xmpp_channel.cc | 34 ++++ src/bgp/community.cc | 21 +- src/bgp/community.h | 7 - src/bgp/routing-instance/service_chaining.cc | 8 +- src/bgp/routing-instance/static_route.cc | 3 +- src/bgp/test/bgp_attr_test.cc | 17 +- src/bgp/test/bgp_table_export_test.cc | 19 +- src/bgp/test/bgp_xmpp_inet6vpn_test.cc | 191 +++++++++++++++++++ src/bgp/test/bgp_xmpp_inetvpn_test.cc | 144 +++++++++++++- src/bgp/test/service_chain_test.cc | 72 ++++++- src/bgp/test/static_route_test.cc | 15 +- src/bgp/xmpp_message_builder.cc | 15 ++ src/control-node/test/network_agent_mock.cc | 10 + src/control-node/test/network_agent_mock.h | 29 ++- src/net/SConscript | 1 + src/net/community_type.cc | 79 ++++++++ src/net/community_type.h | 29 +++ src/net/test/SConscript | 4 + src/net/test/community_type_test.cc | 64 +++++++ src/schema/vnc_cfg.xsd | 22 +++ src/schema/xmpp_unicast.xsd | 5 + 22 files changed, 719 insertions(+), 77 deletions(-) create mode 100644 src/net/community_type.cc create mode 100644 src/net/community_type.h create mode 100644 src/net/test/community_type_test.cc diff --git a/src/bgp/bgp_table.cc b/src/bgp/bgp_table.cc index c913c3985a9..db5fc4e7045 100644 --- a/src/bgp/bgp_table.cc +++ b/src/bgp/bgp_table.cc @@ -13,6 +13,7 @@ #include "bgp/routing-instance/path_resolver.h" #include "bgp/routing-instance/routing_instance.h" #include "bgp/routing-instance/rtarget_group_mgr.h" +#include "net/community_type.h" using std::map; using std::make_pair; @@ -143,12 +144,12 @@ UpdateInfo *BgpTable::GetUpdateInfo(RibOut *ribout, BgpRoute *route, if (attr->community() != NULL && attr->community()->communities().size()) { BOOST_FOREACH(uint32_t value, attr->community()->communities()) { - if (value == Community::NoAdvertise) + if (value == CommunityType::NoAdvertise) return NULL; if ((ribout->peer_type() == BgpProto::EBGP) && - ((value == Community::NoExport) || - (value == Community::NoExportSubconfed))) { + ((value == CommunityType::NoExport) || + (value == CommunityType::NoExportSubconfed))) { return NULL; } } diff --git a/src/bgp/bgp_xmpp_channel.cc b/src/bgp/bgp_xmpp_channel.cc index d2078d7ebfc..9db5a52041f 100644 --- a/src/bgp/bgp_xmpp_channel.cc +++ b/src/bgp/bgp_xmpp_channel.cc @@ -24,6 +24,7 @@ #include "bgp/scheduling_group.h" #include "bgp/security_group/security_group.h" #include "bgp/tunnel_encap/tunnel_encap.h" +#include "net/community_type.h" #include "schema/xmpp_multicast_types.h" #include "schema/xmpp_enet_types.h" #include "xml/xml_pugi.h" @@ -43,6 +44,7 @@ using autogen::McastTunnelEncapsulationListType; using autogen::ItemType; using autogen::NextHopListType; using autogen::SecurityGroupListType; +using autogen::CommunityTagListType; using autogen::TunnelEncapsulationListType; using boost::system::error_code; @@ -1078,6 +1080,7 @@ bool BgpXmppChannel::ProcessItem(string vrf_name, uint32_t label = 0; uint32_t flags = 0; ExtCommunitySpec ext; + CommunitySpec comm; if (add_change) { req.oper = DBRequest::DB_ENTRY_ADD_CHANGE; @@ -1155,6 +1158,18 @@ bool BgpXmppChannel::ProcessItem(string vrf_name, if (med.med != 0) attrs.push_back(&med); + // Process community tags + const CommunityTagListType &ict_list = item.entry.community_tag_list; + for (CommunityTagListType::const_iterator cit = ict_list.begin(); + cit != ict_list.end(); ++cit) { + error_code error; + uint32_t rt_community = + CommunityType::CommunityFromString(*cit, &error); + if (error) + continue; + comm.communities.push_back(rt_community); + } + BgpAttrNextHop nexthop(nh_address.to_v4().to_ulong()); attrs.push_back(&nexthop); @@ -1180,6 +1195,9 @@ bool BgpXmppChannel::ProcessItem(string vrf_name, if (!load_balance.IsDefault()) ext.communities.push_back(load_balance.GetExtCommunityValue()); + if (!comm.communities.empty()) + attrs.push_back(&comm); + if (!ext.communities.empty()) attrs.push_back(&ext); @@ -1272,6 +1290,7 @@ bool BgpXmppChannel::ProcessInet6Item(string vrf_name, uint32_t label = 0; uint32_t flags = 0; ExtCommunitySpec ext; + CommunitySpec comm; if (add_change) { req.oper = DBRequest::DB_ENTRY_ADD_CHANGE; @@ -1352,6 +1371,18 @@ bool BgpXmppChannel::ProcessInet6Item(string vrf_name, if (med.med != 0) attrs.push_back(&med); + // Process community tags + const CommunityTagListType &ict_list = item.entry.community_tag_list; + for (CommunityTagListType::const_iterator cit = ict_list.begin(); + cit != ict_list.end(); ++cit) { + error_code error; + uint32_t rt_community = + CommunityType::CommunityFromString(*cit, &error); + if (error) + continue; + comm.communities.push_back(rt_community); + } + BgpAttrNextHop nexthop(nh_address.to_v4().to_ulong()); attrs.push_back(&nexthop); @@ -1377,6 +1408,9 @@ bool BgpXmppChannel::ProcessInet6Item(string vrf_name, if (!load_balance.IsDefault()) ext.communities.push_back(load_balance.GetExtCommunityValue()); + if (!comm.communities.empty()) + attrs.push_back(&comm); + if (!ext.communities.empty()) { attrs.push_back(&ext); } diff --git a/src/bgp/community.cc b/src/bgp/community.cc index ebdee536bb8..db30bc4d2d5 100644 --- a/src/bgp/community.cc +++ b/src/bgp/community.cc @@ -12,6 +12,7 @@ #include "base/string_util.h" #include "bgp/bgp_proto.h" #include "bgp/tunnel_encap/tunnel_encap.h" +#include "net/community_type.h" using std::sort; using std::string; @@ -77,25 +78,7 @@ bool Community::ContainsValue(uint32_t value) const { void Community::BuildStringList(vector *list) const { BOOST_FOREACH(uint32_t community, communities_) { - string name; - switch (community) { - case AcceptOwn: - name = "accept-own"; - break; - case NoExport: - name = "no-export"; - break; - case NoAdvertise: - name = "no-advertise"; - break; - case NoExportSubconfed: - name = "no-export-subconfed"; - break; - default: - name = integerToString(community / 65536) + ":" + - integerToString(community % 65536); - break; - } + string name = CommunityType::CommunityToString(community); list->push_back(name); } } diff --git a/src/bgp/community.h b/src/bgp/community.h index f360704aeb8..8199648fde9 100644 --- a/src/bgp/community.h +++ b/src/bgp/community.h @@ -43,13 +43,6 @@ struct CommunitySpec : public BgpAttribute { class Community { public: - enum WellKnownCommunity { - AcceptOwn = 0xFFFF0001, - NoExport = 0xFFFFFF01, - NoAdvertise = 0xFFFFFF02, - NoExportSubconfed = 0xFFFFFF03, - }; - explicit Community(CommunityDB *comm_db) : comm_db_(comm_db) { refcount_ = 0; diff --git a/src/bgp/routing-instance/service_chaining.cc b/src/bgp/routing-instance/service_chaining.cc index 8ca43b0cb5f..4db0eddd36d 100644 --- a/src/bgp/routing-instance/service_chaining.cc +++ b/src/bgp/routing-instance/service_chaining.cc @@ -18,6 +18,7 @@ #include "bgp/origin-vn/origin_vn.h" #include "bgp/routing-instance/routing_instance.h" #include "bgp/routing-instance/service_chaining_types.h" +#include "net/community_type.h" using boost::bind; using boost::system::error_code; @@ -158,8 +159,11 @@ bool ServiceChain::Match(BgpServer *server, BgpTable *table, BgpRoute *route, } else { const BgpAttr *attr = route->BestPath()->GetAttr(); const Community *comm = attr ? attr->community() : NULL; - if (comm && comm->ContainsValue(Community::NoAdvertise)) + if (comm) { + if ((comm->ContainsValue(CommunityType::NoAdvertise)) || + (comm->ContainsValue(CommunityType::NoReOriginate))) deleted = true; + } int vn_index = GetOriginVnIndex(table, route); int src_vn_index = src_->virtual_network_index(); @@ -418,7 +422,7 @@ void ServiceChain::AddServiceChainRoute(PrefixT prefix, BgpAttrDB *attr_db = server->attr_db(); CommunityDB *comm_db = server->comm_db(); CommunityPtr new_community = - comm_db->AppendAndLocate(orig_community, Community::AcceptOwn); + comm_db->AppendAndLocate(orig_community, CommunityType::AcceptOwn); ExtCommunityDB *extcomm_db = server->extcomm_db(); PeerRibMembershipManager *membership_mgr = server->membership_mgr(); OriginVnPathDB *ovnpath_db = server->ovnpath_db(); diff --git a/src/bgp/routing-instance/static_route.cc b/src/bgp/routing-instance/static_route.cc index f75c42c476f..31bc0d7eb2a 100644 --- a/src/bgp/routing-instance/static_route.cc +++ b/src/bgp/routing-instance/static_route.cc @@ -16,6 +16,7 @@ #include "bgp/l3vpn/inetvpn_route.h" #include "bgp/routing-instance/routing_instance.h" #include "bgp/routing-instance/static_route_types.h" +#include "net/community_type.h" using boost::assign::list_of; using boost::system::error_code; @@ -431,7 +432,7 @@ void StaticRoute::AddStaticRoute(NexthopPathIdList *old_path_ids) { const Community *orig_community = nexthop_route_path->GetAttr()->community(); CommunityPtr new_community = - comm_db->AppendAndLocate(orig_community, Community::AcceptOwn); + comm_db->AppendAndLocate(orig_community, CommunityType::AcceptOwn); new_attr = attr_db->ReplaceCommunityAndLocate(new_attr.get(), new_community); diff --git a/src/bgp/test/bgp_attr_test.cc b/src/bgp/test/bgp_attr_test.cc index 5a55bbd56e8..3db1a81e27c 100644 --- a/src/bgp/test/bgp_attr_test.cc +++ b/src/bgp/test/bgp_attr_test.cc @@ -13,6 +13,7 @@ #include "bgp/extended-community/mac_mobility.h" #include "bgp/origin-vn/origin_vn.h" #include "control-node/control_node.h" +#include "net/community_type.h" using boost::assign::list_of; using boost::system::error_code; @@ -314,10 +315,10 @@ TEST_F(BgpAttrTest, CommunityCompare2) { TEST_F(BgpAttrTest, CommunityBuildStringList1) { CommunitySpec spec; spec.communities.push_back(0xFFFF0000); - spec.communities.push_back(Community::AcceptOwn); - spec.communities.push_back(Community::NoExport); - spec.communities.push_back(Community::NoAdvertise); - spec.communities.push_back(Community::NoExportSubconfed); + spec.communities.push_back(CommunityType::AcceptOwn); + spec.communities.push_back(CommunityType::NoExport); + spec.communities.push_back(CommunityType::NoAdvertise); + spec.communities.push_back(CommunityType::NoExportSubconfed); Community comm(comm_db_, spec); vector expected_list = list_of("65535:0")("accept-own") @@ -329,10 +330,10 @@ TEST_F(BgpAttrTest, CommunityBuildStringList1) { TEST_F(BgpAttrTest, CommunityBuildStringList2) { CommunitySpec spec; - spec.communities.push_back(Community::NoExportSubconfed); - spec.communities.push_back(Community::NoAdvertise); - spec.communities.push_back(Community::NoExport); - spec.communities.push_back(Community::AcceptOwn); + spec.communities.push_back(CommunityType::NoExportSubconfed); + spec.communities.push_back(CommunityType::NoAdvertise); + spec.communities.push_back(CommunityType::NoExport); + spec.communities.push_back(CommunityType::AcceptOwn); spec.communities.push_back(0xFFFF0000); Community comm(comm_db_, spec); diff --git a/src/bgp/test/bgp_table_export_test.cc b/src/bgp/test/bgp_table_export_test.cc index 861226169fa..3d22ea47874 100644 --- a/src/bgp/test/bgp_table_export_test.cc +++ b/src/bgp/test/bgp_table_export_test.cc @@ -9,6 +9,7 @@ #include "bgp/test/bgp_server_test_util.h" #include "bgp/xmpp_message_builder.h" #include "control-node/control_node.h" +#include "net/community_type.h" using namespace std; @@ -397,7 +398,7 @@ TEST_P(BgpTableExportParamTest1, NoFeasiblePath) { // TEST_P(BgpTableExportParamTest1, CommunityNoAdvertise1) { CreateRibOut(BgpProto::EBGP, RibExportPolicy::BGP, 300); - SetAttrCommunity(Community::NoAdvertise); + SetAttrCommunity(CommunityType::NoAdvertise); AddPath(); RunExport(); VerifyExportReject(); @@ -411,7 +412,7 @@ TEST_P(BgpTableExportParamTest1, CommunityNoAdvertise1) { // TEST_P(BgpTableExportParamTest1, CommunityNoAdvertise2) { CreateRibOut(BgpProto::IBGP, RibExportPolicy::BGP, LocalAsNumber()); - SetAttrCommunity(Community::NoAdvertise); + SetAttrCommunity(CommunityType::NoAdvertise); AddPath(); RunExport(); VerifyExportReject(); @@ -425,7 +426,7 @@ TEST_P(BgpTableExportParamTest1, CommunityNoAdvertise2) { // TEST_P(BgpTableExportParamTest1, CommunityNoExport) { CreateRibOut(BgpProto::EBGP, RibExportPolicy::BGP, 300); - SetAttrCommunity(Community::NoExport); + SetAttrCommunity(CommunityType::NoExport); AddPath(); RunExport(); VerifyExportReject(); @@ -439,7 +440,7 @@ TEST_P(BgpTableExportParamTest1, CommunityNoExport) { // TEST_P(BgpTableExportParamTest1, CommunityNoExportSubconfed) { CreateRibOut(BgpProto::EBGP, RibExportPolicy::BGP, 300); - SetAttrCommunity(Community::NoExportSubconfed); + SetAttrCommunity(CommunityType::NoExportSubconfed); AddPath(); RunExport(); VerifyExportReject(); @@ -622,7 +623,7 @@ class BgpTableExportParamTest3 : // TEST_P(BgpTableExportParamTest3, CommunityNoExport) { CreateRibOut(BgpProto::IBGP, RibExportPolicy::BGP, LocalAsNumber()); - SetAttrCommunity(Community::NoExport); + SetAttrCommunity(CommunityType::NoExport); AddPath(); RunExport(); VerifyExportAccept(); @@ -636,7 +637,7 @@ TEST_P(BgpTableExportParamTest3, CommunityNoExport) { // TEST_P(BgpTableExportParamTest3, CommunityNoExportSubconfed) { CreateRibOut(BgpProto::IBGP, RibExportPolicy::BGP, LocalAsNumber()); - SetAttrCommunity(Community::NoExportSubconfed); + SetAttrCommunity(CommunityType::NoExportSubconfed); AddPath(); RunExport(); VerifyExportAccept(); @@ -840,7 +841,7 @@ TEST_P(BgpTableExportParamTest4b, AttrNoChange) { // Intent: NoAdvertise community is ignored if RibOut is XMPP. // TEST_P(BgpTableExportParamTest4b, CommunityNoAdvertise) { - SetAttrCommunity(Community::NoAdvertise); + SetAttrCommunity(CommunityType::NoAdvertise); AddPath(); RunExport(); VerifyExportAccept(); @@ -854,7 +855,7 @@ TEST_P(BgpTableExportParamTest4b, CommunityNoAdvertise) { // Intent: NoExport community is ignored if RibOut is XMPP. // TEST_P(BgpTableExportParamTest4b, CommunityNoExport) { - SetAttrCommunity(Community::NoExport); + SetAttrCommunity(CommunityType::NoExport); AddPath(); RunExport(); VerifyExportAccept(); @@ -868,7 +869,7 @@ TEST_P(BgpTableExportParamTest4b, CommunityNoExport) { // Intent: NoExportSubconfed community is ignored if RibOut is XMPP. // TEST_P(BgpTableExportParamTest4b, CommunityNoExportSubconfed) { - SetAttrCommunity(Community::NoExportSubconfed); + SetAttrCommunity(CommunityType::NoExportSubconfed); AddPath(); RunExport(); VerifyExportAccept(); diff --git a/src/bgp/test/bgp_xmpp_inet6vpn_test.cc b/src/bgp/test/bgp_xmpp_inet6vpn_test.cc index d624a476ac0..14ac65a5327 100644 --- a/src/bgp/test/bgp_xmpp_inet6vpn_test.cc +++ b/src/bgp/test/bgp_xmpp_inet6vpn_test.cc @@ -1219,6 +1219,41 @@ static const char *two_cns_unconnected_instances_config = "\ \ "; +static const char *config_2_control_nodes_different_asn = "\ +\ + \ + 192.168.0.1\ +
127.0.0.1
\ + 64511\ + %d\ + \ + \ + inet-vpn\ + inet6-vpn\ + \ + \ +
\ + \ + 192.168.0.2\ +
127.0.0.2
\ + 64512\ + %d\ + \ + \ + inet-vpn\ + inet6-vpn\ + \ + \ +
\ + \ + 1\ + \ + \ + blue\ + target:1:1\ + \ +
\ +"; // // Control Nodes X and Y. // Agents A and B. @@ -1384,6 +1419,24 @@ class BgpXmppInet6Test2Peers : public ::testing::Test { } } + bool VerifyRouteUpdateCommunities(string instance_name, string route, + vector& communities, test::NetworkAgentMock *agent) { + const autogen::ItemType *rt = + agent->Inet6RouteLookup(instance_name, route); + if (rt) { + vector recd_communities = + rt->entry.community_tag_list.community_tag; + if (recd_communities == communities) { + return true; + } else { + return false; + } + } else { + return false; + } + } + + bool VerifyRouteUpdateSGids(string instance_name, string route, vector& sgids, test::NetworkAgentMock *agent) { const autogen::ItemType *rt = @@ -4135,6 +4188,144 @@ TEST_F(BgpXmppInet6Test2Peers, ImportExportWithSGidAddChange) { agent_b_->SessionDown(); } +// Add route with community +TEST_F(BgpXmppInet6Test2Peers, RouteWithCommunity) { + Configure(two_cns_unconnected_instances_config); + task_util::WaitForIdle(); + + // Create XMPP Agent A connected to XMPP server 1. + agent_a_.reset( + new test::NetworkAgentMock(&evm_, "agent-a", xmpp_server1_->GetPort(), + "127.0.0.1", "127.0.0.1")); + TASK_UTIL_EXPECT_TRUE(agent_a_->IsEstablished()); + + // Create XMPP Agent B connected to XMPP server 2. + agent_b_.reset( + new test::NetworkAgentMock(&evm_, "agent-b", xmpp_server2_->GetPort(), + "127.0.0.2", "127.0.0.2")); + TASK_UTIL_EXPECT_TRUE(agent_b_->IsEstablished()); + + // Register to blue from A. + agent_a_->Inet6Subscribe("blue", 1); + + // Register to blue from B. + agent_b_->Inet6Subscribe("blue", 1); + + // Add route from agent A to blue instance. + stringstream route_a; + route_a << "2001:db8:85a3::8a2e:370:aaaa/128"; + test::NextHops nexthops_a; + nexthops_a.push_back(test::NextHop("192.168.1.1", 0)); + + vector community_a; + community_a.push_back("no-reoriginate"); + test::RouteAttributes attr_a(community_a); + agent_a_->AddInet6Route("blue", route_a.str(), nexthops_a, attr_a); + task_util::WaitForIdle(); + + // Verify that routes show up on Agent A. + TASK_UTIL_EXPECT_EQ(1, agent_a_->Inet6RouteCount()); + TASK_UTIL_EXPECT_EQ(1, agent_a_->Inet6RouteCount("blue")); + + // Verify that routes show up on Agent B. + TASK_UTIL_EXPECT_EQ(1, agent_b_->Inet6RouteCount()); + TASK_UTIL_EXPECT_EQ(1, agent_b_->Inet6RouteCount("blue")); + + // Verify the community-list at both the agents. + TASK_UTIL_EXPECT_TRUE(VerifyRouteUpdateCommunities("blue", route_a.str(), + community_a, agent_a_.get())); + TASK_UTIL_EXPECT_TRUE(VerifyRouteUpdateCommunities("blue", route_a.str(), + community_a, agent_b_.get())); + + // Add one more community to the route + community_a.push_back("64512:8888"); + attr_a.SetCommunities(community_a); + agent_a_->AddInet6Route("blue", route_a.str(), nexthops_a, attr_a); + task_util::WaitForIdle(); + + sort(community_a.begin(), community_a.end()); + + // Verify the community-list at both the agents. + TASK_UTIL_EXPECT_TRUE(VerifyRouteUpdateCommunities("blue", route_a.str(), + community_a, agent_a_.get())); + TASK_UTIL_EXPECT_TRUE(VerifyRouteUpdateCommunities("blue", route_a.str(), + community_a, agent_b_.get())); + + // Delete route + agent_a_->DeleteInet6Route("blue", route_a.str()); + task_util::WaitForIdle(); + + TASK_UTIL_EXPECT_EQ(0, agent_a_->Inet6RouteCount()); + TASK_UTIL_EXPECT_EQ(0, agent_a_->Inet6RouteCount("blue")); + TASK_UTIL_EXPECT_EQ(0, agent_b_->Inet6RouteCount()); + TASK_UTIL_EXPECT_EQ(0, agent_b_->Inet6RouteCount("blue")); + + // Close the sessions. + agent_a_->SessionDown(); + agent_b_->SessionDown(); +} + +// Add route with NO_EXPORT community and verify that route is +// not published to other control-node +TEST_F(BgpXmppInet6Test2Peers, RouteWithNoExportCommunity) { + Configure(config_2_control_nodes_different_asn); + task_util::WaitForIdle(); + + // Create XMPP Agent A connected to XMPP server 1. + agent_a_.reset( + new test::NetworkAgentMock(&evm_, "agent-a", xmpp_server1_->GetPort(), + "127.0.0.1", "127.0.0.1")); + TASK_UTIL_EXPECT_TRUE(agent_a_->IsEstablished()); + + // Create XMPP Agent B connected to XMPP server 2. + agent_b_.reset( + new test::NetworkAgentMock(&evm_, "agent-b", xmpp_server2_->GetPort(), + "127.0.0.2", "127.0.0.2")); + TASK_UTIL_EXPECT_TRUE(agent_b_->IsEstablished()); + + // Register to blue from A. + agent_a_->Inet6Subscribe("blue", 1); + + // Register to blue from B. + agent_b_->Inet6Subscribe("blue", 1); + + // Add route from agent A to blue instance. + stringstream route_a; + route_a << "2001:db8:85a3::8a2e:370:aaaa/128"; + test::NextHops nexthops_a; + nexthops_a.push_back(test::NextHop("192.168.1.1", 0)); + + vector community_a; + community_a.push_back("no-export"); + test::RouteAttributes attr_a(community_a); + agent_a_->AddInet6Route("blue", route_a.str(), nexthops_a, attr_a); + task_util::WaitForIdle(); + + // Verify that routes show up on Agent A. + TASK_UTIL_EXPECT_EQ(1, agent_a_->Inet6RouteCount()); + TASK_UTIL_EXPECT_EQ(1, agent_a_->Inet6RouteCount("blue")); + + // Verify that route doesn't show up on Agent B. + TASK_UTIL_EXPECT_EQ(0, agent_b_->Inet6RouteCount()); + TASK_UTIL_EXPECT_EQ(0, agent_b_->Inet6RouteCount("blue")); + + // Verify the community-list at agent A + TASK_UTIL_EXPECT_TRUE(VerifyRouteUpdateCommunities("blue", route_a.str(), + community_a, agent_a_.get())); + // Delete route + agent_a_->DeleteInet6Route("blue", route_a.str()); + task_util::WaitForIdle(); + + TASK_UTIL_EXPECT_EQ(0, agent_a_->Inet6RouteCount()); + TASK_UTIL_EXPECT_EQ(0, agent_a_->Inet6RouteCount("blue")); + TASK_UTIL_EXPECT_EQ(0, agent_b_->Inet6RouteCount()); + TASK_UTIL_EXPECT_EQ(0, agent_b_->Inet6RouteCount("blue")); + + // Close the sessions. + agent_a_->SessionDown(); + agent_b_->SessionDown(); +} + // Agent A adds route with sgid-lists. Agent B's xmpp session goes down, agent A // changes the route with new longer sgid-list, xmpp session comes up. TEST_F(BgpXmppInet6Test2Peers, ImportExportWithSGidAddChangeXmppDown) { diff --git a/src/bgp/test/bgp_xmpp_inetvpn_test.cc b/src/bgp/test/bgp_xmpp_inetvpn_test.cc index 33dd787da02..391854364ec 100644 --- a/src/bgp/test/bgp_xmpp_inetvpn_test.cc +++ b/src/bgp/test/bgp_xmpp_inetvpn_test.cc @@ -292,7 +292,7 @@ class BgpXmppInetvpn2ControlNodeTest : public ::testing::Test { bool CheckRoute(test::NetworkAgentMockPtr agent, string net, string prefix, string nexthop, int local_pref, int med, const string &encap, const string &origin_vn, const vector sgids, - const LoadBalance &loadBalance) { + const LoadBalance &loadBalance, const vector communities) { const autogen::ItemType *rt = agent->RouteLookup(net, prefix); if (!rt) return false; @@ -307,6 +307,9 @@ class BgpXmppInetvpn2ControlNodeTest : public ::testing::Test { if (!sgids.empty() && rt->entry.security_group_list.security_group != sgids) return false; + if (!communities.empty() && + rt->entry.community_tag_list.community_tag != communities) + return false; if (LoadBalance(rt->entry.load_balance) != loadBalance) { return false; } @@ -321,7 +324,8 @@ class BgpXmppInetvpn2ControlNodeTest : public ::testing::Test { void VerifyRouteExists(test::NetworkAgentMockPtr agent, string net, string prefix, string nexthop, int local_pref, int med) { TASK_UTIL_EXPECT_TRUE(CheckRoute(agent, net, prefix, nexthop, - local_pref, med, string(), string(), vector(), LoadBalance())); + local_pref, med, string(), string(), vector(), LoadBalance(), + vector())); } void VerifyRouteExists(test::NetworkAgentMockPtr agent, string net, @@ -331,21 +335,29 @@ class BgpXmppInetvpn2ControlNodeTest : public ::testing::Test { const LoadBalance lb = LoadBalance()) { TASK_UTIL_EXPECT_TRUE(CheckRoute( agent, net, prefix, nexthop, local_pref, 0, encap, origin_vn, - sgids, lb)); + sgids, lb, vector())); } void VerifyRouteExists(test::NetworkAgentMockPtr agent, string net, string prefix, string nexthop, const vector sgids) { TASK_UTIL_EXPECT_TRUE(CheckRoute( agent, net, prefix, nexthop, 0, 0, string(), string(), sgids, - LoadBalance())); + LoadBalance(), vector())); } void VerifyRouteExists(test::NetworkAgentMockPtr agent, string net, string prefix, string nexthop, const LoadBalance &lb) { TASK_UTIL_EXPECT_TRUE(CheckRoute( agent, net, prefix, nexthop, 0, 0, string(), string(), vector(), - lb)); + lb, vector())); + } + + + void VerifyRouteExists(test::NetworkAgentMockPtr agent, string net, + string prefix, string nexthop, const vector &communities) { + TASK_UTIL_EXPECT_TRUE(CheckRoute( + agent, net, prefix, nexthop, 0, 0, string(), string(), vector(), + LoadBalance(), communities)); } void VerifyRouteNoExists(test::NetworkAgentMockPtr agent, string net, @@ -503,6 +515,128 @@ TEST_F(BgpXmppInetvpn2ControlNodeTest, RouteChangeLocalPref) { agent_b_->SessionDown(); } +// +// Route added with community list +// +TEST_F(BgpXmppInetvpn2ControlNodeTest, RouteWithCommunity) { + Configure(config_2_control_nodes_different_asn); + 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_->Subscribe("blue", 1); + agent_b_->Subscribe("blue", 1); + + // Add route from agent A with NO_REORIGINATE community + stringstream route_a; + route_a << "10.1.1.1/32"; + + vector community_a; + community_a.push_back("no-reoriginate"); + test::RouteAttributes attr_a(community_a); + test::NextHops nexthops_a; + nexthops_a.push_back(test::NextHop("192.168.1.1", 0)); + agent_a_->AddRoute("blue", route_a.str(), nexthops_a, attr_a); + task_util::WaitForIdle(); + + // Verify that route showed up on agents A and B + VerifyRouteExists(agent_a_, "blue", route_a.str(), + "192.168.1.1", community_a); + VerifyRouteExists(agent_b_, "blue", route_a.str(), + "192.168.1.1", community_a); + + community_a.push_back("64521:9999"); + attr_a.SetCommunities(community_a); + agent_a_->AddRoute("blue", route_a.str(), nexthops_a, attr_a); + task_util::WaitForIdle(); + + sort(community_a.begin(), community_a.end()); + // Verify that route showed up on agents A & B + VerifyRouteExists(agent_a_, "blue", route_a.str(), + "192.168.1.1", community_a); + VerifyRouteExists(agent_b_, "blue", route_a.str(), + "192.168.1.1", community_a); + + // Delete route from agent A. + agent_a_->DeleteRoute("blue", route_a.str()); + task_util::WaitForIdle(); + + // Verify that route is deleted at agents A and B. + VerifyRouteNoExists(agent_a_, "blue", route_a.str()); + VerifyRouteNoExists(agent_b_, "blue", route_a.str()); + + // Close the sessions. + agent_a_->SessionDown(); + agent_b_->SessionDown(); +} + +// +// Route added with No-Export community. Validate the route advertisement in CN +// +TEST_F(BgpXmppInetvpn2ControlNodeTest, RouteWithNoExportCommunity) { + Configure(config_2_control_nodes_different_asn); + 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_->Subscribe("blue", 1); + agent_b_->Subscribe("blue", 1); + + // Add route from agent A with NO_EXPORT community + stringstream route_a; + route_a << "10.1.1.1/32"; + + vector community_a; + community_a.push_back("no-export"); + test::RouteAttributes attr_a(community_a); + test::NextHops nexthops_a; + nexthops_a.push_back(test::NextHop("192.168.1.1", 0)); + agent_a_->AddRoute("blue", route_a.str(), nexthops_a, attr_a); + task_util::WaitForIdle(); + + // Verify that route showed up on agent A + VerifyRouteExists(agent_a_, "blue", route_a.str(), + "192.168.1.1", community_a); + // Verify that route doesn't show up on agent B as it is tagged with + // "no-export" community + VerifyRouteNoExists(agent_b_, "blue", route_a.str()); + + // Delete route from agent A. + agent_a_->DeleteRoute("blue", route_a.str()); + task_util::WaitForIdle(); + + // Verify that route is deleted at agents A and B. + VerifyRouteNoExists(agent_a_, "blue", route_a.str()); + VerifyRouteNoExists(agent_b_, "blue", route_a.str()); + + // Close the sessions. + agent_a_->SessionDown(); + agent_b_->SessionDown(); +} + + // // Route added with explicit med has expected med. // diff --git a/src/bgp/test/service_chain_test.cc b/src/bgp/test/service_chain_test.cc index b59158ea41b..24f406a02e3 100644 --- a/src/bgp/test/service_chain_test.cc +++ b/src/bgp/test/service_chain_test.cc @@ -37,6 +37,7 @@ #include "ifmap/ifmap_link_table.h" #include "ifmap/ifmap_server_parser.h" #include "ifmap/test/ifmap_test_util.h" +#include "net/community_type.h" #include "schema/bgp_schema_types.h" #include "schema/vnc_cfg_types.h" @@ -708,7 +709,7 @@ class ServiceChainTest : public ::testing::Test { const string &prefix, const string &path_id, const string &origin_vn, const set tunnel_encaps) { task_util::WaitForIdle(); - vector commlist = list_of(Community::AcceptOwn); + vector commlist = list_of(CommunityType::AcceptOwn); TASK_UTIL_EXPECT_TRUE(CheckPathAttributes(instance, prefix, path_id, origin_vn, 0, vector(), tunnel_encaps, SiteOfOrigin(), commlist, vector())); @@ -753,7 +754,7 @@ class ServiceChainTest : public ::testing::Test { task_util::WaitForIdle(); vector path_ids = list_of(path_id); - vector commlist = list_of(Community::AcceptOwn); + vector commlist = list_of(CommunityType::AcceptOwn); TASK_UTIL_EXPECT_TRUE(CheckRouteAttributes( instance, prefix, path_ids, origin_vn, 0, vector(), set(), SiteOfOrigin(), commlist, vector(), lb)); @@ -764,7 +765,7 @@ class ServiceChainTest : public ::testing::Test { int label = 0) { task_util::WaitForIdle(); vector path_ids = list_of(path_id); - vector commlist = list_of(Community::AcceptOwn); + vector commlist = list_of(CommunityType::AcceptOwn); TASK_UTIL_EXPECT_TRUE(CheckRouteAttributes( instance, prefix, path_ids, origin_vn, label, vector(), set(), SiteOfOrigin(), commlist, vector())); @@ -773,7 +774,7 @@ class ServiceChainTest : public ::testing::Test { void VerifyRouteAttributes(const string &instance, const string &prefix, const vector &path_ids, const string &origin_vn) { task_util::WaitForIdle(); - vector commlist = list_of(Community::AcceptOwn); + vector commlist = list_of(CommunityType::AcceptOwn); TASK_UTIL_EXPECT_TRUE(CheckRouteAttributes( instance, prefix, path_ids, origin_vn, 0, vector(), set(), SiteOfOrigin(), commlist, vector())); @@ -784,7 +785,7 @@ class ServiceChainTest : public ::testing::Test { const vector sg_ids) { task_util::WaitForIdle(); vector path_ids = list_of(path_id); - vector commlist = list_of(Community::AcceptOwn); + vector commlist = list_of(CommunityType::AcceptOwn); TASK_UTIL_EXPECT_TRUE(CheckRouteAttributes( instance, prefix, path_ids, origin_vn, 0, sg_ids, set(), SiteOfOrigin(), commlist, vector())); @@ -795,7 +796,7 @@ class ServiceChainTest : public ::testing::Test { const set tunnel_encaps) { task_util::WaitForIdle(); vector path_ids = list_of(path_id); - vector commlist = list_of(Community::AcceptOwn); + vector commlist = list_of(CommunityType::AcceptOwn); TASK_UTIL_EXPECT_TRUE(CheckRouteAttributes( instance, prefix, path_ids, origin_vn, 0, vector(), tunnel_encaps, SiteOfOrigin(), commlist, vector())); @@ -806,7 +807,7 @@ class ServiceChainTest : public ::testing::Test { const SiteOfOrigin &soo) { task_util::WaitForIdle(); vector path_ids = list_of(path_id); - vector commlist = list_of(Community::AcceptOwn); + vector commlist = list_of(CommunityType::AcceptOwn); TASK_UTIL_EXPECT_TRUE(CheckRouteAttributes( instance, prefix, path_ids, origin_vn, 0, vector(), set(), soo, commlist, vector())); @@ -828,7 +829,7 @@ class ServiceChainTest : public ::testing::Test { const vector &origin_vn_path) { task_util::WaitForIdle(); vector path_ids = list_of(path_id); - vector commlist = list_of(Community::AcceptOwn); + vector commlist = list_of(CommunityType::AcceptOwn); TASK_UTIL_EXPECT_TRUE(CheckRouteAttributes( instance, prefix, path_ids, origin_vn, 0, vector(), set(), SiteOfOrigin(), commlist, origin_vn_path)); @@ -2569,7 +2570,7 @@ TYPED_TEST(ServiceChainTest, ExtConnectRouteNoAdvertiseCommunity) { this->VerifyRouteExists("blue", this->BuildPrefix("10.1.1.0", 24)); // Change Ext connect route to have NO_ADVERTISE community - vector commlist = list_of(Community::NoAdvertise); + vector commlist = list_of(CommunityType::NoAdvertise); this->AddRoute(NULL, "red", this->BuildPrefix("10.1.1.0", 24), 100, commlist); @@ -2589,6 +2590,57 @@ TYPED_TEST(ServiceChainTest, ExtConnectRouteNoAdvertiseCommunity) { this->DeleteConnectedRoute(NULL, this->BuildPrefix("1.1.2.3", 32)); } +// +// 1. Create Service Chain with 192.168.1.0/24 as vn subnet +// 2. Add MX leaked route 10.1.1.0/24 +// 3. Add connected route +// 4. Verify that ext connect route 10.1.1.0/24 is added +// 5. Change ext connected route to have NO_REORIGINATE community +// 6. Verify that ext connect route is removed +// 7. Change ext connected route to not have NO_REORIGINATE community +// 8. Verify that ext connect route 10.1.1.0/24 is added +// +TYPED_TEST(ServiceChainTest, ExtConnectRouteNoReOriginateCommunity) { + vector instance_names = list_of("blue")("blue-i1")("red-i2")("red"); + multimap connections = + map_list_of("blue", "blue-i1") ("red-i2", "red"); + this->NetworkConfig(instance_names, connections); + this->VerifyNetworkConfig(instance_names); + + this->SetServiceChainInformation("blue-i1", + "controller/src/bgp/testdata/service_chain_1.xml"); + + // Add Ext connect route + this->AddRoute(NULL, "red", this->BuildPrefix("10.1.1.0", 24), 100); + + // Add Connected + this->AddConnectedRoute(NULL, this->BuildPrefix("1.1.2.3", 32), 100, + this->BuildNextHopAddress("2.3.4.5")); + + // Check for ExtConnect route + this->VerifyRouteExists("blue", this->BuildPrefix("10.1.1.0", 24)); + + // Change Ext connect route to have NO_REORIGINATE community + vector commlist = list_of(CommunityType::NoReOriginate); + this->AddRoute(NULL, "red", this->BuildPrefix("10.1.1.0", 24), 100, + commlist); + + // Check for ExtConnect route + this->VerifyRouteNoExists("blue", this->BuildPrefix("10.1.1.0", 24)); + + // Change Ext connect route to not have NO_REORIGINATE community + this->AddRoute(NULL, "red", this->BuildPrefix("10.1.1.0", 24), 100); + + // Check for ExtConnect route + this->VerifyRouteExists("blue", this->BuildPrefix("10.1.1.0", 24)); + this->VerifyRouteAttributes("blue", this->BuildPrefix("10.1.1.0", 24), + this->BuildNextHopAddress("2.3.4.5"), "red"); + + // Delete ExtRoute and connected route + this->DeleteRoute(NULL, "red", this->BuildPrefix("10.1.1.0", 24)); + this->DeleteConnectedRoute(NULL, this->BuildPrefix("1.1.2.3", 32)); +} + // // 1. Create Service Chain with 192.168.1.0/24 as vn subnet // 2. Add connected route @@ -3407,7 +3459,7 @@ TYPED_TEST(ServiceChainTest, ValidateCommunityExtRoute) { // Check for ExtConnect route CommunitySpec commspec; - commspec.communities.push_back(Community::AcceptOwn); + commspec.communities.push_back(CommunityType::AcceptOwn); commspec.communities.insert( commspec.communities.end(), commlist.begin(), commlist.end()); this->VerifyRouteExists("blue", this->BuildPrefix("10.1.1.0", 24)); diff --git a/src/bgp/test/static_route_test.cc b/src/bgp/test/static_route_test.cc index 34d727b116c..1a2ca677a61 100644 --- a/src/bgp/test/static_route_test.cc +++ b/src/bgp/test/static_route_test.cc @@ -35,6 +35,7 @@ #include "ifmap/ifmap_link_table.h" #include "ifmap/ifmap_server_parser.h" #include "ifmap/test/ifmap_test_util.h" +#include "net/community_type.h" #include #include "schema/bgp_schema_types.h" #include "schema/vnc_cfg_types.h" @@ -727,7 +728,7 @@ TYPED_TEST(StaticRouteTest, Basic) { EXPECT_EQ(this->GetOriginVnFromRoute(static_path), "blue"); EXPECT_TRUE(attr->as_path() == NULL); EXPECT_TRUE(attr->community() != NULL); - EXPECT_TRUE(attr->community()->ContainsValue(Community::AcceptOwn)); + EXPECT_TRUE(attr->community()->ContainsValue(CommunityType::AcceptOwn)); static_rt = this->RouteLookup("nat", this->BuildPrefix("192.168.1.0", 24)); @@ -799,7 +800,7 @@ TYPED_TEST(StaticRouteTest, UpdateRtList) { EXPECT_EQ(this->GetOriginVnFromRoute(static_path), "blue"); EXPECT_TRUE(attr->as_path() == NULL); EXPECT_TRUE(attr->community() != NULL); - EXPECT_TRUE(attr->community()->ContainsValue(Community::AcceptOwn)); + EXPECT_TRUE(attr->community()->ContainsValue(CommunityType::AcceptOwn)); static_rt = this->RouteLookup("nat", this->BuildPrefix("192.168.1.0", 24)); @@ -832,7 +833,7 @@ TYPED_TEST(StaticRouteTest, UpdateRtList) { EXPECT_EQ(this->GetOriginVnFromRoute(static_path), "unresolved"); EXPECT_TRUE(attr->as_path() == NULL); EXPECT_TRUE(attr->community() != NULL); - EXPECT_TRUE(attr->community()->ContainsValue(Community::AcceptOwn)); + EXPECT_TRUE(attr->community()->ContainsValue(CommunityType::AcceptOwn)); // Delete nexthop route this->DeleteRoute(NULL, "nat", this->BuildPrefix("192.168.1.254", 32)); @@ -882,7 +883,7 @@ TYPED_TEST(StaticRouteTest, UpdateNexthop) { EXPECT_EQ(this->GetOriginVnFromRoute(static_path), "blue"); EXPECT_TRUE(attr->as_path() == NULL); EXPECT_TRUE(attr->community() != NULL); - EXPECT_TRUE(attr->community()->ContainsValue(Community::AcceptOwn)); + EXPECT_TRUE(attr->community()->ContainsValue(CommunityType::AcceptOwn)); static_rt = this->RouteLookup("nat", this->BuildPrefix("192.168.1.0", 24)); @@ -895,7 +896,7 @@ TYPED_TEST(StaticRouteTest, UpdateNexthop) { EXPECT_EQ(this->GetOriginVnFromRoute(static_path), "unresolved"); EXPECT_TRUE(attr->as_path() == NULL); EXPECT_TRUE(attr->community() != NULL); - EXPECT_TRUE(attr->community()->ContainsValue(Community::AcceptOwn)); + EXPECT_TRUE(attr->community()->ContainsValue(CommunityType::AcceptOwn)); params = this->GetStaticRouteConfig( "controller/src/bgp/testdata/static_route_4.xml"); @@ -928,7 +929,7 @@ TYPED_TEST(StaticRouteTest, UpdateNexthop) { EXPECT_EQ(this->GetOriginVnFromRoute(static_path), "blue"); EXPECT_TRUE(attr->as_path() == NULL); EXPECT_TRUE(attr->community() != NULL); - EXPECT_TRUE(attr->community()->ContainsValue(Community::AcceptOwn)); + EXPECT_TRUE(attr->community()->ContainsValue(CommunityType::AcceptOwn)); static_rt = this->RouteLookup("nat", this->BuildPrefix("192.168.1.0", 24)); @@ -940,7 +941,7 @@ TYPED_TEST(StaticRouteTest, UpdateNexthop) { EXPECT_EQ(this->GetOriginVnFromRoute(static_path), "unresolved"); EXPECT_TRUE(attr->as_path() == NULL); EXPECT_TRUE(attr->community() != NULL); - EXPECT_TRUE(attr->community()->ContainsValue(Community::AcceptOwn)); + EXPECT_TRUE(attr->community()->ContainsValue(CommunityType::AcceptOwn)); // Delete nexthop route this->DeleteRoute(NULL, "nat", this->BuildPrefix("192.168.1.254", 32)); diff --git a/src/bgp/xmpp_message_builder.cc b/src/bgp/xmpp_message_builder.cc index cd88a8275e3..b486fe753a4 100644 --- a/src/bgp/xmpp_message_builder.cc +++ b/src/bgp/xmpp_message_builder.cc @@ -18,6 +18,7 @@ #include "bgp/evpn/evpn_route.h" #include "bgp/origin-vn/origin_vn.h" #include "bgp/security_group/security_group.h" +#include "net/community_type.h" #include "schema/xmpp_multicast_types.h" #include "schema/xmpp_enet_types.h" #include "xmpp/xmpp_init.h" @@ -65,6 +66,13 @@ class BgpXmppMessage : public Message { void AddMcastUnreach(const BgpRoute *route); bool AddMcastRoute(const BgpRoute *route, const RibOutAttr *roattr); + void ProcessCommunity(const Community *community) { + if (community == NULL) + return; + BOOST_FOREACH(uint32_t value, community->communities()) { + community_list_.push_back(CommunityType::CommunityToString(value)); + } + } void ProcessExtCommunity(const ExtCommunity *ext_community) { if (ext_community == NULL) return; @@ -104,6 +112,7 @@ class BgpXmppMessage : public Message { uint32_t sequence_number_; string virtual_network_; vector security_group_list_; + vector community_list_; string repr_; string repr_new_; size_t repr_part1_; @@ -124,6 +133,7 @@ void BgpXmppMessage::Start(const RibOutAttr *roattr, const BgpRoute *route) { if (is_reachable_) { const BgpAttr *attr = roattr->attr(); + ProcessCommunity(attr->community()); ProcessExtCommunity(attr->ext_community()); if (virtual_network_.empty() && roattr->vrf_originated()) { virtual_network_ = @@ -215,6 +225,11 @@ void BgpXmppMessage::AddIpReach(const BgpRoute *route, item.entry.security_group_list.security_group.push_back(*it); } + for (vector::iterator it = community_list_.begin(); + it != community_list_.end(); ++it) { + item.entry.community_tag_list.community_tag.push_back(*it); + } + // Encode load balance attribute. load_balance_attribute_.Encode(&item.entry.load_balance); diff --git a/src/control-node/test/network_agent_mock.cc b/src/control-node/test/network_agent_mock.cc index 8ff1cdd30c0..2dfd6b91186 100644 --- a/src/control-node/test/network_agent_mock.cc +++ b/src/control-node/test/network_agent_mock.cc @@ -375,6 +375,11 @@ pugi::xml_document *XmppDocumentMock::RouteAddDeleteXmlDoc( rt_entry.entry.security_group_list.security_group.push_back(101); } + if (attributes.communities.size()) { + rt_entry.entry.community_tag_list.community_tag = + attributes.communities; + } + // Encode LoadBalance attribute attributes.loadBalanceAttribute.Encode(&rt_entry.entry.load_balance); @@ -438,6 +443,11 @@ pugi::xml_document *XmppDocumentMock::Inet6RouteAddDeleteXmlDoc( rt_entry.entry.security_group_list.security_group.push_back(101); } + if (attributes.communities.size()) { + rt_entry.entry.community_tag_list.community_tag = + attributes.communities; + } + // Encode LoadBalance attribute attributes.loadBalanceAttribute.Encode(&rt_entry.entry.load_balance); diff --git a/src/control-node/test/network_agent_mock.h b/src/control-node/test/network_agent_mock.h index a24fdcc381e..754e1ce4298 100644 --- a/src/control-node/test/network_agent_mock.h +++ b/src/control-node/test/network_agent_mock.h @@ -60,37 +60,50 @@ struct RouteAttributes { : local_pref(kDefaultLocalPref), med(kDefaultMed), sequence(kDefaultSequence), - sgids(std::vector()) { + sgids(std::vector()), + communities(std::vector()) { } RouteAttributes(uint32_t lpref, uint32_t seq, const std::vector &sg) : local_pref(lpref), med(0), sequence(seq), - sgids(sg) { + sgids(sg), + communities(std::vector()) { } RouteAttributes(uint32_t lpref, uint32_t seq) : local_pref(lpref), med(0), sequence(seq), - sgids(std::vector()) { + sgids(std::vector()), + communities(std::vector()) { } RouteAttributes(uint32_t lpref, uint32_t med, uint32_t seq) : local_pref(lpref), med(med), sequence(seq), - sgids(std::vector()) { + sgids(std::vector()), + communities(std::vector()) { } RouteAttributes(uint32_t lpref) : local_pref(lpref), med(0), sequence(kDefaultSequence), - sgids(std::vector()) { + sgids(std::vector()), + communities(std::vector()) { } RouteAttributes(const std::vector &sg) : local_pref(kDefaultLocalPref), med(0), sequence(kDefaultSequence), - sgids(sg) { + sgids(sg), + communities(std::vector()) { + } + RouteAttributes(const std::vector &community) + : local_pref(kDefaultLocalPref), + med(0), + sequence(kDefaultSequence), + sgids(std::vector()), + communities(community) { } RouteAttributes(const LoadBalance::LoadBalanceAttribute &lba) : local_pref(kDefaultLocalPref), sequence(kDefaultSequence), @@ -105,6 +118,9 @@ struct RouteAttributes { void SetSg(const std::vector &sg) { sgids = sg; } + void SetCommunities(const std::vector &community) { + communities = community; + } static int GetDefaultLocalPref() { return kDefaultLocalPref; } static int GetDefaultMed() { return kDefaultMed; } static int GetDefaultSequence() { return kDefaultSequence; } @@ -113,6 +129,7 @@ struct RouteAttributes { uint32_t med; uint32_t sequence; std::vector sgids; + std::vector communities; LoadBalance::LoadBalanceAttribute loadBalanceAttribute; RouteParams params; }; diff --git a/src/net/SConscript b/src/net/SConscript index 8ae86ffe239..49db9caa97e 100644 --- a/src/net/SConscript +++ b/src/net/SConscript @@ -12,6 +12,7 @@ libnet = env.Library('net', ['address.cc', 'address_util.cc', 'bgp_af.cc', + 'community_type.cc', 'esi.cc', 'mac_address.cc', 'rd.cc', diff --git a/src/net/community_type.cc b/src/net/community_type.cc new file mode 100644 index 00000000000..d691e2ca9f2 --- /dev/null +++ b/src/net/community_type.cc @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2015 Juniper Networks, Inc. All rights reserved. + */ + +#include "net/community_type.h" + +#include + +#include + +#include "base/string_util.h" + +using std::map; +using std::string; + +CommunityType::CommunityType() { +} + +static const map + fromString = boost::assign::map_list_of + ("no-advertise", CommunityType::NoAdvertise) + ("no-export", CommunityType::NoExport) + ("no-export-subconfed", CommunityType::NoExportSubconfed) + ("no-reoriginate", CommunityType::NoReOriginate) + ("accept-own", CommunityType::AcceptOwn); + +static const map + toString = boost::assign::map_list_of + (CommunityType::NoAdvertise, "no-advertise") + (CommunityType::NoReOriginate, "no-reoriginate") + (CommunityType::NoExportSubconfed, "no-export-subconfed") + (CommunityType::AcceptOwn, "accept-own") + (CommunityType::NoExport, "no-export"); + +uint32_t CommunityType::CommunityFromString( + const string &comm, boost::system::error_code *perr) { + map::const_iterator it = + fromString.find(comm); + if (it != fromString.end()) { + return it->second; + } + size_t pos = comm.rfind(':'); + if (pos == string::npos) { + if (perr != NULL) { + *perr = make_error_code(boost::system::errc::invalid_argument); + } + return 0; + } + string first(comm.substr(0, pos)); + long asn = -1; + char *endptr; + asn = strtol(first.c_str(), &endptr, 10); + if (asn >= 65535 || *endptr != '\0') { + if (perr != NULL) { + *perr = make_error_code(boost::system::errc::invalid_argument); + } + return 0; + } + string second(comm, pos + 1); + long num = -1; + num = strtol(second.c_str(), &endptr, 10); + if (num >= 65535 || *endptr != '\0') { + if (perr != NULL) { + *perr = make_error_code(boost::system::errc::invalid_argument); + } + return 0; + } + return (asn*65536 + num); +} + +const string CommunityType::CommunityToString(uint32_t comm) { + map::const_iterator it = + toString.find((CommunityType::WellKnownCommunity)comm); + if (it != toString.end()) { + return it->second; + } + return integerToString(comm / 65536) + ":" + + integerToString(comm % 65536); +} diff --git a/src/net/community_type.h b/src/net/community_type.h new file mode 100644 index 00000000000..ec64d560d34 --- /dev/null +++ b/src/net/community_type.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2015 Juniper Networks, Inc. All rights reserved. + */ + +#ifndef ctrlplane_communitytype_h +#define ctrlplane_communitytype_h + +#include +#include "base/util.h" + +class CommunityType { +public: + enum WellKnownCommunity { + AcceptOwn = 0xFFFF0001, + NoReOriginate = 0xFFFFF000, + NoExport = 0xFFFFFF01, + NoAdvertise = 0xFFFFFF02, + NoExportSubconfed = 0xFFFFFF03, + }; + + CommunityType(); + + static uint32_t CommunityFromString(const std::string &comm, + boost::system::error_code *perr = NULL); + + static const std::string CommunityToString(uint32_t comm); +}; + +#endif diff --git a/src/net/test/SConscript b/src/net/test/SConscript index 22f88f81981..8d27f485c3a 100644 --- a/src/net/test/SConscript +++ b/src/net/test/SConscript @@ -23,7 +23,11 @@ env.Alias('src/net:rd_test', rd_test) address_test = env.UnitTest('address_test', ['address_test.cc']) env.Alias('src/net:address_test', rd_test) +community_type_test = env.UnitTest('community_type_test', ['community_type_test.cc']) +env.Alias('src/net:community_type_test', community_type_test) + test_suite = [ + community_type_test, esi_test, mac_address_test, rd_test, diff --git a/src/net/test/community_type_test.cc b/src/net/test/community_type_test.cc new file mode 100644 index 00000000000..d153f52f134 --- /dev/null +++ b/src/net/test/community_type_test.cc @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved. + */ + +#include "net/community_type.h" + +#include "base/logging.h" +#include "testing/gunit.h" + +using namespace std; + +class CommunityTypeTest : public ::testing::Test { +}; + +TEST_F(CommunityTypeTest, FromString_0) { + std::string str = "no-export"; + uint32_t community = CommunityType::CommunityFromString(str); + std::string result = CommunityType::CommunityToString(community); + EXPECT_EQ(str, result); +} + +TEST_F(CommunityTypeTest, FromString_1) { + std::string str = "1234:1234"; + uint32_t community = CommunityType::CommunityFromString(str); + std::string result = CommunityType::CommunityToString(community); + EXPECT_EQ(str, result); +} + +TEST_F(CommunityTypeTest, FromString_2) { + std::string str = "65535:1"; + boost::system::error_code ec; + uint32_t community = CommunityType::CommunityFromString(str, &ec); + EXPECT_NE(0, ec.value()); + EXPECT_EQ(community, 0x0); +} + +TEST_F(CommunityTypeTest, FromString_3) { + std::string str = "accept-own"; + boost::system::error_code ec; + uint32_t community = CommunityType::CommunityFromString(str, &ec); + EXPECT_EQ(0, ec.value()); + EXPECT_EQ(community, 0xFFFF0001); +} + +TEST_F(CommunityTypeTest, ToString_0) { + uint32_t comm = 0x00020001; + boost::system::error_code ec; + std::string community = CommunityType::CommunityToString(comm); + uint32_t result = CommunityType::CommunityFromString(community, &ec); + EXPECT_EQ(0, ec.value()); + EXPECT_EQ(result, comm); +} + +TEST_F(CommunityTypeTest, ToString_1) { + uint32_t comm = 0xFFFF0001; + std::string community = CommunityType::CommunityToString(comm); + EXPECT_EQ(community, "accept-own"); +} + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + int result = RUN_ALL_TESTS(); + return result; +} diff --git a/src/schema/vnc_cfg.xsd b/src/schema/vnc_cfg.xsd index aa9d12cbff1..73a47f3e053 100644 --- a/src/schema/vnc_cfg.xsd +++ b/src/schema/vnc_cfg.xsd @@ -1511,11 +1511,33 @@ targetNamespace="http://www.contrailsystems.com/2012/VNC-CONFIG/0"> + + + + List of Community attributes + This list indicates the attributes with which routes are tagged while + publishing. The attributes will be represented as bgp community in + the path attribute. Each attribute is indicated as string + 1. String with two integer seperated by ':'. E.g. "64512:123" + 2. Wellknown community as string. Possible values are + "no-export" + "accept-own" + "no-advertise" + "no-export-subconfed" + "no-reoriginate" + + + + + + + + diff --git a/src/schema/xmpp_unicast.xsd b/src/schema/xmpp_unicast.xsd index a62b785c210..c6500a1afc2 100644 --- a/src/schema/xmpp_unicast.xsd +++ b/src/schema/xmpp_unicast.xsd @@ -38,6 +38,10 @@ xsd:targetNamespace="http://www.contrailsystems.com/bgp-l3vpn-unicast-cfg.xsd"> + + + + @@ -74,6 +78,7 @@ xsd:targetNamespace="http://www.contrailsystems.com/bgp-l3vpn-unicast-cfg.xsd"> +