From 54a798d218b735b09df205a3a7fb5630a33debea Mon Sep 17 00:00:00 2001 From: Nischal Sheth Date: Thu, 11 Jun 2015 17:27:15 -0700 Subject: [PATCH] Use ethernet tag as label if encapsulation is VXLAN Note that we still encode/decode the label as a 20-bit value in this release. This provides backward compatibility with older 2.0 releases and forward compatibility with 2.20 and newer releases. Note that all releases set the VNI as the ethernet tag. 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 | 43 +++- src/bgp/evpn/test/evpn_prefix_test.cc | 323 ++++++++++++++++++++++++++ 6 files changed, 391 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 7e28494134d..d854a62b2a2 100644 --- a/src/bgp/bgp_attr_base.h +++ b/src/bgp/bgp_attr_base.h @@ -94,8 +94,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 318bab06587..a1224c2d3d5 100644 --- a/src/bgp/evpn/evpn_route.cc +++ b/src/bgp/evpn/evpn_route.cc @@ -34,6 +34,33 @@ 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 and forward +// compatibility with newer JUNOS and Contrail code which encodes/decodes +// the label as a 24-bit value. +// +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, false)); + } 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) { + proto_prefix->WriteLabel(offset, label, false); +} + EvpnPrefix::EvpnPrefix() : type_(Unspecified), tag_(EvpnPrefix::kNullTag), family_(Address::UNSPEC) { } @@ -111,10 +138,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 +171,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: { @@ -229,7 +252,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: { @@ -258,7 +281,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 f9be214e878..1fa0595bd5f 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 }; + 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 }; + 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 }; + 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 }; + 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;