From 289c50d60ef3197ed8ef17f48423cabbce1f66c0 Mon Sep 17 00:00:00 2001 From: Nischal Sheth Date: Mon, 22 Jun 2015 12:39:35 -0700 Subject: [PATCH] Use ethernet tag as label for PmsiTunnel if encap 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: If5d2d0a2bbfc7dc1634652de07d4bfec271deeac Closes-Bug: 1464781 --- src/bgp/evpn/evpn_route.cc | 11 +- src/bgp/evpn/test/evpn_prefix_test.cc | 304 +++++++++++++++++++++++++- 2 files changed, 302 insertions(+), 13 deletions(-) diff --git a/src/bgp/evpn/evpn_route.cc b/src/bgp/evpn/evpn_route.cc index d7d6c019e12..ad10413cb35 100644 --- a/src/bgp/evpn/evpn_route.cc +++ b/src/bgp/evpn/evpn_route.cc @@ -206,7 +206,16 @@ int EvpnPrefix::FromProtoPrefix(BgpServer *server, const PmsiTunnel *pmsi_tunnel = attr ? attr->pmsi_tunnel() : NULL; if (pmsi_tunnel && pmsi_tunnel->tunnel_type == PmsiTunnelSpec::IngressReplication) { - *label = pmsi_tunnel->label; + const ExtCommunity *extcomm = attr ? attr->ext_community() : NULL; + if (extcomm && extcomm->ContainsTunnelEncapVxlan()) { + if (prefix->tag_ && prefix->tag_ <= kMaxVni) { + *label = prefix->tag_; + } else { + *label = pmsi_tunnel->label; + } + } else { + *label = pmsi_tunnel->label; + } } break; } diff --git a/src/bgp/evpn/test/evpn_prefix_test.cc b/src/bgp/evpn/test/evpn_prefix_test.cc index c91c71aef35..21305cdce88 100644 --- a/src/bgp/evpn/test/evpn_prefix_test.cc +++ b/src/bgp/evpn/test/evpn_prefix_test.cc @@ -1656,6 +1656,8 @@ TEST_F(EvpnInclusiveMulticastPrefixTest, ParsePrefix_Error6) { EXPECT_NE(0, ec.value()); } +// Build and parse BgpProtoPrefix for reach, w/ ipv4. +// Encap is not VXLAN, so label should be honored. TEST_F(EvpnInclusiveMulticastPrefixTest, FromProtoPrefix1) { string temp1("3-10.1.1.1:65535-"); string temp2("-192.1.1.1"); @@ -1666,9 +1668,15 @@ TEST_F(EvpnInclusiveMulticastPrefixTest, FromProtoPrefix1) { EvpnPrefix prefix1(EvpnPrefix::FromString(prefix_str, &ec)); EXPECT_EQ(0, ec.value()); - BgpAttr attr1; + BgpAttrSpec attr_spec; + PmsiTunnelSpec pmsi_spec; + pmsi_spec.tunnel_type = PmsiTunnelSpec::IngressReplication; + pmsi_spec.SetLabel(10000); + attr_spec.push_back(&pmsi_spec); + BgpAttrPtr attr = bs_->attr_db()->Locate(attr_spec); + BgpProtoPrefix proto_prefix; - prefix1.BuildProtoPrefix(&attr1, 0, &proto_prefix); + prefix1.BuildProtoPrefix(attr.get(), 0, &proto_prefix); EXPECT_EQ(EvpnPrefix::InclusiveMulticastRoute, proto_prefix.type); EXPECT_EQ((EvpnPrefix::kMinInclusiveMulticastRouteSize + 4) * 8, proto_prefix.prefixlen); @@ -1676,19 +1684,20 @@ TEST_F(EvpnInclusiveMulticastPrefixTest, FromProtoPrefix1) { proto_prefix.prefix.size()); EvpnPrefix prefix2; - BgpAttrPtr attr_in2(new BgpAttr(bs_->attr_db())); BgpAttrPtr attr_out2; uint32_t label2; int result = EvpnPrefix::FromProtoPrefix(bs_.get(), - proto_prefix, attr_in2.get(), &prefix2, &attr_out2, &label2); + 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_in2.get(), attr_out2.get()); - EXPECT_EQ(0, label2); + EXPECT_EQ(attr.get(), attr_out2.get()); + EXPECT_EQ(10000, label2); } } +// Build and parse BgpProtoPrefix for reach, w/ ipv6. +// Encap is not VXLAN, so label should be honored. TEST_F(EvpnInclusiveMulticastPrefixTest, FromProtoPrefix2) { string temp1("3-10.1.1.1:65535-"); string temp2("-2001:db8:0:9::1"); @@ -1699,9 +1708,15 @@ TEST_F(EvpnInclusiveMulticastPrefixTest, FromProtoPrefix2) { EvpnPrefix prefix1(EvpnPrefix::FromString(prefix_str, &ec)); EXPECT_EQ(0, ec.value()); - BgpAttr attr1; + BgpAttrSpec attr_spec; + PmsiTunnelSpec pmsi_spec; + pmsi_spec.tunnel_type = PmsiTunnelSpec::IngressReplication; + pmsi_spec.SetLabel(10000); + attr_spec.push_back(&pmsi_spec); + BgpAttrPtr attr = bs_->attr_db()->Locate(attr_spec); + BgpProtoPrefix proto_prefix; - prefix1.BuildProtoPrefix(&attr1, 0, &proto_prefix); + prefix1.BuildProtoPrefix(attr.get(), 0, &proto_prefix); EXPECT_EQ(EvpnPrefix::InclusiveMulticastRoute, proto_prefix.type); EXPECT_EQ((EvpnPrefix::kMinInclusiveMulticastRouteSize + 16) * 8, proto_prefix.prefixlen); @@ -1709,16 +1724,281 @@ TEST_F(EvpnInclusiveMulticastPrefixTest, FromProtoPrefix2) { proto_prefix.prefix.size()); EvpnPrefix prefix2; - BgpAttrPtr attr_in2(new BgpAttr(bs_->attr_db())); BgpAttrPtr attr_out2; uint32_t label2; int result = EvpnPrefix::FromProtoPrefix(bs_.get(), - proto_prefix, attr_in2.get(), &prefix2, &attr_out2, &label2); + 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_in2.get(), attr_out2.get()); - EXPECT_EQ(0, label2); + EXPECT_EQ(attr.get(), attr_out2.get()); + EXPECT_EQ(10000, label2); + } +} + +// Build and parse BgpProtoPrefix for reach with VXLAN encap, w/ ipv4. +// Tag is not 0, so label should be ignored. +TEST_F(EvpnInclusiveMulticastPrefixTest, FromProtoPrefix3) { + string temp1("3-10.1.1.1:65535-"); + string temp2("-192.1.1.1"); + uint32_t tag_list[] = { 32, 10000, 1048575, 16777215 }; + BOOST_FOREACH(uint32_t tag, tag_list) { + boost::system::error_code ec; + string prefix_str = temp1 + integerToString(tag) + temp2; + 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); + PmsiTunnelSpec pmsi_spec; + pmsi_spec.tunnel_type = PmsiTunnelSpec::IngressReplication; + pmsi_spec.SetLabel(10000); + attr_spec.push_back(&pmsi_spec); + BgpAttrPtr attr = bs_->attr_db()->Locate(attr_spec); + + BgpProtoPrefix proto_prefix; + prefix1.BuildProtoPrefix(attr.get(), 0, &proto_prefix); + EXPECT_EQ(EvpnPrefix::InclusiveMulticastRoute, proto_prefix.type); + EXPECT_EQ((EvpnPrefix::kMinInclusiveMulticastRouteSize + 4) * 8, + proto_prefix.prefixlen); + EXPECT_EQ(EvpnPrefix::kMinInclusiveMulticastRouteSize + 4, + 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, w/ ipv4. +// Tag is 0, so label should be honored. +TEST_F(EvpnInclusiveMulticastPrefixTest, FromProtoPrefix4) { + string temp1("3-10.1.1.1:65535-"); + string temp2("-192.1.1.1"); + uint32_t label_list[] = { 32, 10000, 1048575 }; + BOOST_FOREACH(uint32_t label, label_list) { + boost::system::error_code ec; + string prefix_str = temp1 + integerToString(0) + temp2; + 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); + PmsiTunnelSpec pmsi_spec; + pmsi_spec.tunnel_type = PmsiTunnelSpec::IngressReplication; + pmsi_spec.SetLabel(label); + attr_spec.push_back(&pmsi_spec); + BgpAttrPtr attr = bs_->attr_db()->Locate(attr_spec); + + BgpProtoPrefix proto_prefix; + prefix1.BuildProtoPrefix(attr.get(), 0, &proto_prefix); + EXPECT_EQ(EvpnPrefix::InclusiveMulticastRoute, proto_prefix.type); + EXPECT_EQ((EvpnPrefix::kMinInclusiveMulticastRouteSize + 4) * 8, + proto_prefix.prefixlen); + EXPECT_EQ(EvpnPrefix::kMinInclusiveMulticastRouteSize + 4, + 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(label, label2); + } +} + +// Build and parse BgpProtoPrefix for reach with VXLAN encap, w/ ipv4. +// Tag is greater than kMaxVni, so label should be honored. +TEST_F(EvpnInclusiveMulticastPrefixTest, FromProtoPrefix5) { + string temp1("3-10.1.1.1:65535-"); + string temp2("-192.1.1.1"); + uint32_t label_list[] = { 32, 10000, 1048575 }; + BOOST_FOREACH(uint32_t label, label_list) { + boost::system::error_code ec; + string prefix_str = + temp1 + integerToString(EvpnPrefix::kMaxVni + 1) + temp2; + 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); + PmsiTunnelSpec pmsi_spec; + pmsi_spec.tunnel_type = PmsiTunnelSpec::IngressReplication; + pmsi_spec.SetLabel(label); + attr_spec.push_back(&pmsi_spec); + BgpAttrPtr attr = bs_->attr_db()->Locate(attr_spec); + + BgpProtoPrefix proto_prefix; + prefix1.BuildProtoPrefix(attr.get(), 0, &proto_prefix); + EXPECT_EQ(EvpnPrefix::InclusiveMulticastRoute, proto_prefix.type); + EXPECT_EQ((EvpnPrefix::kMinInclusiveMulticastRouteSize + 4) * 8, + proto_prefix.prefixlen); + EXPECT_EQ(EvpnPrefix::kMinInclusiveMulticastRouteSize + 4, + 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(label, label2); + } +} + +// Build and parse BgpProtoPrefix for reach with VXLAN encap, w/ ipv6. +// Tag is not 0, so label should be ignored. +TEST_F(EvpnInclusiveMulticastPrefixTest, FromProtoPrefix6) { + string temp1("3-10.1.1.1:65535-"); + string temp2("-2001:db8:0:9::1"); + uint32_t tag_list[] = { 32, 10000, 1048575, 16777215 }; + BOOST_FOREACH(uint32_t tag, tag_list) { + boost::system::error_code ec; + string prefix_str = temp1 + integerToString(tag) + temp2; + 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); + PmsiTunnelSpec pmsi_spec; + pmsi_spec.tunnel_type = PmsiTunnelSpec::IngressReplication; + pmsi_spec.SetLabel(10000); + attr_spec.push_back(&pmsi_spec); + BgpAttrPtr attr = bs_->attr_db()->Locate(attr_spec); + + BgpProtoPrefix proto_prefix; + prefix1.BuildProtoPrefix(attr.get(), 0, &proto_prefix); + EXPECT_EQ(EvpnPrefix::InclusiveMulticastRoute, proto_prefix.type); + EXPECT_EQ((EvpnPrefix::kMinInclusiveMulticastRouteSize + 16) * 8, + proto_prefix.prefixlen); + EXPECT_EQ(EvpnPrefix::kMinInclusiveMulticastRouteSize + 16, + 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, w/ ipv6. +// Tag is 0, so label should be honored. +TEST_F(EvpnInclusiveMulticastPrefixTest, FromProtoPrefix7) { + string temp1("3-10.1.1.1:65535-"); + string temp2("-2001:db8:0:9::1"); + uint32_t label_list[] = { 32, 10000, 1048575 }; + BOOST_FOREACH(uint32_t label, label_list) { + boost::system::error_code ec; + string prefix_str = temp1 + integerToString(0) + temp2; + 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); + PmsiTunnelSpec pmsi_spec; + pmsi_spec.tunnel_type = PmsiTunnelSpec::IngressReplication; + pmsi_spec.SetLabel(label); + attr_spec.push_back(&pmsi_spec); + BgpAttrPtr attr = bs_->attr_db()->Locate(attr_spec); + + BgpProtoPrefix proto_prefix; + prefix1.BuildProtoPrefix(attr.get(), 0, &proto_prefix); + EXPECT_EQ(EvpnPrefix::InclusiveMulticastRoute, proto_prefix.type); + EXPECT_EQ((EvpnPrefix::kMinInclusiveMulticastRouteSize + 16) * 8, + proto_prefix.prefixlen); + EXPECT_EQ(EvpnPrefix::kMinInclusiveMulticastRouteSize + 16, + 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(label, label2); + } +} + +// Build and parse BgpProtoPrefix for reach with VXLAN encap, w/ ipv6. +// Tag is greater than kMaxVni, so label should be honored. +TEST_F(EvpnInclusiveMulticastPrefixTest, FromProtoPrefix8) { + string temp1("3-10.1.1.1:65535-"); + string temp2("-2001:db8:0:9::1"); + uint32_t label_list[] = { 32, 10000, 1048575 }; + BOOST_FOREACH(uint32_t label, label_list) { + boost::system::error_code ec; + string prefix_str = + temp1 + integerToString(EvpnPrefix::kMaxVni + 1) + temp2; + 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); + PmsiTunnelSpec pmsi_spec; + pmsi_spec.tunnel_type = PmsiTunnelSpec::IngressReplication; + pmsi_spec.SetLabel(label); + attr_spec.push_back(&pmsi_spec); + BgpAttrPtr attr = bs_->attr_db()->Locate(attr_spec); + + BgpProtoPrefix proto_prefix; + prefix1.BuildProtoPrefix(attr.get(), 0, &proto_prefix); + EXPECT_EQ(EvpnPrefix::InclusiveMulticastRoute, proto_prefix.type); + EXPECT_EQ((EvpnPrefix::kMinInclusiveMulticastRouteSize + 16) * 8, + proto_prefix.prefixlen); + EXPECT_EQ(EvpnPrefix::kMinInclusiveMulticastRouteSize + 16, + 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(label, label2); } }