From f15fba4700d970fee588665624e6fb0dd8b445ab Mon Sep 17 00:00:00 2001 From: Prakash Bailkeri Date: Fri, 16 Dec 2016 23:24:21 +0530 Subject: [PATCH] xmpp message encoding for sticky and leaf flag Add support for rxing Mobility info and etree-leaf flag Add support for seding (xmpp_msg_builder) for Mobility and etree-flag Add tests for tx/rx of mobility info and etree-leaf in xmpp evpn UT Change-Id: I5b2e5847f17b0686ab7ece2325c9cb795c82f413 Related-bug: #1645092 --- src/bgp/bgp_xmpp_channel.cc | 22 ++- src/bgp/community.h | 10 ++ src/bgp/test/bgp_xmpp_evpn_test.cc | 173 +++++++++++++++++++- src/bgp/xmpp_message_builder.cc | 23 ++- src/bgp/xmpp_message_builder.h | 13 +- src/control-node/test/network_agent_mock.cc | 10 +- src/control-node/test/network_agent_mock.h | 63 +++++-- 7 files changed, 286 insertions(+), 28 deletions(-) diff --git a/src/bgp/bgp_xmpp_channel.cc b/src/bgp/bgp_xmpp_channel.cc index 34c27020633..53e6349558b 100644 --- a/src/bgp/bgp_xmpp_channel.cc +++ b/src/bgp/bgp_xmpp_channel.cc @@ -22,6 +22,7 @@ #include "bgp/bgp_xmpp_peer_close.h" #include "bgp/inet/inet_table.h" #include "bgp/inet6/inet6_table.h" +#include "bgp/extended-community/etree.h" #include "bgp/extended-community/load_balance.h" #include "bgp/extended-community/mac_mobility.h" #include "bgp/extended-community/router_mac.h" @@ -1107,7 +1108,11 @@ bool BgpXmppChannel::ProcessItem(string vrf_name, ext.communities.push_back(sg.GetExtCommunityValue()); } - if (item.entry.sequence_number) { + if (item.entry.mobility.seqno) { + MacMobility mm(item.entry.mobility.seqno, + item.entry.mobility.sticky); + ext.communities.push_back(mm.GetExtCommunityValue()); + } else if (item.entry.sequence_number) { MacMobility mm(item.entry.sequence_number); ext.communities.push_back(mm.GetExtCommunityValue()); } @@ -1386,7 +1391,11 @@ bool BgpXmppChannel::ProcessInet6Item(string vrf_name, ext.communities.push_back(sg.GetExtCommunityValue()); } - if (item.entry.sequence_number) { + if (item.entry.mobility.seqno) { + MacMobility mm(item.entry.mobility.seqno, + item.entry.mobility.sticky); + ext.communities.push_back(mm.GetExtCommunityValue()); + } else if (item.entry.sequence_number) { MacMobility mm(item.entry.sequence_number); ext.communities.push_back(mm.GetExtCommunityValue()); } @@ -1646,11 +1655,18 @@ bool BgpXmppChannel::ProcessEnetItem(string vrf_name, ext.communities.push_back(sg.GetExtCommunityValue()); } - if (item.entry.sequence_number) { + if (item.entry.mobility.seqno) { + MacMobility mm(item.entry.mobility.seqno, + item.entry.mobility.sticky); + ext.communities.push_back(mm.GetExtCommunityValue()); + } else if (item.entry.sequence_number) { MacMobility mm(item.entry.sequence_number); ext.communities.push_back(mm.GetExtCommunityValue()); } + ETree etree(item.entry.etree_leaf); + ext.communities.push_back(etree.GetExtCommunityValue()); + if (!ext.communities.empty()) attrs.push_back(&ext); diff --git a/src/bgp/community.h b/src/bgp/community.h index 4b18c274887..ac9ef3858d6 100644 --- a/src/bgp/community.h +++ b/src/bgp/community.h @@ -217,6 +217,16 @@ class ExtCommunity { (val[1] == BgpExtendedCommunityEvpnSubType::MacMobility); } + + static bool is_etree(const ExtCommunityValue &val) { + // + // ETree extended community + // + return (val[0] == BgpExtendedCommunityType::Evpn) && + (val[1] == BgpExtendedCommunityEvpnSubType::ETree); + } + + static bool is_router_mac(const ExtCommunityValue &val) { // // Router MAC extended community diff --git a/src/bgp/test/bgp_xmpp_evpn_test.cc b/src/bgp/test/bgp_xmpp_evpn_test.cc index d5dfc709908..da31afaaecb 100644 --- a/src/bgp/test/bgp_xmpp_evpn_test.cc +++ b/src/bgp/test/bgp_xmpp_evpn_test.cc @@ -1426,9 +1426,9 @@ class BgpXmppEvpnTest2 : public ::testing::Test { return true; } - bool CheckRouteLocalPrefSequence(test::NetworkAgentMockPtr agent, + bool CheckRouteLocalPrefMobilityETreeLeaf(test::NetworkAgentMockPtr agent, const string &network, const string &prefix, - int local_pref, int sequence) { + int local_pref, int sequence, bool sticky, bool leaf) { task_util::TaskSchedulerLock lock; const autogen::EnetItemType *rt = agent->EnetRouteLookup(network, prefix); @@ -1436,7 +1436,11 @@ class BgpXmppEvpnTest2 : public ::testing::Test { return false; if (rt->entry.local_preference != local_pref) return false; - if (rt->entry.sequence_number != sequence) + if (rt->entry.mobility.seqno != sequence) + return false; + if (rt->entry.mobility.sticky != sticky) + return false; + if (rt->entry.etree_leaf != leaf) return false; return true; } @@ -1455,10 +1459,20 @@ class BgpXmppEvpnTest2 : public ::testing::Test { void VerifyRouteLocalPrefSequence(test::NetworkAgentMockPtr agent, const string &network, const string &prefix, int local_pref, uint32_t sequence) { - TASK_UTIL_EXPECT_TRUE(CheckRouteLocalPrefSequence( - agent, network, prefix, local_pref, sequence)); + TASK_UTIL_EXPECT_TRUE(CheckRouteLocalPrefMobilityETreeLeaf( + agent, network, prefix, local_pref, sequence, + test::RouteAttributes::kDefaultSticky, + test::RouteAttributes::kDefaultETreeLeaf)); + } + + void VerifyRouteLocalPrefMobilityETreeLeaf(test::NetworkAgentMockPtr agent, + const string &network, const string &prefix, + int local_pref, uint32_t sequence, bool sticky, bool etree_leaf) { + TASK_UTIL_EXPECT_TRUE(CheckRouteLocalPrefMobilityETreeLeaf( + agent, network, prefix, local_pref, sequence, sticky, etree_leaf)); } + EventManager evm_; ServerThread thread_; BgpServerTestPtr bs_x_; @@ -1766,6 +1780,155 @@ TEST_F(BgpXmppEvpnTest2, RouteAddWithLocalPrefSequence) { agent_b_->SessionDown(); } +// +// Routes with mobility info from 2 agents are advertised to each other. +// +TEST_F(BgpXmppEvpnTest2, RouteAddWithStickyBit) { + Configure(); + task_util::WaitForIdle(); + + // Create XMPP Agent A connected to XMPP server X. + agent_a_.reset( + new test::NetworkAgentMock(&evm_, "agent-a", xs_x_->GetPort(), + "127.0.0.1", "127.0.0.1")); + TASK_UTIL_EXPECT_TRUE(agent_a_->IsEstablished()); + + // Create XMPP Agent B connected to XMPP server Y. + agent_b_.reset( + new test::NetworkAgentMock(&evm_, "agent-b", xs_y_->GetPort(), + "127.0.0.2", "127.0.0.2")); + TASK_UTIL_EXPECT_TRUE(agent_b_->IsEstablished()); + + // Register to blue instance + agent_a_->EnetSubscribe("blue", 1); + agent_b_->EnetSubscribe("blue", 1); + + // Add route from agent A with sticky bit and ETree Leaf mode + stringstream eroute_a; + eroute_a << "aa:00:00:00:00:01,10.1.1.1/32"; + test::NextHop nexthop1("192.168.1.1"); + test::RouteAttributes attr1(100, 100, 99, true); + agent_a_->AddEnetRoute("blue", eroute_a.str(), nexthop1, attr1); + task_util::WaitForIdle(); + + // Add route from agent B with non-sticky bit and ETree Root mode + stringstream eroute_b; + eroute_b << "bb:00:00:00:00:01,10.1.2.1/32"; + test::NextHop nexthop2("192.168.1.2"); + test::RouteAttributes attr2(100, 100, 88, false); + agent_b_->AddEnetRoute("blue", eroute_b.str(), nexthop2, attr2); + task_util::WaitForIdle(); + + // Verify that routes showed up on the agents. + TASK_UTIL_EXPECT_EQ(2, agent_a_->EnetRouteCount()); + TASK_UTIL_EXPECT_EQ(2, agent_a_->EnetRouteCount("blue")); + TASK_UTIL_EXPECT_EQ(2, agent_b_->EnetRouteCount()); + TASK_UTIL_EXPECT_EQ(2, agent_b_->EnetRouteCount("blue")); + + // Verify local pref and sequence on A. + VerifyRouteLocalPrefMobilityETreeLeaf(agent_a_, "blue", eroute_a.str(), + 100, 99, true, test::RouteAttributes::kDefaultETreeLeaf); + VerifyRouteLocalPrefMobilityETreeLeaf(agent_a_, "blue", eroute_b.str(), + 100, 88, false, test::RouteAttributes::kDefaultETreeLeaf); + + // Verify local pref and sequence on B. + VerifyRouteLocalPrefMobilityETreeLeaf(agent_b_, "blue", eroute_a.str(), + 100, 99, true, test::RouteAttributes::kDefaultETreeLeaf); + VerifyRouteLocalPrefMobilityETreeLeaf(agent_b_, "blue", eroute_b.str(), + 100, 88, false, test::RouteAttributes::kDefaultETreeLeaf); + + // Delete route from agent A. + agent_a_->DeleteEnetRoute("blue", eroute_a.str()); + task_util::WaitForIdle(); + + // Delete route from agent B. + agent_b_->DeleteEnetRoute("blue", eroute_b.str()); + task_util::WaitForIdle(); + + // Verify that there are no routes on the agents. + TASK_UTIL_EXPECT_EQ(0, agent_a_->EnetRouteCount()); + TASK_UTIL_EXPECT_EQ(0, agent_a_->EnetRouteCount("blue")); + TASK_UTIL_EXPECT_EQ(0, agent_b_->EnetRouteCount()); + TASK_UTIL_EXPECT_EQ(0, agent_b_->EnetRouteCount("blue")); + + // Close the sessions. + agent_a_->SessionDown(); + agent_b_->SessionDown(); +} + +// +// Routes with mobility info and etree-leaf info from 2 agents are +// advertised to each other. +// +TEST_F(BgpXmppEvpnTest2, RouteAddWithETreeLeaf) { + Configure(); + task_util::WaitForIdle(); + + // Create XMPP Agent A connected to XMPP server X. + agent_a_.reset( + new test::NetworkAgentMock(&evm_, "agent-a", xs_x_->GetPort(), + "127.0.0.1", "127.0.0.1")); + TASK_UTIL_EXPECT_TRUE(agent_a_->IsEstablished()); + + // Create XMPP Agent B connected to XMPP server Y. + agent_b_.reset( + new test::NetworkAgentMock(&evm_, "agent-b", xs_y_->GetPort(), + "127.0.0.2", "127.0.0.2")); + TASK_UTIL_EXPECT_TRUE(agent_b_->IsEstablished()); + + // Register to blue instance + agent_a_->EnetSubscribe("blue", 1); + agent_b_->EnetSubscribe("blue", 1); + + // Add route from agent A with sticky bit and ETree Leaf mode + stringstream eroute_a; + eroute_a << "aa:00:00:00:00:01,10.1.1.1/32"; + test::NextHop nexthop1("192.168.1.1"); + test::RouteAttributes attr1(202, 202, 2002, true, true); + agent_a_->AddEnetRoute("blue", eroute_a.str(), nexthop1, attr1); + task_util::WaitForIdle(); + + // Add route from agent B with non-sticky bit and ETree Root mode + stringstream eroute_b; + eroute_b << "bb:00:00:00:00:01,10.1.2.1/32"; + test::NextHop nexthop2("192.168.1.2"); + test::RouteAttributes attr2(202, 202, 2002, false, false); + agent_b_->AddEnetRoute("blue", eroute_b.str(), nexthop2, attr2); + task_util::WaitForIdle(); + + // Verify that routes showed up on the agents. + TASK_UTIL_EXPECT_EQ(2, agent_a_->EnetRouteCount()); + TASK_UTIL_EXPECT_EQ(2, agent_a_->EnetRouteCount("blue")); + TASK_UTIL_EXPECT_EQ(2, agent_b_->EnetRouteCount()); + TASK_UTIL_EXPECT_EQ(2, agent_b_->EnetRouteCount("blue")); + + // Verify local pref and sequence on A. + VerifyRouteLocalPrefMobilityETreeLeaf(agent_a_, "blue", eroute_a.str(), 202, 2002, true, true); + VerifyRouteLocalPrefMobilityETreeLeaf(agent_a_, "blue", eroute_b.str(), 202, 2002, false, false); + + // Verify local pref and sequence on B. + VerifyRouteLocalPrefMobilityETreeLeaf(agent_b_, "blue", eroute_a.str(), 202, 2002, true, true); + VerifyRouteLocalPrefMobilityETreeLeaf(agent_b_, "blue", eroute_b.str(), 202, 2002, false, false); + + // Delete route from agent A. + agent_a_->DeleteEnetRoute("blue", eroute_a.str()); + task_util::WaitForIdle(); + + // Delete route from agent B. + agent_b_->DeleteEnetRoute("blue", eroute_b.str()); + task_util::WaitForIdle(); + + // Verify that there are no routes on the agents. + TASK_UTIL_EXPECT_EQ(0, agent_a_->EnetRouteCount()); + TASK_UTIL_EXPECT_EQ(0, agent_a_->EnetRouteCount("blue")); + TASK_UTIL_EXPECT_EQ(0, agent_b_->EnetRouteCount()); + TASK_UTIL_EXPECT_EQ(0, agent_b_->EnetRouteCount("blue")); + + // Close the sessions. + agent_a_->SessionDown(); + agent_b_->SessionDown(); +} + // // Route from 1 agent shows up on the other. // Update route and verify the next hop and label. diff --git a/src/bgp/xmpp_message_builder.cc b/src/bgp/xmpp_message_builder.cc index 6e33313a6f8..e04013aba94 100644 --- a/src/bgp/xmpp_message_builder.cc +++ b/src/bgp/xmpp_message_builder.cc @@ -11,6 +11,7 @@ #include "bgp/ipeer.h" #include "bgp/bgp_server.h" #include "bgp/bgp_table.h" +#include "bgp/extended-community/etree.h" #include "bgp/extended-community/mac_mobility.h" #include "bgp/ermvpn/ermvpn_route.h" #include "bgp/evpn/evpn_route.h" @@ -70,7 +71,8 @@ BgpXmppMessage::BgpXmppMessage() is_reachable_(false), cache_routes_(false), repr_valid_(false), - sequence_number_(0) { + mobility_(0, false), + etree_leaf_(false) { msg_begin_.reserve(kMaxFromToLength); } @@ -191,7 +193,9 @@ void BgpXmppMessage::AddIpReach(const BgpRoute *route, item.entry.virtual_network = GetVirtualNetwork(route, roattr); item.entry.local_preference = roattr->attr()->local_pref(); item.entry.med = roattr->attr()->med(); - item.entry.sequence_number = sequence_number_; + item.entry.sequence_number = mobility_.sequence_number; + item.entry.mobility.seqno = mobility_.sequence_number; + item.entry.mobility.sticky = mobility_.sticky; assert(!roattr->nexthop_list().empty()); @@ -299,7 +303,10 @@ void BgpXmppMessage::AddEnetReach(const BgpRoute *route, item.entry.virtual_network = GetVirtualNetwork(route, roattr); item.entry.local_preference = roattr->attr()->local_pref(); item.entry.med = roattr->attr()->med(); - item.entry.sequence_number = sequence_number_; + item.entry.sequence_number = mobility_.sequence_number; + item.entry.mobility.seqno = mobility_.sequence_number; + item.entry.mobility.sticky = mobility_.sticky; + item.entry.etree_leaf = etree_leaf_; for (vector::const_iterator it = security_group_list_.begin(); it != security_group_list_.end(); ++it) { @@ -477,7 +484,9 @@ void BgpXmppMessage::ProcessCommunity(const Community *community) { } void BgpXmppMessage::ProcessExtCommunity(const ExtCommunity *ext_community) { - sequence_number_ = 0; + mobility_.sequence_number = 0; + mobility_.sticky = false; + etree_leaf_ = false; security_group_list_.clear(); load_balance_attribute_ = LoadBalance::LoadBalanceAttribute(); if (ext_community == NULL) @@ -494,10 +503,14 @@ void BgpXmppMessage::ProcessExtCommunity(const ExtCommunity *ext_community) { security_group_list_.push_back(sg.security_group_id()); } else if (ExtCommunity::is_mac_mobility(*iter)) { MacMobility mm(*iter); - sequence_number_ = mm.sequence_number(); + mobility_.sequence_number = mm.sequence_number(); + mobility_.sticky = mm.sticky(); } else if (ExtCommunity::is_load_balance(*iter)) { LoadBalance load_balance(*iter); load_balance.FillAttribute(&load_balance_attribute_); + } else if (ExtCommunity::is_etree(*iter)) { + ETree etree(*iter); + etree_leaf_ = etree.leaf(); } } } diff --git a/src/bgp/xmpp_message_builder.h b/src/bgp/xmpp_message_builder.h index 7db172decc5..1831e52976f 100644 --- a/src/bgp/xmpp_message_builder.h +++ b/src/bgp/xmpp_message_builder.h @@ -58,6 +58,15 @@ class BgpXmppMessage : public Message { std::string *repr_; }; + struct MobilityInfo { + public: + MobilityInfo(uint32_t seqno, bool sticky) + : sequence_number(seqno), sticky(sticky) { + } + uint32_t sequence_number; + bool sticky; + }; + virtual void Reset(); void EncodeNextHop(const BgpRoute *route, const RibOutAttr::NextHop &nexthop, @@ -93,7 +102,9 @@ class BgpXmppMessage : public Message { std::string msg_begin_; std::string repr_; pugi::xml_document doc_; - uint32_t sequence_number_; + MobilityInfo mobility_; + bool etree_leaf_; + std::vector security_group_list_; std::vector community_list_; LoadBalance::LoadBalanceAttribute load_balance_attribute_; diff --git a/src/control-node/test/network_agent_mock.cc b/src/control-node/test/network_agent_mock.cc index c13f6bc0b79..9b719715032 100644 --- a/src/control-node/test/network_agent_mock.cc +++ b/src/control-node/test/network_agent_mock.cc @@ -381,7 +381,8 @@ pugi::xml_document *XmppDocumentMock::RouteAddDeleteXmlDoc( if (add) { rt_entry.entry.local_preference = attributes.local_pref; rt_entry.entry.med = attributes.med; - rt_entry.entry.sequence_number = attributes.sequence; + rt_entry.entry.mobility.seqno = attributes.mobility.seqno; + rt_entry.entry.mobility.sticky = attributes.mobility.sticky; if (attributes.sgids.size()) { rt_entry.entry.security_group_list.security_group = attributes.sgids; @@ -449,7 +450,8 @@ pugi::xml_document *XmppDocumentMock::Inet6RouteAddDeleteXmlDoc( if (oper == ADD || oper == CHANGE) { rt_entry.entry.local_preference = attributes.local_pref; - rt_entry.entry.sequence_number = attributes.sequence; + rt_entry.entry.mobility.seqno = attributes.mobility.seqno; + rt_entry.entry.mobility.sticky = attributes.mobility.sticky; if (attributes.sgids.size()) { rt_entry.entry.security_group_list.security_group = attributes.sgids; @@ -617,7 +619,9 @@ pugi::xml_document *XmppDocumentMock::RouteEnetAddDeleteXmlDoc( if (add) { rt_entry.entry.local_preference = attributes.local_pref; - rt_entry.entry.sequence_number = attributes.sequence; + rt_entry.entry.etree_leaf = attributes.etree_leaf; + rt_entry.entry.mobility.seqno = attributes.mobility.seqno; + rt_entry.entry.mobility.sticky = attributes.mobility.sticky; if (attributes.sgids.size()) { rt_entry.entry.security_group_list.security_group = attributes.sgids; diff --git a/src/control-node/test/network_agent_mock.h b/src/control-node/test/network_agent_mock.h index 67174cf58c0..be0ee189366 100644 --- a/src/control-node/test/network_agent_mock.h +++ b/src/control-node/test/network_agent_mock.h @@ -56,70 +56,110 @@ struct RouteAttributes { static const int kDefaultLocalPref = 100; static const int kDefaultMed = 200; static const int kDefaultSequence = 0; + static const int kDefaultSticky = false; + static const int kDefaultETreeLeaf = false; + + struct MobilityInfo { + MobilityInfo() : seqno (kDefaultSequence), sticky(kDefaultSticky) { + } + + MobilityInfo(uint32_t seq, bool sbit) : seqno (seq), sticky(sbit) { + } + uint32_t seqno; + bool sticky; + }; + RouteAttributes() : local_pref(kDefaultLocalPref), med(kDefaultMed), - sequence(kDefaultSequence), + etree_leaf(kDefaultETreeLeaf), + mobility(kDefaultSequence, kDefaultSticky), sgids(std::vector()), communities(std::vector()) { } RouteAttributes(uint32_t lpref, uint32_t seq, const std::vector &sg) : local_pref(lpref), med(0), - sequence(seq), + etree_leaf(kDefaultETreeLeaf), + mobility(seq, kDefaultSticky), sgids(sg), communities(std::vector()) { } RouteAttributes(uint32_t lpref, uint32_t seq) : local_pref(lpref), med(0), - sequence(seq), + etree_leaf(kDefaultETreeLeaf), + mobility(seq, kDefaultSticky), sgids(std::vector()), communities(std::vector()) { } RouteAttributes(uint32_t lpref, uint32_t med, uint32_t seq) : local_pref(lpref), med(med), - sequence(seq), + etree_leaf(kDefaultETreeLeaf), + mobility(seq, kDefaultSticky), + sgids(std::vector()), + communities(std::vector()) { + } + RouteAttributes(uint32_t lpref, uint32_t med, uint32_t seq, bool sticky) + : local_pref(lpref), + med(kDefaultMed), + etree_leaf(kDefaultETreeLeaf), + mobility(seq, sticky), + sgids(std::vector()), + communities(std::vector()) { + } + RouteAttributes(uint32_t lpref, uint32_t med, uint32_t seq, bool sticky, bool leaf) + : local_pref(lpref), + med(kDefaultMed), + etree_leaf(leaf), + mobility(seq, sticky), sgids(std::vector()), communities(std::vector()) { } RouteAttributes(uint32_t lpref) : local_pref(lpref), med(0), - sequence(kDefaultSequence), + etree_leaf(kDefaultETreeLeaf), + mobility(kDefaultSequence, kDefaultSticky), sgids(std::vector()), communities(std::vector()) { } RouteAttributes(uint32_t lpref, const std::vector &sg) : local_pref(lpref), med(0), - sequence(kDefaultSequence), + etree_leaf(kDefaultETreeLeaf), + mobility(kDefaultSequence, kDefaultSticky), sgids(sg), communities(std::vector()) { } RouteAttributes(const std::vector &sg) : local_pref(kDefaultLocalPref), med(0), - sequence(kDefaultSequence), + etree_leaf(kDefaultETreeLeaf), + mobility(kDefaultSequence, kDefaultSticky), sgids(sg), communities(std::vector()) { } RouteAttributes(const std::vector &community) : local_pref(kDefaultLocalPref), med(0), - sequence(kDefaultSequence), + etree_leaf(kDefaultETreeLeaf), + mobility(kDefaultSequence, kDefaultSticky), sgids(std::vector()), communities(community) { } RouteAttributes(const LoadBalance::LoadBalanceAttribute &lba) - : local_pref(kDefaultLocalPref), med(0), sequence(kDefaultSequence), + : local_pref(kDefaultLocalPref), med(0), etree_leaf(kDefaultETreeLeaf), + mobility(kDefaultSequence, kDefaultSticky), loadBalanceAttribute(lba) { } + RouteAttributes(const RouteParams ¶ms) : local_pref(kDefaultLocalPref), med(kDefaultMed), - sequence(kDefaultSequence), + etree_leaf(kDefaultETreeLeaf), + mobility(kDefaultSequence, kDefaultSticky), params(params) { } void SetSg(const std::vector &sg) { @@ -134,7 +174,8 @@ struct RouteAttributes { uint32_t local_pref; uint32_t med; - uint32_t sequence; + bool etree_leaf; + MobilityInfo mobility; std::vector sgids; std::vector communities; LoadBalance::LoadBalanceAttribute loadBalanceAttribute;