From 5cf95b2169e479492eb866a89f60544bc9d06eb0 Mon Sep 17 00:00:00 2001 From: Nischal Sheth Date: Thu, 11 Jun 2015 17:27:15 -0700 Subject: [PATCH] Use label as 24-bit field when encoding/decoding VNI Change-Id: I60cdae79cf4a8b60ebb9ed271ccafca4193d4a91 Closes-Bug: 1464781 --- src/bgp/bgp_attr_base.cc | 20 +- src/bgp/bgp_attr_base.h | 4 +- src/bgp/community.cc | 14 ++ src/bgp/community.h | 1 + src/bgp/evpn/evpn_route.cc | 46 +++- src/bgp/evpn/test/evpn_prefix_test.cc | 323 ++++++++++++++++++++++++++ 6 files changed, 394 insertions(+), 14 deletions(-) diff --git a/src/bgp/bgp_attr_base.cc b/src/bgp/bgp_attr_base.cc index b341eeb626b..cbd636d0213 100644 --- a/src/bgp/bgp_attr_base.cc +++ b/src/bgp/bgp_attr_base.cc @@ -12,16 +12,32 @@ const size_t BgpProtoPrefix::kLabelSize = 3; BgpProtoPrefix::BgpProtoPrefix() : prefixlen(0), type(0) { } -uint32_t BgpProtoPrefix::ReadLabel(size_t label_offset) const { +// +// Extract the label from the BgpProtorefix. +// EVPN extensions for VXLAN use the label to convey a 24-bit VNI. +// +uint32_t BgpProtoPrefix::ReadLabel(size_t label_offset, bool is_vni) const { assert((label_offset + kLabelSize) <= prefix.size()); + if (is_vni) + return get_value(&prefix[label_offset], kLabelSize); uint32_t label = (prefix[label_offset] << 16 | prefix[label_offset + 1] << 8 | prefix[label_offset + 2]) >> 4; return label; } -void BgpProtoPrefix::WriteLabel(size_t label_offset, uint32_t label) { +// +// Write the label to the BgpProtorefix. +// EVPN extensions for VXLAN use the label to convey a 24-bit VNI. +// +void BgpProtoPrefix::WriteLabel(size_t label_offset, uint32_t label, + bool is_vni) { assert((label_offset + kLabelSize) <= prefix.size()); + if (is_vni) { + assert(label <= 0xFFFFFF); + put_value(&prefix[label_offset], kLabelSize, label); + return; + } assert(label <= 0xFFFFF); uint32_t tmp = (label << 4 | 0x1); for (size_t idx = 0; idx < kLabelSize; ++idx) { diff --git a/src/bgp/bgp_attr_base.h b/src/bgp/bgp_attr_base.h index ab44a6b7256..0c3241765b0 100644 --- a/src/bgp/bgp_attr_base.h +++ b/src/bgp/bgp_attr_base.h @@ -96,8 +96,8 @@ struct BgpProtoPrefix : public ParseObject { BgpProtoPrefix(); - uint32_t ReadLabel(size_t label_offset) const; - void WriteLabel(size_t label_offset, uint32_t label); + uint32_t ReadLabel(size_t label_offset, bool is_vni = false) const; + void WriteLabel(size_t label_offset, uint32_t label, bool is_vni = false); std::vector prefix; int prefixlen; diff --git a/src/bgp/community.cc b/src/bgp/community.cc index 50403e7392e..a7a00d3e702 100644 --- a/src/bgp/community.cc +++ b/src/bgp/community.cc @@ -212,6 +212,20 @@ vector ExtCommunity::GetTunnelEncap() const { return encap_list; } +bool ExtCommunity::ContainsTunnelEncapVxlan() const { + for (ExtCommunityList::const_iterator iter = communities_.begin(); + iter != communities_.end(); ++iter) { + if (!ExtCommunity::is_tunnel_encap(*iter)) + continue; + TunnelEncap encap(*iter); + if (encap.tunnel_encap() == TunnelEncapType::VXLAN) + return true; + if (encap.tunnel_encap() == TunnelEncapType::VXLAN_CONTRAIL) + return true; + } + return false; +} + ExtCommunity::ExtCommunity(ExtCommunityDB *extcomm_db, const ExtCommunitySpec spec) : extcomm_db_(extcomm_db) { refcount_ = 0; diff --git a/src/bgp/community.h b/src/bgp/community.h index 1722361d941..2d408d36773 100644 --- a/src/bgp/community.h +++ b/src/bgp/community.h @@ -163,6 +163,7 @@ class ExtCommunity { } std::vector GetTunnelEncap() const; + bool ContainsTunnelEncapVxlan() const; static bool is_origin_vn(const ExtCommunityValue &val) { // diff --git a/src/bgp/evpn/evpn_route.cc b/src/bgp/evpn/evpn_route.cc index a4e585dc633..1ea5aa47680 100644 --- a/src/bgp/evpn/evpn_route.cc +++ b/src/bgp/evpn/evpn_route.cc @@ -34,6 +34,36 @@ const size_t EvpnPrefix::kMinInclusiveMulticastRouteSize = const size_t EvpnPrefix::kMinSegmentRouteSize = kRdSize + kEsiSize + 1; +// +// Read label from the BgpProtoPrefix. +// If the encapsulation is VXLAN and ethernet tag is non-zero use that as +// the label for backward compatibility with older JUNOS code. +// +static uint32_t ReadLabel(const BgpProtoPrefix &proto_prefix, + const BgpAttr *attr, size_t offset, uint32_t tag) { + if (!attr) + return 0; + const ExtCommunity *extcomm = attr->ext_community(); + if (extcomm && extcomm->ContainsTunnelEncapVxlan()) { + return (tag ? tag : proto_prefix.ReadLabel(offset, true)); + } else { + return proto_prefix.ReadLabel(offset, false); + } +} + +// +// Write label to the BgpProtoPrefix. +// +static void WriteLabel(BgpProtoPrefix *proto_prefix, + const BgpAttr *attr, size_t offset, uint32_t label) { + const ExtCommunity *extcomm = attr ? attr->ext_community() : NULL; + if (extcomm && extcomm->ContainsTunnelEncapVxlan()) { + proto_prefix->WriteLabel(offset, label, true); + } else { + proto_prefix->WriteLabel(offset, label, false); + } +} + EvpnPrefix::EvpnPrefix() : type_(Unspecified), tag_(EvpnPrefix::kNullTag), family_(Address::UNSPEC) { } @@ -111,10 +141,8 @@ int EvpnPrefix::FromProtoPrefix(BgpServer *server, prefix->esi_ = EthernetSegmentId(&proto_prefix.prefix[esi_offset]); size_t tag_offset = esi_offset + kEsiSize; prefix->tag_ = get_value(&proto_prefix.prefix[tag_offset], kTagSize); - if (attr) { - size_t label_offset = tag_offset + kTagSize; - *label = proto_prefix.ReadLabel(label_offset); - } + size_t label_offset = tag_offset + kTagSize; + *label = ReadLabel(proto_prefix, attr, label_offset, prefix->tag_); break; } case MacAdvertisementRoute: { @@ -146,10 +174,8 @@ int EvpnPrefix::FromProtoPrefix(BgpServer *server, return -1; size_t ip_offset = ip_len_offset + 1; prefix->ReadIpAddress(proto_prefix, ip_offset, ip_size); - if (attr) { - size_t label_offset = ip_offset + ip_size; - *label = proto_prefix.ReadLabel(label_offset); - } + size_t label_offset = ip_offset + ip_size; + *label = ReadLabel(proto_prefix, attr, label_offset, prefix->tag_); break; } case InclusiveMulticastRoute: { @@ -231,7 +257,7 @@ void EvpnPrefix::BuildProtoPrefix(const BgpAttr *attr, uint32_t label, size_t tag_offset = esi_offset + kEsiSize; put_value(&proto_prefix->prefix[tag_offset], kTagSize, tag_); size_t label_offset = tag_offset + kTagSize; - proto_prefix->WriteLabel(label_offset, label); + WriteLabel(proto_prefix, attr, label_offset, label); break; } case MacAdvertisementRoute: { @@ -260,7 +286,7 @@ void EvpnPrefix::BuildProtoPrefix(const BgpAttr *attr, uint32_t label, size_t ip_offset = ip_len_offset + 1; WriteIpAddress(proto_prefix, ip_offset); size_t label_offset = ip_offset + ip_size; - proto_prefix->WriteLabel(label_offset, label); + WriteLabel(proto_prefix, attr, label_offset, label); break; } case InclusiveMulticastRoute: { diff --git a/src/bgp/evpn/test/evpn_prefix_test.cc b/src/bgp/evpn/test/evpn_prefix_test.cc index 80bf0a822f5..50dcf9df4ce 100644 --- a/src/bgp/evpn/test/evpn_prefix_test.cc +++ b/src/bgp/evpn/test/evpn_prefix_test.cc @@ -10,6 +10,7 @@ #include "bgp/evpn/evpn_route.h" #include "bgp/evpn/evpn_table.h" #include "bgp/test/bgp_server_test_util.h" +#include "bgp/tunnel_encap/tunnel_encap.h" #include "control-node/control_node.h" #include "testing/gunit.h" @@ -242,6 +243,85 @@ TEST_F(EvpnAutoDiscoveryPrefixTest, FromProtoPrefix2) { } } +// Build and parse BgpProtoPrefix for reach with VXLAN encap. +// Tag is not 0, so label should be ignored. +TEST_F(EvpnAutoDiscoveryPrefixTest, FromProtoPrefix3) { + string temp("1-10.1.1.1:65535-00:01:02:03:04:05:06:07:08:09-"); + uint32_t tag_list[] = { 32, 10000, 1048575, 16777215 }; + BOOST_FOREACH(uint32_t tag, tag_list) { + string prefix_str = temp + integerToString(tag); + boost::system::error_code ec; + EvpnPrefix prefix1(EvpnPrefix::FromString(prefix_str, &ec)); + EXPECT_EQ(0, ec.value()); + + TunnelEncap tunnel_encap(TunnelEncapType::VXLAN); + ExtCommunitySpec comm_spec; + comm_spec.communities.push_back(tunnel_encap.GetExtCommunityValue()); + BgpAttrSpec attr_spec; + attr_spec.push_back(&comm_spec); + BgpAttrPtr attr = bs_->attr_db()->Locate(attr_spec); + + uint32_t label1 = 10000; + BgpProtoPrefix proto_prefix; + prefix1.BuildProtoPrefix(attr.get(), label1, &proto_prefix); + EXPECT_EQ(EvpnPrefix::AutoDiscoveryRoute, proto_prefix.type); + size_t expected_size = + EvpnPrefix::kMinAutoDiscoveryRouteSize + EvpnPrefix::kLabelSize; + EXPECT_EQ(expected_size * 8, proto_prefix.prefixlen); + EXPECT_EQ(expected_size, proto_prefix.prefix.size()); + + EvpnPrefix prefix2; + BgpAttrPtr attr_out2; + uint32_t label2; + int result = EvpnPrefix::FromProtoPrefix(bs_.get(), + proto_prefix, attr.get(), &prefix2, &attr_out2, &label2); + EXPECT_EQ(0, result); + EXPECT_EQ(prefix1, prefix2); + EXPECT_TRUE(attr_out2->esi().IsZero()); + EXPECT_EQ(attr.get(), attr_out2.get()); + EXPECT_EQ(tag, label2); + } +} + +// Build and parse BgpProtoPrefix for reach with VXLAN encap. +// Tag is 0, so label should be honored. +TEST_F(EvpnAutoDiscoveryPrefixTest, FromProtoPrefix4) { + string temp("1-10.1.1.1:65535-00:01:02:03:04:05:06:07:08:09-"); + uint32_t label_list[] = { 32, 10000, 1048575, 16777215 }; + BOOST_FOREACH(uint32_t label1, label_list) { + string prefix_str = temp + integerToString(0); + boost::system::error_code ec; + EvpnPrefix prefix1(EvpnPrefix::FromString(prefix_str, &ec)); + EXPECT_EQ(0, ec.value()); + + TunnelEncap tunnel_encap(TunnelEncapType::VXLAN); + ExtCommunitySpec comm_spec; + comm_spec.communities.push_back(tunnel_encap.GetExtCommunityValue()); + BgpAttrSpec attr_spec; + attr_spec.push_back(&comm_spec); + BgpAttrPtr attr = bs_->attr_db()->Locate(attr_spec); + + BgpProtoPrefix proto_prefix; + prefix1.BuildProtoPrefix(attr.get(), label1, &proto_prefix); + EXPECT_EQ(EvpnPrefix::AutoDiscoveryRoute, proto_prefix.type); + size_t expected_size = + EvpnPrefix::kMinAutoDiscoveryRouteSize + EvpnPrefix::kLabelSize; + EXPECT_EQ(expected_size * 8, proto_prefix.prefixlen); + EXPECT_EQ(expected_size, proto_prefix.prefix.size()); + + EvpnPrefix prefix2; + BgpAttrPtr attr_out2; + uint32_t label2; + int result = EvpnPrefix::FromProtoPrefix(bs_.get(), + proto_prefix, attr.get(), &prefix2, &attr_out2, &label2); + EXPECT_EQ(0, result); + EXPECT_EQ(prefix1, prefix2); + EXPECT_TRUE(attr_out2->esi().IsZero()); + EXPECT_EQ(attr.get(), attr_out2.get()); + EXPECT_EQ(label1, label2); + } +} + // Smaller than minimum size for reach. TEST_F(EvpnAutoDiscoveryPrefixTest, FromProtoPrefix_Error1) { BgpProtoPrefix proto_prefix; @@ -771,6 +851,249 @@ TEST_F(EvpnMacAdvertisementPrefixTest, FromProtoPrefix6) { } } +// Build and parse BgpProtoPrefix for reach with VXLAN encap, w/o ip. +// Tag is not 0, so label should be ignored. +TEST_F(EvpnMacAdvertisementPrefixTest, FromProtoPrefix7) { + string temp1("2-10.1.1.1:65535-"); + string temp2("-11:12:13:14:15:16,0.0.0.0"); + uint32_t tag_list[] = { 32, 10000, 1048575, 16777215 }; + BOOST_FOREACH(uint32_t tag, tag_list) { + string prefix_str = temp1 + integerToString(tag) + temp2; + boost::system::error_code ec; + EvpnPrefix prefix1(EvpnPrefix::FromString(prefix_str, &ec)); + EXPECT_EQ(0, ec.value()); + + TunnelEncap tunnel_encap(TunnelEncapType::VXLAN); + ExtCommunitySpec comm_spec; + comm_spec.communities.push_back(tunnel_encap.GetExtCommunityValue()); + BgpAttrSpec attr_spec; + attr_spec.push_back(&comm_spec); + BgpAttrPtr attr = bs_->attr_db()->Locate(attr_spec); + + uint32_t label1 = 10000; + BgpProtoPrefix proto_prefix; + prefix1.BuildProtoPrefix(attr.get(), label1, &proto_prefix); + EXPECT_EQ(EvpnPrefix::MacAdvertisementRoute, proto_prefix.type); + size_t expected_size = + EvpnPrefix::kMinMacAdvertisementRouteSize + EvpnPrefix::kLabelSize; + EXPECT_EQ(expected_size * 8, proto_prefix.prefixlen); + EXPECT_EQ(expected_size, proto_prefix.prefix.size()); + + EvpnPrefix prefix2; + BgpAttrPtr attr_out2; + uint32_t label2; + int result = EvpnPrefix::FromProtoPrefix(bs_.get(), + proto_prefix, attr.get(), &prefix2, &attr_out2, &label2); + EXPECT_EQ(0, result); + EXPECT_EQ(prefix1, prefix2); + EXPECT_TRUE(prefix2.esi().IsZero()); + EXPECT_EQ(attr.get(), attr_out2.get()); + EXPECT_EQ(tag, label2); + } +} + +// Build and parse BgpProtoPrefix for reach with VXLAN encap, w/o ip. +// Tag is 0, so label should be honored. +TEST_F(EvpnMacAdvertisementPrefixTest, FromProtoPrefix8) { + string temp1("2-10.1.1.1:65535-"); + string temp2("-11:12:13:14:15:16,0.0.0.0"); + uint32_t label_list[] = { 32, 10000, 1048575, 16777215 }; + BOOST_FOREACH(uint32_t label1, label_list) { + string prefix_str = temp1 + integerToString(0) + temp2; + boost::system::error_code ec; + EvpnPrefix prefix1(EvpnPrefix::FromString(prefix_str, &ec)); + EXPECT_EQ(0, ec.value()); + + TunnelEncap tunnel_encap(TunnelEncapType::VXLAN); + ExtCommunitySpec comm_spec; + comm_spec.communities.push_back(tunnel_encap.GetExtCommunityValue()); + BgpAttrSpec attr_spec; + attr_spec.push_back(&comm_spec); + BgpAttrPtr attr = bs_->attr_db()->Locate(attr_spec); + + BgpProtoPrefix proto_prefix; + prefix1.BuildProtoPrefix(attr.get(), label1, &proto_prefix); + EXPECT_EQ(EvpnPrefix::MacAdvertisementRoute, proto_prefix.type); + size_t expected_size = + EvpnPrefix::kMinMacAdvertisementRouteSize + EvpnPrefix::kLabelSize; + EXPECT_EQ(expected_size * 8, proto_prefix.prefixlen); + EXPECT_EQ(expected_size, proto_prefix.prefix.size()); + + EvpnPrefix prefix2; + BgpAttrPtr attr_out2; + uint32_t label2; + int result = EvpnPrefix::FromProtoPrefix(bs_.get(), + proto_prefix, attr.get(), &prefix2, &attr_out2, &label2); + EXPECT_EQ(0, result); + EXPECT_EQ(prefix1, prefix2); + EXPECT_TRUE(prefix2.esi().IsZero()); + EXPECT_EQ(attr.get(), attr_out2.get()); + EXPECT_EQ(label1, label2); + } +} + +// Build and parse BgpProtoPrefix for reach with VXLAN encap, w/ ipv4. +// Tag is not 0, so label should be ignored. +TEST_F(EvpnMacAdvertisementPrefixTest, FromProtoPrefix9) { + string temp1("2-10.1.1.1:65535-"); + string temp2("-11:12:13:14:15:16,192.1.1.1"); + uint32_t tag_list[] = { 32, 10000, 1048575, 16777215 }; + BOOST_FOREACH(uint32_t tag, tag_list) { + string prefix_str = temp1 + integerToString(tag) + temp2; + boost::system::error_code ec; + EvpnPrefix prefix1(EvpnPrefix::FromString(prefix_str, &ec)); + EXPECT_EQ(0, ec.value()); + + TunnelEncap tunnel_encap(TunnelEncapType::VXLAN); + ExtCommunitySpec comm_spec; + comm_spec.communities.push_back(tunnel_encap.GetExtCommunityValue()); + BgpAttrSpec attr_spec; + attr_spec.push_back(&comm_spec); + BgpAttrPtr attr = bs_->attr_db()->Locate(attr_spec); + + uint32_t label1 = 10000; + BgpProtoPrefix proto_prefix; + prefix1.BuildProtoPrefix(attr.get(), label1, &proto_prefix); + EXPECT_EQ(EvpnPrefix::MacAdvertisementRoute, proto_prefix.type); + size_t expected_size = + EvpnPrefix::kMinMacAdvertisementRouteSize + EvpnPrefix::kLabelSize + 4; + EXPECT_EQ(expected_size * 8, proto_prefix.prefixlen); + EXPECT_EQ(expected_size, proto_prefix.prefix.size()); + + EvpnPrefix prefix2; + BgpAttrPtr attr_out2; + uint32_t label2; + int result = EvpnPrefix::FromProtoPrefix(bs_.get(), + proto_prefix, attr.get(), &prefix2, &attr_out2, &label2); + EXPECT_EQ(0, result); + EXPECT_EQ(prefix1, prefix2); + EXPECT_TRUE(prefix2.esi().IsZero()); + EXPECT_EQ(attr.get(), attr_out2.get()); + EXPECT_EQ(tag, label2); + } +} + +// Build and parse BgpProtoPrefix for reach with VXLAN encap, w/ ipv4. +// Tag is 0, so label should be honored. +TEST_F(EvpnMacAdvertisementPrefixTest, FromProtoPrefix10) { + string temp1("2-10.1.1.1:65535-"); + string temp2("-11:12:13:14:15:16,192.1.1.1"); + uint32_t label_list[] = { 32, 10000, 1048575, 16777215 }; + BOOST_FOREACH(uint32_t label1, label_list) { + string prefix_str = temp1 + integerToString(0) + temp2; + boost::system::error_code ec; + EvpnPrefix prefix1(EvpnPrefix::FromString(prefix_str, &ec)); + EXPECT_EQ(0, ec.value()); + + TunnelEncap tunnel_encap(TunnelEncapType::VXLAN); + ExtCommunitySpec comm_spec; + comm_spec.communities.push_back(tunnel_encap.GetExtCommunityValue()); + BgpAttrSpec attr_spec; + attr_spec.push_back(&comm_spec); + BgpAttrPtr attr = bs_->attr_db()->Locate(attr_spec); + + BgpProtoPrefix proto_prefix; + prefix1.BuildProtoPrefix(attr.get(), label1, &proto_prefix); + EXPECT_EQ(EvpnPrefix::MacAdvertisementRoute, proto_prefix.type); + size_t expected_size = + EvpnPrefix::kMinMacAdvertisementRouteSize + EvpnPrefix::kLabelSize + 4; + EXPECT_EQ(expected_size * 8, proto_prefix.prefixlen); + EXPECT_EQ(expected_size, proto_prefix.prefix.size()); + + EvpnPrefix prefix2; + BgpAttrPtr attr_out2; + uint32_t label2; + int result = EvpnPrefix::FromProtoPrefix(bs_.get(), + proto_prefix, attr.get(), &prefix2, &attr_out2, &label2); + EXPECT_EQ(0, result); + EXPECT_EQ(prefix1, prefix2); + EXPECT_TRUE(prefix2.esi().IsZero()); + EXPECT_EQ(attr.get(), attr_out2.get()); + EXPECT_EQ(label1, label2); + } +} + +// Build and parse BgpProtoPrefix for reach with VXLAN encap, w/ ipv6. +// Tag is not 0, so label should be ignored. +TEST_F(EvpnMacAdvertisementPrefixTest, FromProtoPrefix11) { + string temp1("2-10.1.1.1:65535-"); + string temp2("-11:12:13:14:15:16,2001:db8:0:9::1"); + uint32_t tag_list[] = { 32, 10000, 1048575, 16777215 }; + BOOST_FOREACH(uint32_t tag, tag_list) { + string prefix_str = temp1 + integerToString(tag) + temp2; + boost::system::error_code ec; + EvpnPrefix prefix1(EvpnPrefix::FromString(prefix_str, &ec)); + EXPECT_EQ(0, ec.value()); + + TunnelEncap tunnel_encap(TunnelEncapType::VXLAN); + ExtCommunitySpec comm_spec; + comm_spec.communities.push_back(tunnel_encap.GetExtCommunityValue()); + BgpAttrSpec attr_spec; + attr_spec.push_back(&comm_spec); + BgpAttrPtr attr = bs_->attr_db()->Locate(attr_spec); + + uint32_t label1 = 10000; + BgpProtoPrefix proto_prefix; + prefix1.BuildProtoPrefix(attr.get(), label1, &proto_prefix); + EXPECT_EQ(EvpnPrefix::MacAdvertisementRoute, proto_prefix.type); + size_t expected_size = + EvpnPrefix::kMinMacAdvertisementRouteSize + EvpnPrefix::kLabelSize + 16; + EXPECT_EQ(expected_size * 8, proto_prefix.prefixlen); + EXPECT_EQ(expected_size, proto_prefix.prefix.size()); + + EvpnPrefix prefix2; + BgpAttrPtr attr_out2; + uint32_t label2; + int result = EvpnPrefix::FromProtoPrefix(bs_.get(), + proto_prefix, attr.get(), &prefix2, &attr_out2, &label2); + EXPECT_EQ(0, result); + EXPECT_EQ(prefix1, prefix2); + EXPECT_TRUE(prefix2.esi().IsZero()); + EXPECT_EQ(attr.get(), attr_out2.get()); + EXPECT_EQ(tag, label2); + } +} + +// Build and parse BgpProtoPrefix for reach with VXLAN encap, w/ ipv6. +// Tag is 0, so label should be honored. +TEST_F(EvpnMacAdvertisementPrefixTest, FromProtoPrefix12) { + string temp1("2-10.1.1.1:65535-"); + string temp2("-11:12:13:14:15:16,2001:db8:0:9::1"); + uint32_t label_list[] = { 32, 10000, 1048575, 16777215 }; + BOOST_FOREACH(uint32_t label1, label_list) { + string prefix_str = temp1 + integerToString(0) + temp2; + boost::system::error_code ec; + EvpnPrefix prefix1(EvpnPrefix::FromString(prefix_str, &ec)); + EXPECT_EQ(0, ec.value()); + + TunnelEncap tunnel_encap(TunnelEncapType::VXLAN); + ExtCommunitySpec comm_spec; + comm_spec.communities.push_back(tunnel_encap.GetExtCommunityValue()); + BgpAttrSpec attr_spec; + attr_spec.push_back(&comm_spec); + BgpAttrPtr attr = bs_->attr_db()->Locate(attr_spec); + + BgpProtoPrefix proto_prefix; + prefix1.BuildProtoPrefix(attr.get(), label1, &proto_prefix); + EXPECT_EQ(EvpnPrefix::MacAdvertisementRoute, proto_prefix.type); + size_t expected_size = + EvpnPrefix::kMinMacAdvertisementRouteSize + EvpnPrefix::kLabelSize + 16; + EXPECT_EQ(expected_size * 8, proto_prefix.prefixlen); + EXPECT_EQ(expected_size, proto_prefix.prefix.size()); + + EvpnPrefix prefix2; + BgpAttrPtr attr_out2; + uint32_t label2; + int result = EvpnPrefix::FromProtoPrefix(bs_.get(), + proto_prefix, attr.get(), &prefix2, &attr_out2, &label2); + EXPECT_EQ(0, result); + EXPECT_EQ(prefix1, prefix2); + EXPECT_TRUE(prefix2.esi().IsZero()); + EXPECT_EQ(attr.get(), attr_out2.get()); + EXPECT_EQ(label1, label2); + } +} + // Smaller than minimum size for reach. TEST_F(EvpnMacAdvertisementPrefixTest, FromProtoPrefix_Error1) { BgpProtoPrefix proto_prefix;