From 106f830add2b7600fe092399bfba65d359c852db Mon Sep 17 00:00:00 2001 From: Nikhil Bansal Date: Tue, 31 Jul 2018 07:16:51 +0530 Subject: [PATCH] Contrail to support 4 byte AS Contrail only supports 2 byte AS today. There is a requirement to extend it to use 4 byte AS also. This is first draft to support the same. Some testcaes are added and some more may need to be added. Change-Id: I6691e49c6e78f0d46010db344b02dd9608ff0d93 Partial-Bug: #1416551 --- src/bgp/bgp_aspath.cc | 473 +++++++++++++++++- src/bgp/bgp_aspath.h | 347 ++++++++++++- src/bgp/bgp_attr.cc | 44 +- src/bgp/bgp_attr.h | 19 +- src/bgp/bgp_attr_base.h | 1 + src/bgp/bgp_common.h | 5 +- src/bgp/bgp_config.h | 2 +- src/bgp/bgp_config_ifmap.cc | 2 +- src/bgp/bgp_message_builder.cc | 15 +- src/bgp/bgp_origin_vn_path.cc | 11 + src/bgp/bgp_origin_vn_path.h | 2 + src/bgp/bgp_peer.cc | 47 +- src/bgp/bgp_peer.h | 6 + src/bgp/bgp_proto.cc | 258 +++++++++- src/bgp/bgp_proto.h | 4 +- src/bgp/bgp_rib_policy.cc | 10 +- src/bgp/bgp_rib_policy.h | 11 +- src/bgp/bgp_ribout.cc | 2 +- src/bgp/bgp_ribout.h | 1 + src/bgp/bgp_route.cc | 6 + src/bgp/bgp_server.cc | 2 + src/bgp/bgp_server.h | 6 + src/bgp/bgp_table.cc | 311 ++++++++++-- src/bgp/bgp_table.h | 13 + src/bgp/bgp_xmpp_channel.cc | 70 ++- src/bgp/bgp_xmpp_rtarget_manager.cc | 4 +- src/bgp/bgp_xmpp_rtarget_manager.h | 2 +- src/bgp/community.cc | 62 ++- src/bgp/community.h | 30 +- src/bgp/ermvpn/ermvpn_table.cc | 5 +- src/bgp/evpn/evpn_table.cc | 5 +- src/bgp/extended-community/tag.cc | 45 +- src/bgp/extended-community/tag.h | 24 +- src/bgp/extended-community/types.h | 1 + src/bgp/ipeer.h | 1 + src/bgp/l3vpn/test/inetvpn_peer_test.cc | 6 +- src/bgp/l3vpn/test/inetvpn_table_test.cc | 1 + src/bgp/origin-vn/origin_vn.cc | 131 ++++- src/bgp/origin-vn/origin_vn.h | 44 +- src/bgp/routing-instance/path_resolver.cc | 3 +- src/bgp/routing-instance/routing_instance.cc | 12 +- src/bgp/routing-instance/routing_instance.h | 16 +- src/bgp/routing-instance/service_chaining.cc | 5 +- .../routing-policy/routing_policy_action.cc | 18 +- .../routing-policy/routing_policy_action.h | 6 +- src/bgp/rtarget/rtarget_prefix.cc | 14 +- src/bgp/rtarget/rtarget_prefix.h | 6 +- src/bgp/security_group/security_group.cc | 58 ++- src/bgp/security_group/security_group.h | 29 +- src/bgp/test/bgp_attr_test.cc | 2 +- src/bgp/test/bgp_bgpaas_test.cc | 8 +- src/bgp/test/bgp_evpn_aliasing_test.cc | 1 + src/bgp/test/bgp_evpn_manager_test.cc | 1 + src/bgp/test/bgp_ip_test.cc | 8 +- src/bgp/test/bgp_msg_builder_test.cc | 11 +- src/bgp/test/bgp_multicast_test.cc | 1 + src/bgp/test/bgp_mvpn_test.cc | 1 + src/bgp/test/bgp_proto_test.cc | 64 +-- src/bgp/test/bgp_route_test.cc | 1 + src/bgp/test/bgp_server_test.cc | 44 +- src/bgp/test/bgp_table_export_test.cc | 322 +++++++++++- src/bgp/test/bgp_table_test.cc | 27 +- src/bgp/test/bgp_xmpp_rtarget_manager_test.cc | 2 +- src/bgp/test/bgp_xmpp_rtarget_test.cc | 39 +- src/bgp/test/path_resolver_test.cc | 1 + src/bgp/test/ribout_attributes_test.cc | 1 + src/bgp/test/route_aggregator_test.cc | 1 + .../test/routepath_replicator_random_test.cc | 1 + src/bgp/test/routepath_replicator_test.cc | 1 + src/bgp/test/routing_policy_action_test.cc | 28 +- src/bgp/test/routing_policy_match_test.cc | 1 + src/bgp/test/routing_policy_test.cc | 10 +- src/bgp/test/service_chain_test.cc | 1 + src/bgp/test/static_route_test.cc | 1 + src/bgp/xmpp_message_builder.cc | 5 + 75 files changed, 2468 insertions(+), 311 deletions(-) diff --git a/src/bgp/bgp_aspath.cc b/src/bgp/bgp_aspath.cc index 2a821663466..db695965284 100644 --- a/src/bgp/bgp_aspath.cc +++ b/src/bgp/bgp_aspath.cc @@ -18,7 +18,7 @@ using std::vector; // // Return the left most AS. // -as_t AsPathSpec::AsLeftMost() const { +as2_t AsPathSpec::AsLeftMost() const { if (path_segments.empty()) return 0; if (path_segments[0]->path_segment_type == PathSegment::AS_SET) @@ -31,7 +31,7 @@ as_t AsPathSpec::AsLeftMost() const { // // Return true if left most AS matches the input. // -bool AsPathSpec::AsLeftMostMatch(as_t as) const { +bool AsPathSpec::AsLeftMostMatch(as2_t as) const { if (path_segments.empty()) return false; if (path_segments[0]->path_segment.empty()) @@ -42,7 +42,7 @@ bool AsPathSpec::AsLeftMostMatch(as_t as) const { // // Return the left most public AS. // -as_t AsPathSpec::AsLeftMostPublic() const { +as2_t AsPathSpec::AsLeftMostPublic() const { for (size_t i = 0; i < path_segments.size(); ++i) { PathSegment *ps = path_segments[i]; for (size_t j = 0; j < path_segments[i]->path_segment.size(); ++j) { @@ -111,7 +111,7 @@ size_t AsPathSpec::EncodeLength() const { // Check AsPathSpec for loops for the given as. // Return true if the number of occurrences of as exceeds given max loop count. // -bool AsPathSpec::AsPathLoop(as_t as, uint8_t max_loop_count) const { +bool AsPathSpec::AsPathLoop(as2_t as, uint8_t max_loop_count) const { uint8_t loop_count = 0; for (size_t i = 0; i < path_segments.size(); ++i) { for (size_t j = 0; j < path_segments[i]->path_segment.size(); ++j) { @@ -127,8 +127,8 @@ bool AsPathSpec::AsPathLoop(as_t as, uint8_t max_loop_count) const { // // Create a new AsPathSpec by prepending the given asn at the beginning. // -AsPathSpec *AsPathSpec::Add(as_t asn) const { - vector asn_list = list_of(asn); +AsPathSpec *AsPathSpec::Add(as2_t asn) const { + vector asn_list = list_of(asn); return Add(asn_list); } @@ -136,7 +136,7 @@ AsPathSpec *AsPathSpec::Add(as_t asn) const { // Create a new AsPathSpec by prepending the given vector of asns at the // beginning. // -AsPathSpec *AsPathSpec::Add(const vector &asn_list) const { +AsPathSpec *AsPathSpec::Add(const vector &asn_list) const { AsPathSpec *new_spec = new AsPathSpec; PathSegment *ps = new PathSegment; ps->path_segment_type = PathSegment::AS_SEQUENCE; @@ -167,7 +167,7 @@ AsPathSpec *AsPathSpec::Add(const vector &asn_list) const { // // Create a new AsPathSpec by replacing the old asn with given asn. // -AsPathSpec *AsPathSpec::Replace(as_t old_asn, as_t asn) const { +AsPathSpec *AsPathSpec::Replace(as2_t old_asn, as2_t asn) const { AsPathSpec *new_spec = new AsPathSpec(*this); for (size_t i = 0; i < new_spec->path_segments.size(); ++i) { PathSegment *ps = new_spec->path_segments[i]; @@ -189,7 +189,7 @@ AsPathSpec *AsPathSpec::Replace(as_t old_asn, as_t asn) const { // asn, then use the given asn. // If peer asn is non-zero, do not remove/replace it. // -AsPathSpec *AsPathSpec::RemovePrivate(bool all, as_t asn, as_t peer_asn) const { +AsPathSpec *AsPathSpec::RemovePrivate(bool all, as2_t asn, as2_t peer_asn) const { bool remove_replace_done = false; AsPathSpec *new_spec = new AsPathSpec; for (size_t i = 0; i < path_segments.size(); ++i) { @@ -197,14 +197,14 @@ AsPathSpec *AsPathSpec::RemovePrivate(bool all, as_t asn, as_t peer_asn) const { PathSegment *new_ps = new PathSegment; // We've already removed/replaced all private asns that we can. - // Copy the entire segment instead of copying one as_t at a time. + // Copy the entire segment instead of copying one as2_t at a time. if (remove_replace_done) { *new_ps = *ps; new_spec->path_segments.push_back(new_ps); continue; } - // Examine each as_t in the path segment to build a modified version. + // Examine each as2_t in the path segment to build a modified version. // Note down that we're done removing/replacing when we see a public // asn or the peer asn. new_ps->path_segment_type = ps->path_segment_type; @@ -241,3 +241,454 @@ void AsPath::Remove() { AsPathDB::AsPathDB(BgpServer *server) { } +// +// Return the left most AS. +// +as_t AsPath4ByteSpec::AsLeftMost() const { + if (path_segments.empty()) + return 0; + if (path_segments[0]->path_segment_type == PathSegment::AS_SET) + return 0; + if (path_segments[0]->path_segment.empty()) + return 0; + return (path_segments[0]->path_segment[0]); +} + +// +// Return true if left most AS matches the input. +// +bool AsPath4ByteSpec::AsLeftMostMatch(as_t as) const { + if (path_segments.empty()) + return false; + if (path_segments[0]->path_segment.empty()) + return false; + return (path_segments[0]->path_segment[0] == as); +} + +// +// Return the left most public AS. +// +as_t AsPath4ByteSpec::AsLeftMostPublic() const { + for (size_t i = 0; i < path_segments.size(); ++i) { + PathSegment *ps = path_segments[i]; + for (size_t j = 0; j < path_segments[i]->path_segment.size(); ++j) { + if (!AsIsPrivate(ps->path_segment[j])) + return ps->path_segment[j]; + } + } + return 0; +} + +int AsPath4ByteSpec::CompareTo(const BgpAttribute &rhs_attr) const { + int ret = BgpAttribute::CompareTo(rhs_attr); + if (ret != 0) return ret; + const AsPath4ByteSpec &rhs = static_cast(rhs_attr); + KEY_COMPARE(path_segments.size(), rhs.path_segments.size()); + + for (size_t i = 0; i < path_segments.size(); i++) { + int ret = path_segments[i]->CompareTo(*rhs.path_segments[i]); + if (ret != 0) return ret; + } + return 0; +} + +void AsPath4ByteSpec::ToCanonical(BgpAttr *attr) { + attr->set_aspath_4byte(this); +} + +string AsPath4ByteSpec::ToString() const { + ostringstream oss; + + for (size_t i = 0; i < path_segments.size(); i++) { + if (i != 0) oss << " "; + switch (path_segments[i]->path_segment_type) { + case AsPath4ByteSpec::PathSegment::AS_SET: + oss << "{"; + for (size_t j = 0; j < path_segments[i]->path_segment.size(); j++) { + if (j != 0) oss << " "; + oss << path_segments[i]->path_segment[j]; + } + oss << "}"; + break; + case AsPath4ByteSpec::PathSegment::AS_SEQUENCE: + for (size_t j = 0; j < path_segments[i]->path_segment.size(); j++) { + if (j != 0) oss << " "; + oss << path_segments[i]->path_segment[j]; + } + break; + default: + break; + } + } + + return oss.str(); +} + +size_t AsPath4ByteSpec::EncodeLength() const { + size_t sz = 0; + for (size_t i = 0; i < path_segments.size(); i++) { + sz += 2; + sz += path_segments[i]->path_segment.size() * 4; + } + return sz; +} + +// +// Check AsPath4ByteSpec for loops for the given as. +// Return true if the number of occurrences of as exceeds given max loop count. +// +bool AsPath4ByteSpec::AsPathLoop(as_t as, uint8_t max_loop_count) const { + uint8_t loop_count = 0; + for (size_t i = 0; i < path_segments.size(); ++i) { + for (size_t j = 0; j < path_segments[i]->path_segment.size(); ++j) { + if (path_segments[i]->path_segment[j] == as && + ++loop_count > max_loop_count) { + return true; + } + } + } + return false; +} + +// +// Create a new AsPath4ByteSpec by prepending the given asn at the beginning. +// +AsPath4ByteSpec *AsPath4ByteSpec::Add(as_t asn) const { + vector asn_list = list_of(asn); + return Add(asn_list); +} + +// +// Create a new AsPath4ByteSpec by prepending the given vector of asns at the +// beginning. +// +AsPath4ByteSpec *AsPath4ByteSpec::Add(const vector &asn_list) const { + AsPath4ByteSpec *new_spec = new AsPath4ByteSpec; + PathSegment *ps = new PathSegment; + ps->path_segment_type = PathSegment::AS_SEQUENCE; + ps->path_segment = asn_list; + size_t first = 0; + size_t last = path_segments.size(); + if (last && + path_segments[0]->path_segment_type == PathSegment::AS_SEQUENCE && + path_segments[0]->path_segment.size() + asn_list.size() <= 255) { + copy(path_segments[0]->path_segment.begin(), + path_segments[0]->path_segment.end(), + back_inserter(ps->path_segment)); + new_spec->path_segments.push_back(ps); + first++; + } else { + new_spec->path_segments.push_back(ps); + } + if (first == last) + return new_spec; + for (size_t idx = first; idx < last; ++idx) { + PathSegment *ps = new PathSegment; + *ps = *path_segments[idx]; + new_spec->path_segments.push_back(ps); + } + return new_spec; +} + +// +// Create a new AsPath4ByteSpec by replacing the old asn with given asn. +// +AsPath4ByteSpec *AsPath4ByteSpec::Replace(as_t old_asn, as_t asn) const { + AsPath4ByteSpec *new_spec = new AsPath4ByteSpec(*this); + for (size_t i = 0; i < new_spec->path_segments.size(); ++i) { + PathSegment *ps = new_spec->path_segments[i]; + for (size_t j = 0; j < ps->path_segment.size(); ++j) { + if (ps->path_segment[j] == old_asn) + ps->path_segment[j] = asn; + } + } + return new_spec; +} + +// +// Create a new AsPath4ByteSpec by removing private asns. Stop looking for private +// asns when we encounter the first public asn or the peer asn. +// If all is true, remove all private asns i.e. do not stop when we encounter +// the first public asn or the peer asn. +// If asn is non-zero, replace private asns instead of removing them. Use the +// nearest public asn as the replacement value. If we haven't found a public +// asn, then use the given asn. +// If peer asn is non-zero, do not remove/replace it. +// +AsPath4ByteSpec *AsPath4ByteSpec::RemovePrivate(bool all, as_t asn, as_t peer_asn) const { + bool remove_replace_done = false; + AsPath4ByteSpec *new_spec = new AsPath4ByteSpec; + for (size_t i = 0; i < path_segments.size(); ++i) { + PathSegment *ps = path_segments[i]; + PathSegment *new_ps = new PathSegment; + + // We've already removed/replaced all private asns that we can. + // Copy the entire segment instead of copying one as_t at a time. + if (remove_replace_done) { + *new_ps = *ps; + new_spec->path_segments.push_back(new_ps); + continue; + } + + // Examine each as_t in the path segment to build a modified version. + // Note down that we're done removing/replacing when we see a public + // asn or the peer asn. + new_ps->path_segment_type = ps->path_segment_type; + for (size_t j = 0; j < ps->path_segment.size(); ++j) { + if (remove_replace_done || + !AsIsPrivate(ps->path_segment[j]) || + ps->path_segment[j] == peer_asn) { + new_ps->path_segment.push_back(ps->path_segment[j]); + remove_replace_done = !all; + if (asn && !AsIsPrivate(ps->path_segment[j])) { + asn = ps->path_segment[j]; + } + } else if (asn) { + new_ps->path_segment.push_back(asn); + } + } + + // Get rid of the new path segment if it's empty. + // Otherwise add it to the new spec. + if (new_ps->path_segment.empty()) { + delete new_ps; + } else { + new_spec->path_segments.push_back(new_ps); + } + } + + return new_spec; +} + +void AsPath4Byte::Remove() { + aspath_db_->Delete(this); +} + +AsPath4ByteDB::AsPath4ByteDB(BgpServer *server) { +} + +// +// Return the left most AS. +// +as_t As4PathSpec::AsLeftMost() const { + if (path_segments.empty()) + return 0; + if (path_segments[0]->path_segment_type == PathSegment::AS_SET) + return 0; + if (path_segments[0]->path_segment.empty()) + return 0; + return (path_segments[0]->path_segment[0]); +} + +// +// Return true if left most AS matches the input. +// +bool As4PathSpec::AsLeftMostMatch(as_t as) const { + if (path_segments.empty()) + return false; + if (path_segments[0]->path_segment.empty()) + return false; + return (path_segments[0]->path_segment[0] == as); +} + +// +// Return the left most public AS. +// +as_t As4PathSpec::AsLeftMostPublic() const { + for (size_t i = 0; i < path_segments.size(); ++i) { + PathSegment *ps = path_segments[i]; + for (size_t j = 0; j < path_segments[i]->path_segment.size(); ++j) { + if (!AsIsPrivate(ps->path_segment[j])) + return ps->path_segment[j]; + } + } + return 0; +} + +int As4PathSpec::CompareTo(const BgpAttribute &rhs_attr) const { + int ret = BgpAttribute::CompareTo(rhs_attr); + if (ret != 0) return ret; + const As4PathSpec &rhs = static_cast(rhs_attr); + KEY_COMPARE(path_segments.size(), rhs.path_segments.size()); + + for (size_t i = 0; i < path_segments.size(); i++) { + int ret = path_segments[i]->CompareTo(*rhs.path_segments[i]); + if (ret != 0) return ret; + } + return 0; +} + +void As4PathSpec::ToCanonical(BgpAttr *attr) { + attr->set_as4_path(this); +} + +string As4PathSpec::ToString() const { + ostringstream oss; + + for (size_t i = 0; i < path_segments.size(); i++) { + if (i != 0) oss << " "; + switch (path_segments[i]->path_segment_type) { + case As4PathSpec::PathSegment::AS_SET: + oss << "{"; + for (size_t j = 0; j < path_segments[i]->path_segment.size(); j++) { + if (j != 0) oss << " "; + oss << path_segments[i]->path_segment[j]; + } + oss << "}"; + break; + case As4PathSpec::PathSegment::AS_SEQUENCE: + for (size_t j = 0; j < path_segments[i]->path_segment.size(); j++) { + if (j != 0) oss << " "; + oss << path_segments[i]->path_segment[j]; + } + break; + default: + break; + } + } + + return oss.str(); +} + +size_t As4PathSpec::EncodeLength() const { + size_t sz = 0; + for (size_t i = 0; i < path_segments.size(); i++) { + sz += 2; + sz += path_segments[i]->path_segment.size() * 4; + } + return sz; +} + +// +// Check As4PathSpec for loops for the given as. +// Return true if the number of occurrences of as exceeds given max loop count. +// +bool As4PathSpec::AsPathLoop(as_t as, uint8_t max_loop_count) const { + uint8_t loop_count = 0; + for (size_t i = 0; i < path_segments.size(); ++i) { + for (size_t j = 0; j < path_segments[i]->path_segment.size(); ++j) { + if (path_segments[i]->path_segment[j] == as && + ++loop_count > max_loop_count) { + return true; + } + } + } + return false; +} + +// +// Create a new As4PathSpec by prepending the given asn at the beginning. +// +As4PathSpec *As4PathSpec::Add(as_t asn) const { + vector asn_list = list_of(asn); + return Add(asn_list); +} + +// +// Create a new As4PathSpec by prepending the given vector of asns at the +// beginning. +// +As4PathSpec *As4PathSpec::Add(const vector &asn_list) const { + As4PathSpec *new_spec = new As4PathSpec; + PathSegment *ps = new PathSegment; + ps->path_segment_type = PathSegment::AS_SEQUENCE; + ps->path_segment = asn_list; + size_t first = 0; + size_t last = path_segments.size(); + if (last && + path_segments[0]->path_segment_type == PathSegment::AS_SEQUENCE && + path_segments[0]->path_segment.size() + asn_list.size() <= 255) { + copy(path_segments[0]->path_segment.begin(), + path_segments[0]->path_segment.end(), + back_inserter(ps->path_segment)); + new_spec->path_segments.push_back(ps); + first++; + } else { + new_spec->path_segments.push_back(ps); + } + if (first == last) + return new_spec; + for (size_t idx = first; idx < last; ++idx) { + PathSegment *ps = new PathSegment; + *ps = *path_segments[idx]; + new_spec->path_segments.push_back(ps); + } + return new_spec; +} + +// +// Create a new As4PathSpec by replacing the old asn with given asn. +// +As4PathSpec *As4PathSpec::Replace(as_t old_asn, as_t asn) const { + As4PathSpec *new_spec = new As4PathSpec(*this); + for (size_t i = 0; i < new_spec->path_segments.size(); ++i) { + PathSegment *ps = new_spec->path_segments[i]; + for (size_t j = 0; j < ps->path_segment.size(); ++j) { + if (ps->path_segment[j] == old_asn) + ps->path_segment[j] = asn; + } + } + return new_spec; +} + +// +// Create a new As4PathSpec by removing private asns. Stop looking for private +// asns when we encounter the first public asn or the peer asn. +// If all is true, remove all private asns i.e. do not stop when we encounter +// the first public asn or the peer asn. +// If asn is non-zero, replace private asns instead of removing them. Use the +// nearest public asn as the replacement value. If we haven't found a public +// asn, then use the given asn. +// If peer asn is non-zero, do not remove/replace it. +// +As4PathSpec *As4PathSpec::RemovePrivate(bool all, as_t asn, as_t peer_asn) const { + bool remove_replace_done = false; + As4PathSpec *new_spec = new As4PathSpec; + for (size_t i = 0; i < path_segments.size(); ++i) { + PathSegment *ps = path_segments[i]; + PathSegment *new_ps = new PathSegment; + + // We've already removed/replaced all private asns that we can. + // Copy the entire segment instead of copying one as_t at a time. + if (remove_replace_done) { + *new_ps = *ps; + new_spec->path_segments.push_back(new_ps); + continue; + } + + // Examine each as_t in the path segment to build a modified version. + // Note down that we're done removing/replacing when we see a public + // asn or the peer asn. + new_ps->path_segment_type = ps->path_segment_type; + for (size_t j = 0; j < ps->path_segment.size(); ++j) { + if (remove_replace_done || + !AsIsPrivate(ps->path_segment[j]) || + ps->path_segment[j] == peer_asn) { + new_ps->path_segment.push_back(ps->path_segment[j]); + remove_replace_done = !all; + if (asn && !AsIsPrivate(ps->path_segment[j])) { + asn = ps->path_segment[j]; + } + } else if (asn) { + new_ps->path_segment.push_back(asn); + } + } + + // Get rid of the new path segment if it's empty. + // Otherwise add it to the new spec. + if (new_ps->path_segment.empty()) { + delete new_ps; + } else { + new_spec->path_segments.push_back(new_ps); + } + } + + return new_spec; +} + +void As4Path::Remove() { + aspath_db_->Delete(this); +} + +As4PathDB::As4PathDB(BgpServer *server) { +} diff --git a/src/bgp/bgp_aspath.h b/src/bgp/bgp_aspath.h index 390385a7dd8..eabef9ec885 100644 --- a/src/bgp/bgp_aspath.h +++ b/src/bgp/bgp_aspath.h @@ -20,13 +20,15 @@ class BgpAttr; class AsPathDB; +class As4PathDB; +class AsPath4ByteDB; class BgpServer; struct AsPathSpec : public BgpAttribute { static const int kSize = -1; static const uint8_t kFlags = Transitive; - static const as_t kMinPrivateAs = 64512; - static const as_t kMaxPrivateAs = 65535; + static const as2_t kMinPrivateAs = 64512; + static const as2_t kMaxPrivateAs = 65535; AsPathSpec() : BgpAttribute(BgpAttribute::AsPath, kFlags) {} explicit AsPathSpec(const BgpAttribute &rhs) : BgpAttribute(rhs) {} @@ -53,14 +55,14 @@ struct AsPathSpec : public BgpAttribute { AS_SEQUENCE = 2 }; int path_segment_type; - std::vector path_segment; + std::vector path_segment; }; - as_t AsLeftMost() const; - bool AsLeftMostMatch(as_t as) const; - as_t AsLeftMostPublic() const; - bool AsPathLoop(as_t as, uint8_t max_loop_count = 0) const; - static bool AsIsPrivate(as_t as) { + as2_t AsLeftMost() const; + bool AsLeftMostMatch(as2_t as) const; + as2_t AsLeftMostPublic() const; + bool AsPathLoop(as2_t as, uint8_t max_loop_count = 0) const; + static bool AsIsPrivate(as2_t as) { return as >= kMinPrivateAs && as <= kMaxPrivateAs; } @@ -68,10 +70,10 @@ struct AsPathSpec : public BgpAttribute { virtual void ToCanonical(BgpAttr *attr); virtual size_t EncodeLength() const; virtual std::string ToString() const; - AsPathSpec *Add(as_t asn) const; - AsPathSpec *Add(const std::vector &asn_list) const; - AsPathSpec *Replace(as_t old_asn, as_t asn) const; - AsPathSpec *RemovePrivate(bool all, as_t asn, as_t peer_as) const; + AsPathSpec *Add(as2_t asn) const; + AsPathSpec *Add(const std::vector &asn_list) const; + AsPathSpec *Replace(as2_t old_asn, as2_t asn) const; + AsPathSpec *RemovePrivate(bool all, as2_t asn, as2_t peer_as) const; std::vector path_segments; }; @@ -123,9 +125,9 @@ class AsPath { } const AsPathSpec &path() const { return path_; } bool empty() const { return path_.path_segments.empty(); } - as_t neighbor_as() const { return path_.AsLeftMost(); } + as2_t neighbor_as() const { return path_.AsLeftMost(); } - friend std::size_t hash_value(AsPath const &as_path) { + friend std::size_t hash_value(const AsPath &as_path) { size_t hash = 0; boost::hash_combine(hash, as_path.path().ToString()); return hash; @@ -175,4 +177,321 @@ class AsPathDB : public BgpPathAttributeDB path_segment; + }; + + as_t AsLeftMost() const; + bool AsLeftMostMatch(as_t as) const; + as_t AsLeftMostPublic() const; + bool AsPathLoop(as_t as, uint8_t max_loop_count = 0) const; + static bool AsIsPrivate(as_t as) { + return ((as >= kMinPrivateAs && as <= kMaxPrivateAs) || + (as >= kMinPrivateAs4 && as <= kMaxPrivateAs4)); + } + + virtual int CompareTo(const BgpAttribute &rhs_attr) const; + virtual void ToCanonical(BgpAttr *attr); + virtual size_t EncodeLength() const; + virtual std::string ToString() const; + AsPath4ByteSpec *Add(as_t asn) const; + AsPath4ByteSpec *Add(const std::vector &asn_list) const; + AsPath4ByteSpec *Replace(as_t old_asn, as_t asn) const; + AsPath4ByteSpec *RemovePrivate(bool all, as_t asn, as_t peer_as) const; + + std::vector path_segments; +}; + +class AsPath4Byte { +public: + explicit AsPath4Byte(AsPath4ByteDB *aspath_db) : aspath_db_(aspath_db) { + refcount_ = 0; + } + explicit AsPath4Byte(AsPath4ByteDB *aspath_db, const AsPath4ByteSpec &spec) + : aspath_db_(aspath_db), path_(spec) { + refcount_ = 0; + for (size_t i = 0; i < path_.path_segments.size(); i++) { + AsPath4ByteSpec::PathSegment *ps = path_.path_segments[i]; + if (ps->path_segment_type == AsPath4ByteSpec::PathSegment::AS_SET) { + std::sort(ps->path_segment.begin(), ps->path_segment.end()); + } + } + } + virtual ~AsPath4Byte() { } + virtual void Remove(); + int AsCount() const { + int count = 0; + std::vector::const_iterator i; + for (i = path_.path_segments.begin(); i < path_.path_segments.end(); + i++) { + if ((*i)->path_segment_type == + AsPath4ByteSpec::PathSegment::AS_SET) { + count++; + } else { + count += (*i)->path_segment.size(); + } + } + return count; + } + + int CompareTo(const AsPath4Byte &rhs) const { + const std::vector &lps = + path_.path_segments; + const std::vector &rps = + rhs.path_.path_segments; + + KEY_COMPARE(lps.size(), rps.size()); + + std::vector::const_iterator i, j; + for (i = lps.begin(), j = rps.begin(); i < lps.end(); i++, j++) { + int ret = (*i)->CompareTo(**j); + if (ret != 0) return ret; + } + return 0; + } + const AsPath4ByteSpec &path() const { return path_; } + bool empty() const { return path_.path_segments.empty(); } + as_t neighbor_as() const { return path_.AsLeftMost(); } + + friend std::size_t hash_value(const AsPath4Byte &as_path) { + size_t hash = 0; + boost::hash_combine(hash, as_path.path().ToString()); + return hash; + } + +private: + friend int intrusive_ptr_add_ref(const AsPath4Byte *cpath); + friend int intrusive_ptr_del_ref(const AsPath4Byte *cpath); + friend void intrusive_ptr_release(const AsPath4Byte *cpath); + + mutable tbb::atomic refcount_; + AsPath4ByteDB *aspath_db_; + AsPath4ByteSpec path_; +}; + +inline int intrusive_ptr_add_ref(const AsPath4Byte *cpath) { + return cpath->refcount_.fetch_and_increment(); +} + +inline int intrusive_ptr_del_ref(const AsPath4Byte *cpath) { + return cpath->refcount_.fetch_and_decrement(); +} + +inline void intrusive_ptr_release(const AsPath4Byte *cpath) { + int prev = cpath->refcount_.fetch_and_decrement(); + if (prev == 1) { + AsPath4Byte *path = const_cast(cpath); + path->Remove(); + assert(path->refcount_ == 0); + delete path; + } +} + +typedef boost::intrusive_ptr AsPath4BytePtr; + +struct AsPath4ByteCompare { + bool operator()(const AsPath4Byte *lhs, const AsPath4Byte *rhs) { + return lhs->CompareTo(*rhs) < 0; + } +}; + +class AsPath4ByteDB : public BgpPathAttributeDB { +public: + explicit AsPath4ByteDB(BgpServer *server); + +private: +}; + +typedef boost::intrusive_ptr AsPath4BytePtr; + +struct As4PathSpec : public BgpAttribute { + static const int kSize = -1; + static const uint8_t kFlags = Transitive|Optional; + static const as_t kMinPrivateAs = 64512; + static const as_t kMaxPrivateAs = 65535; + static const as_t kMinPrivateAs4 = 4200000000; + static const as_t kMaxPrivateAs4 = 4294967294; + + As4PathSpec() : BgpAttribute(BgpAttribute::As4Path, kFlags) {} + explicit As4PathSpec(const BgpAttribute &rhs) : BgpAttribute(rhs) {} + explicit As4PathSpec(const As4PathSpec &rhs) : + BgpAttribute(BgpAttribute::As4Path, kFlags) { + for (size_t i = 0; i < rhs.path_segments.size(); i++) { + PathSegment *ps = new PathSegment; + *ps = *rhs.path_segments[i]; + path_segments.push_back(ps); + } + } + ~As4PathSpec() { + STLDeleteValues(&path_segments); + } + struct PathSegment : public ParseObject { + int CompareTo(const PathSegment &rhs) const { + KEY_COMPARE(path_segment_type, rhs.path_segment_type); + KEY_COMPARE(path_segment, rhs.path_segment); + return 0; + } + + enum PathSegmentType { + AS_SET = 1, + AS_SEQUENCE = 2 + }; + int path_segment_type; + std::vector path_segment; + }; + + as_t AsLeftMost() const; + bool AsLeftMostMatch(as_t as) const; + as_t AsLeftMostPublic() const; + bool AsPathLoop(as_t as, uint8_t max_loop_count = 0) const; + static bool AsIsPrivate(as_t as) { + return ((as >= kMinPrivateAs && as <= kMaxPrivateAs) || + (as >= kMinPrivateAs4 && as <= kMaxPrivateAs4)); + } + + virtual int CompareTo(const BgpAttribute &rhs_attr) const; + virtual void ToCanonical(BgpAttr *attr); + virtual size_t EncodeLength() const; + virtual std::string ToString() const; + As4PathSpec *Add(as_t asn) const; + As4PathSpec *Add(const std::vector &asn_list) const; + As4PathSpec *Replace(as_t old_asn, as_t asn) const; + As4PathSpec *RemovePrivate(bool all, as_t asn, as_t peer_as) const; + + std::vector path_segments; +}; + +class As4Path { +public: + explicit As4Path(As4PathDB *aspath_db) : aspath_db_(aspath_db) { + refcount_ = 0; + } + explicit As4Path(As4PathDB *aspath_db, const As4PathSpec &spec) + : aspath_db_(aspath_db), path_(spec) { + refcount_ = 0; + for (size_t i = 0; i < path_.path_segments.size(); i++) { + As4PathSpec::PathSegment *ps = path_.path_segments[i]; + if (ps->path_segment_type == As4PathSpec::PathSegment::AS_SET) { + std::sort(ps->path_segment.begin(), ps->path_segment.end()); + } + } + } + virtual ~As4Path() { } + virtual void Remove(); + int AsCount() const { + int count = 0; + std::vector::const_iterator i; + for (i = path_.path_segments.begin(); i < path_.path_segments.end(); + i++) { + if ((*i)->path_segment_type == As4PathSpec::PathSegment::AS_SET) { + count++; + } else { + count += (*i)->path_segment.size(); + } + } + return count; + } + + int CompareTo(const As4Path &rhs) const { + const std::vector &lps = path_.path_segments; + const std::vector &rps = + rhs.path_.path_segments; + + KEY_COMPARE(lps.size(), rps.size()); + + std::vector::const_iterator i, j; + for (i = lps.begin(), j = rps.begin(); i < lps.end(); i++, j++) { + int ret = (*i)->CompareTo(**j); + if (ret != 0) return ret; + } + return 0; + } + const As4PathSpec &path() const { return path_; } + bool empty() const { return path_.path_segments.empty(); } + as_t neighbor_as() const { return path_.AsLeftMost(); } + + friend std::size_t hash_value(As4Path const &as_path) { + size_t hash = 0; + boost::hash_combine(hash, as_path.path().ToString()); + return hash; + } + +private: + friend int intrusive_ptr_add_ref(const As4Path *cpath); + friend int intrusive_ptr_del_ref(const As4Path *cpath); + friend void intrusive_ptr_release(const As4Path *cpath); + + mutable tbb::atomic refcount_; + As4PathDB *aspath_db_; + As4PathSpec path_; +}; + +inline int intrusive_ptr_add_ref(const As4Path *cpath) { + return cpath->refcount_.fetch_and_increment(); +} + +inline int intrusive_ptr_del_ref(const As4Path *cpath) { + return cpath->refcount_.fetch_and_decrement(); +} + +inline void intrusive_ptr_release(const As4Path *cpath) { + int prev = cpath->refcount_.fetch_and_decrement(); + if (prev == 1) { + As4Path *path = const_cast(cpath); + path->Remove(); + assert(path->refcount_ == 0); + delete path; + } +} + +typedef boost::intrusive_ptr As4PathPtr; + +struct As4PathCompare { + bool operator()(const As4Path *lhs, const As4Path *rhs) { + return lhs->CompareTo(*rhs) < 0; + } +}; + +class As4PathDB : public BgpPathAttributeDB { +public: + explicit As4PathDB(BgpServer *server); + +private: +}; + +typedef boost::intrusive_ptr As4PathPtr; #endif // SRC_BGP_BGP_ASPATH_H_ diff --git a/src/bgp/bgp_attr.cc b/src/bgp/bgp_attr.cc index 5a2911c9d64..68fe7e81ba3 100644 --- a/src/bgp/bgp_attr.cc +++ b/src/bgp/bgp_attr.cc @@ -892,6 +892,8 @@ BgpAttr::BgpAttr(const BgpAttr &rhs) originator_id_(rhs.originator_id_), source_rd_(rhs.source_rd_), esi_(rhs.esi_), params_(rhs.params_), as_path_(rhs.as_path_), + aspath_4byte_(rhs.aspath_4byte_), + as4_path_(rhs.as4_path_), cluster_list_(rhs.cluster_list_), community_(rhs.community_), ext_community_(rhs.ext_community_), @@ -918,6 +920,30 @@ void BgpAttr::set_as_path(const AsPathSpec *spec) { } } +void BgpAttr::set_as4_path(As4PathPtr aspath) { + as4_path_ = aspath; +} + +void BgpAttr::set_as4_path(const As4PathSpec *spec) { + if (spec) { + as4_path_ = attr_db_->server()->as4path_db()->Locate(*spec); + } else { + as4_path_ = NULL; + } +} + +void BgpAttr::set_aspath_4byte(AsPath4BytePtr aspath) { + aspath_4byte_ = aspath; +} + +void BgpAttr::set_aspath_4byte(const AsPath4ByteSpec *spec) { + if (spec) { + aspath_4byte_ = attr_db_->server()->aspath_4byte_db()->Locate(*spec); + } else { + aspath_4byte_ = NULL; + } +} + void BgpAttr::set_cluster_list(const ClusterListSpec *spec) { if (spec) { cluster_list_ = attr_db_->server()->cluster_list_db()->Locate(*spec); @@ -1008,6 +1034,14 @@ void BgpAttr::set_leaf_olist(const BgpOListSpec *leaf_olist_spec) { } } +bool BgpAttr::IsAsPathEmpty() const { + if (as_path_ && !as_path_->empty()) + return false; + if (aspath_4byte_ && !aspath_4byte_->empty()) + return false; + return true; +} + string BgpAttr::OriginToString(BgpAttrOrigin::OriginType origin) { switch (origin) { case BgpAttrOrigin::IGP: @@ -1046,7 +1080,11 @@ Address::Family BgpAttr::nexthop_family() const { } as_t BgpAttr::neighbor_as() const { - return (as_path_.get() ? as_path_->neighbor_as() : 0); + if (as_path_.get()) + return as_path_->neighbor_as(); + if (aspath_4byte_.get()) + return aspath_4byte_->neighbor_as(); + return 0; } uint32_t BgpAttr::sequence_number() const { @@ -1142,6 +1180,8 @@ int BgpAttr::CompareTo(const BgpAttr &rhs) const { KEY_COMPARE(olist_.get(), rhs.olist_.get()); KEY_COMPARE(leaf_olist_.get(), rhs.leaf_olist_.get()); KEY_COMPARE(as_path_.get(), rhs.as_path_.get()); + KEY_COMPARE(aspath_4byte_.get(), rhs.aspath_4byte_.get()); + KEY_COMPARE(as4_path_.get(), rhs.as4_path_.get()); KEY_COMPARE(cluster_list_.get(), rhs.cluster_list_.get()); KEY_COMPARE(community_.get(), rhs.community_.get()); KEY_COMPARE(ext_community_.get(), rhs.ext_community_.get()); @@ -1180,6 +1220,8 @@ std::size_t hash_value(BgpAttr const &attr) { } if (attr.as_path_) boost::hash_combine(hash, *attr.as_path_); + if (attr.aspath_4byte_) boost::hash_combine(hash, *attr.aspath_4byte_); + if (attr.as4_path_) boost::hash_combine(hash, *attr.as4_path_); if (attr.community_) boost::hash_combine(hash, *attr.community_); if (attr.ext_community_) boost::hash_combine(hash, *attr.ext_community_); if (attr.origin_vn_path_) boost::hash_combine(hash, *attr.origin_vn_path_); diff --git a/src/bgp/bgp_attr.h b/src/bgp/bgp_attr.h index 08c913ba3bd..fd1147f1d8c 100644 --- a/src/bgp/bgp_attr.h +++ b/src/bgp/bgp_attr.h @@ -140,7 +140,7 @@ struct BgpAttrAggregator : public BgpAttribute { } explicit BgpAttrAggregator(uint32_t as_num, uint32_t address) : BgpAttribute(Aggregator, kFlags), as_num(as_num), address(address) {} - as_t as_num; + as2_t as_num; uint32_t address; virtual int CompareTo(const BgpAttribute &rhs_attr) const; virtual void ToCanonical(BgpAttr *attr); @@ -816,6 +816,10 @@ class BgpAttr { void set_params(uint64_t params) { params_ = params; } void set_as_path(AsPathPtr aspath); void set_as_path(const AsPathSpec *spec); + void set_as4_path(As4PathPtr aspath); + void set_as4_path(const As4PathSpec *spec); + void set_aspath_4byte(AsPath4BytePtr aspath); + void set_aspath_4byte(const AsPath4ByteSpec *spec); void set_cluster_list(const ClusterListSpec *spec); void set_community(CommunityPtr comm); void set_community(const CommunitySpec *comm); @@ -853,10 +857,21 @@ class BgpAttr { uint64_t params() const { return params_; } const AsPath *as_path() const { return as_path_.get(); } int as_path_count() const { return as_path_ ? as_path_->AsCount() : 0; } + const AsPath4Byte *aspath_4byte() const { return aspath_4byte_.get(); } + int aspath_4byte_count() const { + return aspath_4byte_ ? aspath_4byte_->AsCount() : 0; + } const ClusterList *cluster_list() const { return cluster_list_.get(); } size_t cluster_list_length() const { return cluster_list_ ? cluster_list_->size() : 0; } + const As4Path *as4_path() const { return as4_path_.get(); } + int as4_path_count() const { return as4_path_ ? as4_path_->AsCount() : 0; } + bool IsAsPathEmpty() const; + //const Cluster4List *cluster4_list() const { return cluster4_list_.get(); } + //size_t cluster4_list_length() const { + //return cluster4_list_ ? cluster4_list_->size() : 0; + //} const Community *community() const { return community_.get(); } const ExtCommunity *ext_community() const { return ext_community_.get(); } const OriginVnPath *origin_vn_path() const { return origin_vn_path_.get(); } @@ -900,6 +915,8 @@ class BgpAttr { EthernetSegmentId esi_; uint64_t params_; AsPathPtr as_path_; + AsPath4BytePtr aspath_4byte_; + As4PathPtr as4_path_; ClusterListPtr cluster_list_; CommunityPtr community_; ExtCommunityPtr ext_community_; diff --git a/src/bgp/bgp_attr_base.h b/src/bgp/bgp_attr_base.h index e9928fdba4f..968f053c7ed 100644 --- a/src/bgp/bgp_attr_base.h +++ b/src/bgp/bgp_attr_base.h @@ -42,6 +42,7 @@ class BgpAttribute : public ParseObject { MPReachNlri = 14, MPUnreachNlri = 15, ExtendedCommunities = 16, + As4Path = 17, PmsiTunnel = 22, McastEdgeDiscovery = 241, McastEdgeForwarding = 242, diff --git a/src/bgp/bgp_common.h b/src/bgp/bgp_common.h index f30ffb3bd03..80acf379c6c 100644 --- a/src/bgp/bgp_common.h +++ b/src/bgp/bgp_common.h @@ -12,8 +12,9 @@ #include #include -typedef uint16_t as_t; -typedef uint32_t as4_t; +typedef uint32_t as_t; +typedef uint16_t as2_t; +#define AS_TRANS 23456 class RoutingPolicy; typedef boost::intrusive_ptr RoutingPolicyPtr; diff --git a/src/bgp/bgp_config.h b/src/bgp/bgp_config.h index b1551c83fcd..a18058fcc68 100644 --- a/src/bgp/bgp_config.h +++ b/src/bgp/bgp_config.h @@ -339,7 +339,7 @@ struct StaticRouteConfig { std::vector communities; }; -typedef std::vector AsnList; +typedef std::vector AsnList; typedef std::vector CommunityList; typedef std::vector ProtocolList; diff --git a/src/bgp/bgp_config_ifmap.cc b/src/bgp/bgp_config_ifmap.cc index 0143c3979d9..b86ff34695f 100644 --- a/src/bgp/bgp_config_ifmap.cc +++ b/src/bgp/bgp_config_ifmap.cc @@ -1790,7 +1790,7 @@ static void BuildPolicyTermConfig(autogen::PolicyTermType cfg_term, cfg_term.term_match_condition.extcommunity_list; } - BOOST_FOREACH(uint16_t asn, + BOOST_FOREACH(uint32_t asn, cfg_term.term_action_list.update.as_path.expand.asn_list) { term->action.update.aspath_expand.push_back(asn); } diff --git a/src/bgp/bgp_message_builder.cc b/src/bgp/bgp_message_builder.cc index 52e3d3c7f9b..c8a59a31600 100644 --- a/src/bgp/bgp_message_builder.cc +++ b/src/bgp/bgp_message_builder.cc @@ -75,6 +75,17 @@ bool BgpMessage::StartReach(const RibOut *ribout, const RibOutAttr *roattr, update.path_attributes.push_back(path); } + if (attr->aspath_4byte()) { + AsPath4ByteSpec *path = new AsPath4ByteSpec( + attr->aspath_4byte()->path()); + update.path_attributes.push_back(path); + } + + if (attr->as4_path()) { + As4PathSpec *path = new As4PathSpec(attr->as4_path()->path()); + update.path_attributes.push_back(path); + } + if (attr->edge_discovery()) { EdgeDiscoverySpec *edspec = new EdgeDiscoverySpec(attr->edge_discovery()->edge_discovery()); @@ -137,8 +148,8 @@ bool BgpMessage::StartReach(const RibOut *ribout, const RibOutAttr *roattr, route->BuildProtoPrefix(prefix, attr, label, roattr->l3_label()); nlri->nlri.push_back(prefix); - int result = - BgpProto::Encode(&update, data_, sizeof(data_), &encode_offsets_); + int result = BgpProto::Encode(&update, data_, sizeof(data_), + &encode_offsets_, ribout->as4_supported()); if (result <= 0) { BGP_LOG_WARNING_STR(BgpMessageSend, BGP_LOG_FLAG_ALL, "Error encoding reach message for route " << route->ToString() << diff --git a/src/bgp/bgp_origin_vn_path.cc b/src/bgp/bgp_origin_vn_path.cc index 88990b87b36..6d238db8fc7 100644 --- a/src/bgp/bgp_origin_vn_path.cc +++ b/src/bgp/bgp_origin_vn_path.cc @@ -59,6 +59,17 @@ void OriginVnPath::Prepend(const OriginVnValue &value) { origin_vns_.insert(it, value); } +bool OriginVnPath::Contains(as_t asn, uint32_t vn_index) const { + if (asn <= 0xffff) { + OriginVn origin_vn(asn, vn_index); + return Contains(origin_vn.GetExtCommunity()); + } + OriginVn4ByteAs origin_vn4(asn, AS_TRANS); + OriginVn origin_vn(AS_TRANS, vn_index); + return (Contains(origin_vn.GetExtCommunity()) && + Contains(origin_vn4.GetExtCommunity())); +} + bool OriginVnPath::Contains(const OriginVnValue &val) const { OriginVn in_origin_vn(val); int in_vn_index = in_origin_vn.IsGlobal() ? in_origin_vn.vn_index() : 0; diff --git a/src/bgp/bgp_origin_vn_path.h b/src/bgp/bgp_origin_vn_path.h index c3c5fa7dd9b..17e6aa6e0c3 100644 --- a/src/bgp/bgp_origin_vn_path.h +++ b/src/bgp/bgp_origin_vn_path.h @@ -16,6 +16,7 @@ #include "base/parse_object.h" #include "base/util.h" #include "bgp/bgp_attr_base.h" +#include "bgp/bgp_common.h" class BgpAttr; class OriginVnPathDB; @@ -53,6 +54,7 @@ class OriginVnPath { virtual void Remove(); bool Contains(const OriginVnValue &value) const; + bool Contains(as_t asn, uint32_t vn_index) const; int CompareTo(const OriginVnPath &rhs) const; const OriginVnList &origin_vns() const { return origin_vns_; } diff --git a/src/bgp/bgp_peer.cc b/src/bgp/bgp_peer.cc index 4fa1979264f..6c0fa574573 100644 --- a/src/bgp/bgp_peer.cc +++ b/src/bgp/bgp_peer.cc @@ -236,11 +236,11 @@ RibExportPolicy BgpPeer::BuildRibExportPolicy(Address::Family family) const { if (!family_attributes) { policy = RibExportPolicy(peer_type_, RibExportPolicy::BGP, peer_as_, as_override_, peer_close_->IsCloseLongLivedGraceful(), - -1, cluster_id_, local_as_); + as4_supported_, -1, cluster_id_, local_as_); } else { policy = RibExportPolicy(peer_type_, RibExportPolicy::BGP, peer_as_, as_override_, peer_close_->IsCloseLongLivedGraceful(), - family_attributes->gateway_address, + as4_supported_, family_attributes->gateway_address, -1, cluster_id_, family_attributes->default_tunnel_encap_list, local_as_); } @@ -279,7 +279,8 @@ void BgpPeer::SendEndOfRIBActual(Address::Family family) { BgpMpNlri *nlri = new BgpMpNlri(BgpAttribute::MPUnreachNlri, afi, safi); update.path_attributes.push_back(nlri); uint8_t data[256]; - int msgsize = BgpProto::Encode(&update, data, sizeof(data)); + int msgsize = BgpProto::Encode(&update, data, sizeof(data), NULL, + Is4ByteAsSupported()); assert(msgsize > BgpProto::kMinMessageSize); session_->Send(data, msgsize, NULL); inc_tx_end_of_rib(); @@ -490,6 +491,7 @@ BgpPeer::BgpPeer(BgpServer *server, RoutingInstance *instance, origin_override_(config->origin_override()), defer_close_(false), graceful_close_(true), + as4_supported_(true), vpn_tables_registered_(false), hold_time_(config->hold_time()), local_as_(config->local_as()), @@ -1401,6 +1403,11 @@ void BgpPeer::SendOpen(TcpSession *session) { opt_param->capabilities.push_back(cap); } + BgpProto::OpenMessage::Capability *cap = + new BgpProto::OpenMessage::Capability( + BgpProto::OpenMessage::Capability::AS4Support, + (const uint8_t *)(&local_as_), 4); + opt_param->capabilities.push_back(cap); peer_close_->AddGRCapabilities(opt_param); peer_close_->AddLLGRCapabilities(opt_param); @@ -1558,6 +1565,14 @@ bool BgpPeer::SetCapabilities(const BgpProto::OpenMessage *msg) { (*it)->capabilities.clear(); } + as4_supported_ = false; + vector::iterator c_it; + for (c_it = capabilities_.begin(); c_it < capabilities_.end(); ++c_it) { + if ((*c_it)->code == BgpProto::OpenMessage::Capability::AS4Support) { + as4_supported_ = true; + break; + } + } BgpPeerInfoData peer_info; peer_info.set_name(ToUVEKey()); peer_info.set_peer_id(peer_bgp_id_); @@ -1638,6 +1653,16 @@ bool BgpPeer::MpNlriAllowed(uint16_t afi, uint8_t safi) { return false; } +bool BgpPeer::Is4ByteAsSupported() { + return as4_supported_; + vector::iterator it; + for (it = capabilities_.begin(); it < capabilities_.end(); ++it) { + if ((*it)->code == BgpProto::OpenMessage::Capability::AS4Support) + return true; + } + return false; +} + template void BgpPeer::ProcessNlri(Address::Family family, DBRequest::DBOperation oper, const BgpMpNlri *nlri, BgpAttrPtr attr, uint32_t flags) { @@ -1688,18 +1713,25 @@ uint32_t BgpPeer::GetPathFlags(Address::Family family, flags |= BgpPath::ClusterListLooped; } - if (!attr->as_path()) + if (!attr->as_path() && !attr->aspath_4byte()) return flags; // Check whether neighbor has appended its AS to the AS_PATH. if ((PeerType() == BgpProto::EBGP) && - (!attr->as_path()->path().AsLeftMostMatch(peer_as()))) { + ((attr->as_path() && !attr->as_path()->path().AsLeftMostMatch( + peer_as())) || (attr->aspath_4byte() && + !attr->aspath_4byte()->path().AsLeftMostMatch(peer_as())))) { flags |= BgpPath::NoNeighborAs; } // Check for AS_PATH loop. uint8_t max_loop_count = family_attributes_list_[family]->loop_count; - if (attr->as_path()->path().AsPathLoop(local_as_, max_loop_count)) { + if (attr->as_path() && + attr->as_path()->path().AsPathLoop(local_as_, max_loop_count)) { + flags |= BgpPath::AsPathLooped; + } + if (attr->aspath_4byte() && + attr->aspath_4byte()->path().AsPathLoop(local_as_, max_loop_count)) { flags |= BgpPath::AsPathLooped; } @@ -2105,7 +2137,8 @@ string BgpPeer::BytesToHexString(const u_int8_t *msg, size_t size) { bool BgpPeer::ReceiveMsg(BgpSession *session, const u_int8_t *msg, size_t size) { ParseErrorContext ec; - BgpProto::BgpMessage *minfo = BgpProto::Decode(msg, size, &ec); + BgpProto::BgpMessage *minfo = BgpProto::Decode(msg, size, &ec, + Is4ByteAsSupported()); if (minfo == NULL) { BGP_TRACE_PEER_PACKET(this, msg, size, SandeshLevel::SYS_WARN); diff --git a/src/bgp/bgp_peer.h b/src/bgp/bgp_peer.h index a2839fbf240..a25a8c47a9f 100644 --- a/src/bgp/bgp_peer.h +++ b/src/bgp/bgp_peer.h @@ -309,6 +309,8 @@ class BgpPeer : public IPeer { total_path_count_ += count; } virtual int GetTotalPathCount() const { return total_path_count_; } + virtual bool IsAs4Supported() const { return as4_supported_; } + virtual void ResetAs4Supported() { as4_supported_ = false; } virtual void UpdatePrimaryPathCount(int count, Address::Family family) const; virtual void ProcessPathTunnelEncapsulation(const BgpPath *path, @@ -382,6 +384,8 @@ class BgpPeer : public IPeer { size_t GetBufferCapacity() const; bool FlushUpdateUnlocked(); + static int Encode(const BgpMessage *msg, uint8_t *data, size_t size, + EncodeOffsets *offsets = NULL, bool as4 = false); void KeepaliveTimerErrorHandler(std::string error_name, std::string error_message); virtual void StartKeepaliveTimerUnlocked(); @@ -410,6 +414,7 @@ class BgpPeer : public IPeer { uint32_t GetPathFlags(Address::Family family, const BgpAttr *attr) const; uint32_t GetLocalPrefFromMed(uint32_t med) const; virtual bool MpNlriAllowed(uint16_t afi, uint8_t safi); + virtual bool Is4ByteAsSupported(); BgpAttrPtr GetMpNlriNexthop(BgpMpNlri *nlri, BgpAttrPtr attr); template void ProcessNlri(Address::Family family, DBRequest::DBOperation oper, @@ -496,6 +501,7 @@ class BgpPeer : public IPeer { tbb::atomic membership_req_pending_; bool defer_close_; bool graceful_close_; + bool as4_supported_; bool vpn_tables_registered_; std::vector capabilities_; uint16_t hold_time_; diff --git a/src/bgp/bgp_proto.cc b/src/bgp/bgp_proto.cc index d129af02440..1d44fe45dbd 100644 --- a/src/bgp/bgp_proto.cc +++ b/src/bgp/bgp_proto.cc @@ -873,6 +873,24 @@ struct BgpAttributeVerifier { } }; +template <> +struct BgpAttributeVerifier { + static bool Verifier(const AsPath4ByteSpec::PathSegment *obj, + const uint8_t *data, size_t size, + ParseContext *context) { + return true; + } +}; + +template <> +struct BgpAttributeVerifier { + static bool Verifier(const As4PathSpec::PathSegment *obj, + const uint8_t *data, size_t size, + ParseContext *context) { + return true; + } +}; + template class BgpAttributeValue : public ProtoElement > { @@ -928,7 +946,7 @@ class BgpPathAttributeAggregator : typedef BgpAttrAggregator ContextType; typedef BgpContextSwap ContextSwap; typedef mpl::list, BgpAttributeValue<4, BgpAttrAggregator, uint32_t, &BgpAttrAggregator::address> @@ -956,15 +974,73 @@ class BgpPathAttrAsPathSegmentLength : typedef SetLength EncodingCallback; }; +class BgpPathAttrAsPath4ByteSegmentLength : + public ProtoElement { +public: + static const int kSize = 1; + struct PathSegmentLength { + int operator()(AsPath4ByteSpec::PathSegment *obj, + const uint8_t *data, size_t size) { + return get_value(data, 1) * 4; + } + }; + typedef PathSegmentLength SequenceLength; + struct SetLength { + static void Callback(EncodeContext *context, uint8_t *data, + int offset, int element_size) { + int len = get_value(data, kSize); + put_value(data, kSize, len/4); + } + }; + typedef SetLength EncodingCallback; +}; + +class BgpPathAttrAs4PathSegmentLength : + public ProtoElement { +public: + static const int kSize = 1; + struct PathSegmentLength { + int operator()(As4PathSpec::PathSegment *obj, + const uint8_t *data, size_t size) { + return get_value(data, 1) * 4; + } + }; + typedef PathSegmentLength SequenceLength; + struct SetLength { + static void Callback(EncodeContext *context, uint8_t *data, + int offset, int element_size) { + int len = get_value(data, kSize); + put_value(data, kSize, len/4); + } + }; + typedef SetLength EncodingCallback; +}; + class BgpPathAttrAsPathSegmentValue : public ProtoElement { public: static const int kSize = -1; - typedef VectorAccessor Setter; }; +class BgpPathAttrAsPath4ByteSegmentValue : + public ProtoElement { +public: + static const int kSize = -1; + typedef VectorAccessor Setter; +}; + +class BgpPathAttrAs4PathSegmentValue : + public ProtoElement { +public: + static const int kSize = -1; + typedef VectorAccessor Setter; +}; + class BgpPathAttrAsPathSegmentList : public ProtoSequence { public: @@ -988,6 +1064,52 @@ class BgpPathAttrAsPathSegmentList : > Sequence; }; +class BgpPathAttrAsPath4ByteSegmentList : + public ProtoSequence { +public: + static const int kMinOccurs = 0; + static const int kMaxOccurs = -1; + + static bool Verifier(const AsPath4ByteSpec *obj, const uint8_t *data, + size_t size, ParseContext *context) { + return BgpAttributeVerifier::Verifier(obj, data, size, + context); + } + + typedef CollectionAccessor, + &AsPath4ByteSpec::path_segments> ContextStorer; + + typedef mpl::list, + BgpPathAttrAsPath4ByteSegmentLength, + BgpPathAttrAsPath4ByteSegmentValue + > Sequence; +}; + +class BgpPathAttrAs4PathSegmentList : + public ProtoSequence { +public: + static const int kMinOccurs = 0; + static const int kMaxOccurs = -1; + + static bool Verifier(const As4PathSpec *obj, const uint8_t *data, + size_t size, ParseContext *context) { + return BgpAttributeVerifier::Verifier(obj, data, size, + context); + } + + typedef CollectionAccessor, + &As4PathSpec::path_segments> ContextStorer; + + typedef mpl::list, + BgpPathAttrAs4PathSegmentLength, + BgpPathAttrAs4PathSegmentValue + > Sequence; +}; + class BgpPathAttributeAsPath : public ProtoSequence { public: typedef AsPathSpec ContextType; @@ -995,6 +1117,22 @@ class BgpPathAttributeAsPath : public ProtoSequence { typedef mpl::list Sequence; }; +class BgpPathAttributeAsPath4Byte : + public ProtoSequence { +public: + typedef AsPath4ByteSpec ContextType; + typedef BgpContextSwap ContextSwap; + typedef mpl::list Sequence; +}; + +class BgpPathAttributeAs4Path : public ProtoSequence { +public: + typedef As4PathSpec ContextType; + typedef BgpContextSwap ContextSwap; + typedef mpl::list Sequence; +}; + class BgpPathAttributeFlags : public ProtoElement { public: static const int kSize = 1; @@ -1737,6 +1875,56 @@ class BgpPathAttribute : public ProtoChoice { > Choice; }; +class BgpPathAttributeAs4 : public ProtoChoice { +public: + static const int kSize = 1; + + typedef Accessor Setter; + typedef mpl::map< + mpl::pair, + BgpAttrTemplate >, + mpl::pair, + BgpPathAttributeAsPath4Byte>, + mpl::pair, BgpPathAttributeAs4Path>, + mpl::pair, + BgpAttrTemplate >, + mpl::pair, + BgpAttrTemplate >, + mpl::pair, + BgpAttrTemplate >, + mpl::pair, + BgpPathAttributeAtomicAggregate>, + mpl::pair, + BgpPathAttributeAggregator>, + mpl::pair, + BgpPathAttributeCommunities>, + mpl::pair, + BgpAttrTemplate >, + mpl::pair, + BgpPathAttributeClusterList>, + mpl::pair, + BgpPathAttributeMpReachNlriSequence>, + mpl::pair, + BgpPathAttributeMpUnreachNlriSequence>, + mpl::pair, + BgpPathAttributeExtendedCommunities>, + mpl::pair, + BgpPathAttributePmsiTunnel>, + mpl::pair, + BgpPathAttributeEdgeDiscovery>, + mpl::pair, + BgpPathAttributeEdgeForwarding>, + mpl::pair, + BgpPathAttributeOriginVnPath>, + mpl::pair, BgpPathAttributeUnknown> + > Choice; +}; + class BgpPathAttributeList : public ProtoSequence { public: static const int kSize = 2; @@ -1757,6 +1945,26 @@ class BgpPathAttributeList : public ProtoSequence { typedef mpl::list Sequence; }; +class BgpPathAttributeAs4List : public ProtoSequence { +public: + static const int kSize = 2; + static const int kMinOccurs = 0; + static const int kMaxOccurs = -1; + static const int kErrorCode = BgpProto::Notification::UpdateMsgErr; + static const int kErrorSubcode = + BgpProto::Notification::MalformedAttributeList; + struct Offset { + string operator()() { + return "BgpPathAttribute"; + } + }; + typedef Offset SaveOffset; + typedef CollectionAccessor, + &BgpProto::Update::path_attributes> ContextStorer; + typedef mpl::list Sequence; +}; + class BgpUpdateNlri : public ProtoSequence { public: static const int kMinOccurs = 0; @@ -1775,6 +1983,13 @@ class BgpUpdateNlri : public ProtoSequence { typedef mpl::list Sequence; }; +class BgpUpdateMessageAs4 : public ProtoSequence { +public: + typedef mpl::list Sequence; + typedef BgpProto::Update ContextType; +}; + class BgpUpdateMessage : public ProtoSequence { public: typedef mpl::list { > Choice; }; +class BgpMsgTypeAs4 : public ProtoChoice { +public: + static const int kSize = 1; + static const int kErrorCode = BgpProto::Notification::MsgHdrErr; + static const int kErrorSubcode = BgpProto::Notification::BadMsgType; + typedef mpl::map< + mpl::pair, BgpOpenMessage>, + mpl::pair, BgpNotificationMessage>, + mpl::pair, BgpKeepaliveMessage>, + mpl::pair, BgpUpdateMessageAs4> + > Choice; +}; + class BgpProtocol : public ProtoSequence { public: typedef mpl::list Sequence; }; +class BgpProtocolAs4 : public ProtoSequence { +public: + typedef mpl::list Sequence; +}; + BgpProto::BgpMessage *BgpProto::Decode(const uint8_t *data, size_t size, - ParseErrorContext *ec) { + ParseErrorContext *ec, bool as4) { ParseContext context; - int result = BgpProtocol::Parse( - data, size, &context, reinterpret_cast(NULL)); + int result; + if (as4) { + result = BgpProtocolAs4::Parse(data, size, &context, + reinterpret_cast(NULL)); + } else { + result = BgpProtocol::Parse(data, size, &context, + reinterpret_cast(NULL)); + } if (result < 0) { if (ec) { *ec = context.error_context(); @@ -1815,9 +2054,14 @@ BgpProto::BgpMessage *BgpProto::Decode(const uint8_t *data, size_t size, } int BgpProto::Encode(const BgpMessage *msg, uint8_t *data, size_t size, - EncodeOffsets *offsets) { + EncodeOffsets *offsets, bool as4) { EncodeContext ctx; - int result = BgpProtocol::Encode(&ctx, msg, data, size); + int result; + if (as4) { + result = BgpProtocolAs4::Encode(&ctx, msg, data, size); + } else { + result = BgpProtocol::Encode(&ctx, msg, data, size); + } if (offsets) { *offsets = ctx.encode_offsets(); } diff --git a/src/bgp/bgp_proto.h b/src/bgp/bgp_proto.h index d2a4ad5d9b5..a1c245f1ffc 100644 --- a/src/bgp/bgp_proto.h +++ b/src/bgp/bgp_proto.h @@ -441,10 +441,10 @@ class BgpProto { static const int kMaxMessageSize = 4096; static BgpMessage *Decode(const uint8_t *data, size_t size, - ParseErrorContext *ec = NULL); + ParseErrorContext *ec = NULL, bool as4 = true); static int Encode(const BgpMessage *msg, uint8_t *data, size_t size, - EncodeOffsets *offsets = NULL); + EncodeOffsets *offsets = NULL, bool as4 = true); static int Encode(const BgpMpNlri *msg, uint8_t *data, size_t size, EncodeOffsets *offsets = NULL); }; diff --git a/src/bgp/bgp_rib_policy.cc b/src/bgp/bgp_rib_policy.cc index aeb7927c4e2..57ba1bff2d7 100644 --- a/src/bgp/bgp_rib_policy.cc +++ b/src/bgp/bgp_rib_policy.cc @@ -22,6 +22,7 @@ RibExportPolicy::RibExportPolicy() as_override(false), affinity(-1), llgr(false), + as4_supported(true), cluster_id(0) { } @@ -33,6 +34,7 @@ RibExportPolicy::RibExportPolicy(uint32_t cluster_id) as_override(false), affinity(-1), llgr(false), + as4_supported(true), cluster_id(cluster_id) { } @@ -45,6 +47,7 @@ RibExportPolicy::RibExportPolicy(BgpProto::BgpPeerType type, Encoding encoding, as_override(false), affinity(affinity), llgr(false), + as4_supported(true), cluster_id(cluster_id) { if (encoding == XMPP) assert(type == BgpProto::XMPP); @@ -53,7 +56,7 @@ RibExportPolicy::RibExportPolicy(BgpProto::BgpPeerType type, Encoding encoding, } RibExportPolicy::RibExportPolicy(BgpProto::BgpPeerType type, Encoding encoding, - as_t as_number, bool as_override, bool llgr, int affinity, + as_t as_number, bool as_override, bool llgr, bool as4, int affinity, uint32_t cluster_id, as_t local_as_number) : type(type), encoding(encoding), @@ -62,6 +65,7 @@ RibExportPolicy::RibExportPolicy(BgpProto::BgpPeerType type, Encoding encoding, as_override(as_override), affinity(affinity), llgr(llgr), + as4_supported(as4), cluster_id(cluster_id) { if (encoding == XMPP) assert(type == BgpProto::XMPP); @@ -71,7 +75,7 @@ RibExportPolicy::RibExportPolicy(BgpProto::BgpPeerType type, Encoding encoding, RibExportPolicy::RibExportPolicy(BgpProto::BgpPeerType type, Encoding encoding, - as_t as_number, bool as_override, bool llgr, IpAddress nexthop, + as_t as_number, bool as_override, bool llgr, bool as4, IpAddress nexthop, int affinity, uint32_t cluster_id, vector &default_tunnel_encap_list, as_t local_as_number) : type(type), @@ -82,6 +86,7 @@ RibExportPolicy::RibExportPolicy(BgpProto::BgpPeerType type, Encoding encoding, nexthop(nexthop), affinity(affinity), llgr(llgr), + as4_supported(as4), cluster_id(cluster_id), default_tunnel_encap_list(default_tunnel_encap_list) { assert(type == BgpProto::IBGP || type == BgpProto::EBGP); @@ -108,6 +113,7 @@ bool RibExportPolicy::operator<(const RibExportPolicy &rhs) const { BOOL_KEY_COMPARE(nexthop, rhs.nexthop); BOOL_KEY_COMPARE(affinity, rhs.affinity); BOOL_KEY_COMPARE(llgr, rhs.llgr); + BOOL_KEY_COMPARE(as4_supported, rhs.as4_supported); BOOL_KEY_COMPARE(cluster_id, rhs.cluster_id); BOOL_KEY_COMPARE(remove_private.enabled, rhs.remove_private.enabled); BOOL_KEY_COMPARE(remove_private.all, rhs.remove_private.all); diff --git a/src/bgp/bgp_rib_policy.h b/src/bgp/bgp_rib_policy.h index 983a1731532..8d67a464dd8 100644 --- a/src/bgp/bgp_rib_policy.h +++ b/src/bgp/bgp_rib_policy.h @@ -36,6 +36,10 @@ // Instead, we should bring down the local pref to make the paths less // preferable. // +// Adding as4_supported so that peers who support 4 byte AS can be grouped +// together. For non AS4 neighbors, we need to add AS_TRANS in AS_PATH if +// local AS does not fit in 2 bytes. +// struct RibExportPolicy { enum Encoding { BGP, @@ -56,11 +60,11 @@ struct RibExportPolicy { RibExportPolicy(BgpProto::BgpPeerType type, Encoding encoding, int affinity, uint32_t cluster_id); RibExportPolicy(BgpProto::BgpPeerType type, Encoding encoding, - as_t as_number, bool as_override, bool llgr, + as_t as_number, bool as_override, bool llgr, bool as4_supported, int affinity, uint32_t cluster_id, as_t local_as_number = 0); RibExportPolicy(BgpProto::BgpPeerType type, Encoding encoding, - as_t as_number, bool as_override, bool llgr, IpAddress nexthop, - int affinity, uint32_t cluster_id, + as_t as_number, bool as_override, bool llgr, bool as4_supported, + IpAddress nexthop, int affinity, uint32_t cluster_id, std::vector &default_tunnel_encap_list, as_t local_as_number = 0); void SetRemovePrivatePolicy(bool all, bool replace, bool peer_loop_check); @@ -74,6 +78,7 @@ struct RibExportPolicy { IpAddress nexthop; int affinity; bool llgr; + bool as4_supported; uint32_t cluster_id; RemovePrivatePolicy remove_private; std::vector default_tunnel_encap_list; diff --git a/src/bgp/bgp_ribout.cc b/src/bgp/bgp_ribout.cc index 642af4e13cd..0ae1f283273 100644 --- a/src/bgp/bgp_ribout.cc +++ b/src/bgp/bgp_ribout.cc @@ -36,7 +36,7 @@ RibOutAttr::NextHop::NextHop(const BgpTable *table, IpAddress address, if (ext_community) { as_t asn = table ? table->server()->autonomous_system() : 0; encap_ = ext_community->GetTunnelEncap(); - tag_list_ = ext_community->GetTagList(asn); + tag_list_ = ext_community->GetTag4List(asn); origin_vn_index_ = ext_community->GetOriginVnIndex(); } if (origin_vn_index_ < 0 && vrf_originated) { diff --git a/src/bgp/bgp_ribout.h b/src/bgp/bgp_ribout.h index e90241afdc7..8a72e19d176 100644 --- a/src/bgp/bgp_ribout.h +++ b/src/bgp/bgp_ribout.h @@ -322,6 +322,7 @@ class RibOut { as_t local_as() const { return policy_.local_as_number; } bool as_override() const { return policy_.as_override; } bool llgr() const { return policy_.llgr; } + bool as4_supported() const { return policy_.as4_supported; } const IpAddress &nexthop() const { return policy_.nexthop; } bool IsEncodingXmpp() const { return (policy_.encoding == RibExportPolicy::XMPP); diff --git a/src/bgp/bgp_route.cc b/src/bgp/bgp_route.cc index ee9957041ee..72516026d3b 100644 --- a/src/bgp/bgp_route.cc +++ b/src/bgp/bgp_route.cc @@ -482,6 +482,9 @@ static void FillRoutePathExtCommunityInfo(const BgpTable *table, } else if (ExtCommunity::is_security_group(*it)) { SecurityGroup sg(*it); communities->push_back(sg.ToString()); + } else if (ExtCommunity::is_security_group4(*it)) { + SecurityGroup4ByteAs sg(*it); + communities->push_back(sg.ToString()); } else if (ExtCommunity::is_site_of_origin(*it)) { SiteOfOrigin soo(*it); communities->push_back(soo.ToString()); @@ -500,6 +503,9 @@ static void FillRoutePathExtCommunityInfo(const BgpTable *table, } else if (ExtCommunity::is_tag(*it)) { Tag tag(*it); communities->push_back(tag.ToString()); + } else if (ExtCommunity::is_tag4(*it)) { + Tag4ByteAs tag(*it); + communities->push_back(tag.ToString()); } else if (ExtCommunity::is_source_as(*it)) { SourceAs sas(*it); communities->push_back(sas.ToString()); diff --git a/src/bgp/bgp_server.cc b/src/bgp/bgp_server.cc index 54b062d41c8..61ffc76a8b0 100644 --- a/src/bgp/bgp_server.cc +++ b/src/bgp/bgp_server.cc @@ -461,6 +461,8 @@ BgpServer::BgpServer(EventManager *evm) logging_disabled_(false), mvpn_ipv4_enable_(false), aspath_db_(new AsPathDB(this)), + aspath_4byte_db_(new AsPath4ByteDB(this)), + as4path_db_(new As4PathDB(this)), olist_db_(new BgpOListDB(this)), cluster_list_db_(new ClusterListDB(this)), comm_db_(new CommunityDB(this)), diff --git a/src/bgp/bgp_server.h b/src/bgp/bgp_server.h index d30233c8481..5a0610692e3 100644 --- a/src/bgp/bgp_server.h +++ b/src/bgp/bgp_server.h @@ -24,6 +24,8 @@ #include "net/address.h" class AsPathDB; +class AsPath4ByteDB; +class As4PathDB; class BgpAttrDB; class BgpConditionListener; class BgpConfigManager; @@ -154,6 +156,8 @@ class BgpServer { } AsPathDB *aspath_db() { return aspath_db_.get(); } + AsPath4ByteDB *aspath_4byte_db() { return aspath_4byte_db_.get(); } + As4PathDB *as4path_db() { return as4path_db_.get(); } BgpAttrDB *attr_db() { return attr_db_.get(); } BgpOListDB *olist_db() { return olist_db_.get(); } ClusterListDB *cluster_list_db() { return cluster_list_db_.get(); } @@ -333,6 +337,8 @@ class BgpServer { // databases boost::scoped_ptr aspath_db_; + boost::scoped_ptr aspath_4byte_db_; + boost::scoped_ptr as4path_db_; boost::scoped_ptr olist_db_; boost::scoped_ptr cluster_list_db_; boost::scoped_ptr comm_db_; diff --git a/src/bgp/bgp_table.cc b/src/bgp/bgp_table.cc index 917c91ab462..302ceda5332 100644 --- a/src/bgp/bgp_table.cc +++ b/src/bgp/bgp_table.cc @@ -129,17 +129,24 @@ void BgpTable::RibOutDelete(const RibExportPolicy &policy) { ribout_map_.erase(loc); } -// -// Process Remove Private information. -// -void BgpTable::ProcessRemovePrivate(const RibOut *ribout, BgpAttr *attr) const { - if (!ribout->IsEncodingBgp()) - return; - if (!ribout->remove_private_enabled()) - return; - if (!attr->as_path()) - return; +void BgpTable::PrependLocalAs(const RibOut *ribout, BgpAttr *clone, + const IPeer* peer) const { + as_t local_as = ribout->local_as() ?: + clone->attr_db()->server()->local_autonomous_system(); + if (ribout->as4_supported()) { + if (peer && peer->IsAs4Supported()) + PrependAsToAsPath4Byte(clone, local_as); + else + CreateAsPath4Byte(clone, local_as); + } else { + if (peer && peer->IsAs4Supported()) + CreateAsPath2Byte(clone, local_as); + else + PrependAsToAsPath2Byte(clone, local_as); + } +} +void BgpTable::RemovePrivateAs(const RibOut *ribout, BgpAttr *attr) const { bool all = ribout->remove_private_all(); bool replace = ribout->remove_private_replace(); bool peer_loop_check = ribout->remove_private_peer_loop_check(); @@ -160,6 +167,102 @@ void BgpTable::ProcessRemovePrivate(const RibOut *ribout, BgpAttr *attr) const { delete new_spec; } +void BgpTable::RemovePrivate4ByteAs(const RibOut *ribout, BgpAttr *attr) const { + bool all = ribout->remove_private_all(); + bool replace = ribout->remove_private_replace(); + bool peer_loop_check = ribout->remove_private_peer_loop_check(); + + const AsPath4ByteSpec &spec = attr->aspath_4byte()->path(); + as_t peer_asn = peer_loop_check ? ribout->peer_as() : 0; + as_t replace_asn = 0; + if (replace) { + if (ribout->peer_type() == BgpProto::EBGP) { + replace_asn = server()->local_autonomous_system(); + } else { + replace_asn = spec.AsLeftMostPublic(); + } + } + + AsPath4ByteSpec *new_spec = spec.RemovePrivate(all, replace_asn, peer_asn); + attr->set_aspath_4byte(new_spec); + delete new_spec; +} + +void BgpTable::RemovePrivateAs4(const RibOut *ribout, BgpAttr *attr) const { + bool all = ribout->remove_private_all(); + bool replace = ribout->remove_private_replace(); + bool peer_loop_check = ribout->remove_private_peer_loop_check(); + + const As4PathSpec &spec = attr->as4_path()->path(); + as_t peer_asn = peer_loop_check ? ribout->peer_as() : 0; + as_t replace_asn = 0; + if (replace) { + if (ribout->peer_type() == BgpProto::EBGP) { + replace_asn = server()->local_autonomous_system(); + } else { + replace_asn = spec.AsLeftMostPublic(); + } + } + + As4PathSpec *new_spec = spec.RemovePrivate(all, replace_asn, peer_asn); + attr->set_as4_path(new_spec); + delete new_spec; +} + +// +// Process Remove Private information. +// +void BgpTable::ProcessRemovePrivate(const RibOut *ribout, BgpAttr *attr) const { + if (!ribout->IsEncodingBgp()) + return; + if (!ribout->remove_private_enabled()) + return; + + if (attr->as_path()) + RemovePrivateAs(ribout, attr); + if (attr->aspath_4byte()) + RemovePrivate4ByteAs(ribout, attr); + if (attr->as4_path()) + RemovePrivateAs4(ribout, attr); +} + +// +// Process Remove Private information. +// +void BgpTable::ProcessAsOverride(const RibOut *ribout, BgpAttr *attr) const { + if (ribout->as_override() && !attr->IsAsPathEmpty()) { + as_t local_as = ribout->local_as() ?: + attr->attr_db()->server()->local_autonomous_system(); + if (attr->as_path()) { + const AsPathSpec &as_path = attr->as_path()->path(); + if (local_as > AsPathSpec::kMaxPrivateAs) { + as2_t as_trans = AS_TRANS; + AsPathSpec *as_path_ptr = as_path.Replace( + ribout->peer_as(), as_trans); + attr->set_as_path(as_path_ptr); + delete as_path_ptr; + const As4Path *as4 = attr->as4_path(); + if (as4) + PrependAsToAs4Path(attr, NULL, NULL, local_as, true); + else + PrependAsToAs4Path(attr, NULL, NULL, local_as); + } else { + AsPathSpec *as_path_ptr = as_path.Replace( + ribout->peer_as(), local_as); + attr->set_as_path(as_path_ptr); + delete as_path_ptr; + } + } + if (attr->aspath_4byte()) { + const AsPath4ByteSpec &as_path = attr->aspath_4byte()->path(); + AsPath4ByteSpec *as_path_ptr = + as_path.Replace(ribout->peer_as(), local_as); + attr->set_aspath_4byte(as_path_ptr); + delete as_path_ptr; + } + } +} + // // Process Long Lived Graceful Restart state information. // @@ -229,6 +332,159 @@ void BgpTable::ProcessDefaultTunnelEncapsulation(const RibOut *ribout, } } +void BgpTable::PrependAsToAsPath2Byte(BgpAttr *attr, as2_t asn) const { + if (attr->as_path()) { + const AsPathSpec &as_path = attr->as_path()->path(); + AsPathSpec *as_path_ptr = as_path.Add(asn); + attr->set_as_path(as_path_ptr); + delete as_path_ptr; + } else { + AsPathSpec as_path; + AsPathSpec *as_path_ptr = as_path.Add(asn); + attr->set_as_path(as_path_ptr); + delete as_path_ptr; + } +} + +void BgpTable::PrependAsToAsPath2Byte(BgpAttr *clone, as_t asn) const { + if (asn <= AsPathSpec::kMaxPrivateAs) { + PrependAsToAsPath2Byte(clone, (as2_t)asn); + return; + } + as2_t as_trans = AS_TRANS; + PrependAsToAsPath2Byte(clone, as_trans); + PrependAsToAs4Path(clone, NULL, NULL, asn); +} + +void BgpTable::PrependAsToAsPath4Byte(BgpAttr *clone, as_t asn) const { + if (clone->aspath_4byte()) { + const AsPath4ByteSpec &as4_path = clone->aspath_4byte()->path(); + AsPath4ByteSpec *as4_path_ptr = as4_path.Add(asn); + clone->set_aspath_4byte(as4_path_ptr); + delete as4_path_ptr; + } else { + AsPath4ByteSpec as_path; + AsPath4ByteSpec *as_path_ptr = as_path.Add(asn); + clone->set_aspath_4byte(as_path_ptr); + delete as_path_ptr; + } +} + +void BgpTable::PrependAsToAs4Path(BgpAttr* attr, + As4PathSpec::PathSegment *as4ps, + As4PathSpec *as4_path, + as_t local_as, + bool update) const { + if (!update && !as4ps) { + as4ps = new As4PathSpec::PathSegment; + as4ps->path_segment_type = As4PathSpec::PathSegment::AS_SEQUENCE; + } + if (!update && !as4_path) { + as4_path = new As4PathSpec; + as4_path->path_segments.push_back(as4ps); + } + if (update) { + if (attr->as4_path()) + as4_path = const_cast(&attr->as4_path()->path()); + } + as4_path = as4_path->Add(local_as); + attr->set_as4_path(as4_path); + delete as4_path; +} + +// Create as_path (and as4_path) from as_path4byte +void BgpTable::CreateAsPath2Byte(BgpAttr *attr, as_t local_as) const { + AsPathSpec *new_as_path = new AsPathSpec; + As4PathSpec *new_as4_path = NULL; + As4PathSpec::PathSegment *new_as4ps = NULL; + if (attr->aspath_4byte()) { + const AsPath4ByteSpec &as_path4 = attr->aspath_4byte()->path(); + for (size_t i = 0; i < as_path4.path_segments.size(); i++) { + AsPathSpec::PathSegment *ps = new AsPathSpec::PathSegment; + AsPath4ByteSpec::PathSegment *ps4 = as_path4.path_segments[i]; + ps->path_segment_type = ps4->path_segment_type; + for (size_t j = ps4->path_segment.size(); j > 0; j--) { + as_t as4 = ps4->path_segment[j-1]; + if (as4 > AsPathSpec::kMaxPrivateAs) { + as2_t as_trans = AS_TRANS; + ps->path_segment.push_back(as_trans); + PrependAsToAs4Path(attr, new_as4ps, new_as4_path, as4); + } else { + ps->path_segment.push_back((as2_t)as4); + } + } + new_as_path->path_segments.push_back(ps); + if (new_as4ps) { + new_as4_path = new As4PathSpec; + new_as4_path->path_segments.push_back(new_as4ps); + } + } + } + if (local_as <= AsPathSpec::kMaxPrivateAs) { + AsPathSpec *as_path_ptr; + as_path_ptr = new_as_path->Add(local_as); + attr->set_as_path(as_path_ptr); + delete as_path_ptr; + } else { + PrependAsToAs4Path(attr, new_as4ps, new_as4_path, local_as); + } + attr->set_aspath_4byte(NULL); +} + +// Create aspath_4byte by merging as_path and as4_path +void BgpTable::CreateAsPath4Byte(BgpAttr *attr, as_t local_as) const { + AsPath4ByteSpec *aspath_4byte = new AsPath4ByteSpec; + if (attr->as_path()) { + const AsPathSpec &as_path = attr->as_path()->path(); + if (attr->as4_path()) { + const As4PathSpec &as4_path = attr->as4_path()->path(); + if (as_path.path_segments.size() < as4_path.path_segments.size()) + return; + uint32_t as4_seg_index = 0; + for (size_t i = 0; i < as_path.path_segments.size(); i++) { + AsPath4ByteSpec::PathSegment *ps4 = + new AsPath4ByteSpec::PathSegment; + AsPathSpec::PathSegment *ps = as_path.path_segments[i]; + ps4->path_segment_type = ps->path_segment_type; + uint32_t as4_index = 0; + bool as_trans_found = false; + for (size_t j = ps->path_segment.size(); j > 0; j--) { + as2_t as = ps->path_segment[j-1]; + if (as != AS_TRANS) + ps4->path_segment.push_back(as); + else { + as_trans_found = true; + As4PathSpec::PathSegment *ps4 = + as4_path.path_segments[as4_seg_index]; + if (as4_index >= ps4->path_segment.size()) + assert(0); + as_t as4 = ps4->path_segment[as4_index++]; + ps4->path_segment.push_back(as4); + } + } + if (as_trans_found) + as4_seg_index++; + aspath_4byte->path_segments.push_back(ps4); + } + } + } + AsPath4ByteSpec *as_path_ptr = aspath_4byte->Add(local_as); + attr->set_aspath_4byte(as_path_ptr); + delete as_path_ptr; +} + +bool BgpTable::IsAsPathLoop(const RibOut *ribout, const BgpAttr *attr) const { + if ((ribout->peer_as() <= AsPathSpec::kMaxPrivateAs) && attr->as_path() && + attr->as_path()->path().AsPathLoop(ribout->peer_as())) { + return true; + } + if (attr->aspath_4byte() && + attr->aspath_4byte()->path().AsPathLoop(ribout->peer_as())) { + return true; + } + return false; +} + UpdateInfo *BgpTable::GetUpdateInfo(RibOut *ribout, BgpRoute *route, const RibPeerSet &peerset) { const BgpPath *path = route->BestPath(); @@ -330,9 +586,9 @@ UpdateInfo *BgpTable::GetUpdateInfo(RibOut *ribout, BgpRoute *route, // then generate a Nil AsPath i.e. one with 0 length. No need // to modify the AsPath if it already exists since this is an // iBGP RibOut. - if (clone->as_path() == NULL) { - AsPathSpec as_path; - clone->set_as_path(&as_path); + if (clone->aspath_4byte() == NULL) { + AsPath4ByteSpec as_path; + clone->set_aspath_4byte(&as_path); } } else if (ribout->peer_type() == BgpProto::EBGP) { // Don't advertise routes from non-master instances if there's @@ -353,10 +609,8 @@ UpdateInfo *BgpTable::GetUpdateInfo(RibOut *ribout, BgpRoute *route, // Sender side AS path loop check and split horizon within RibOut. if (!ribout->as_override()) { - if (attr->as_path() && - attr->as_path()->path().AsPathLoop(ribout->peer_as())) { + if (IsAsPathLoop(ribout, attr)) return NULL; - } } else { if (peer && peer->PeerType() == BgpProto::EBGP) { ribout->GetSubsetPeerSet(&new_peerset, peer); @@ -384,36 +638,17 @@ UpdateInfo *BgpTable::GetUpdateInfo(RibOut *ribout, BgpRoute *route, // The AS path is NULL if the originating xmpp peer is locally // connected. It's non-NULL but empty if the originating xmpp // peer is connected to another bgp speaker in the iBGP mesh. - if (clone->med() && clone->as_path() && !clone->as_path()->empty()) + if (clone->med() && !clone->IsAsPathEmpty()) clone->set_med(0); - as_t local_as = ribout->local_as() ?: - clone->attr_db()->server()->local_autonomous_system(); - // Override the peer AS with local AS in AsPath. - if (ribout->as_override() && clone->as_path() != NULL) { - const AsPathSpec &as_path = clone->as_path()->path(); - AsPathSpec *as_path_ptr = - as_path.Replace(ribout->peer_as(), local_as); - clone->set_as_path(as_path_ptr); - delete as_path_ptr; - } + ProcessAsOverride(ribout, clone); // Remove private processing must happen before local AS prepend. ProcessRemovePrivate(ribout, clone); // Prepend the local AS to AsPath. - if (clone->as_path() != NULL) { - const AsPathSpec &as_path = clone->as_path()->path(); - AsPathSpec *as_path_ptr = as_path.Add(local_as); - clone->set_as_path(as_path_ptr); - delete as_path_ptr; - } else { - AsPathSpec as_path; - AsPathSpec *as_path_ptr = as_path.Add(local_as); - clone->set_as_path(as_path_ptr); - delete as_path_ptr; - } + PrependLocalAs(ribout, clone, peer); } assert(clone); diff --git a/src/bgp/bgp_table.h b/src/bgp/bgp_table.h index 18873e402a4..0aa4b893b0f 100644 --- a/src/bgp/bgp_table.h +++ b/src/bgp/bgp_table.h @@ -118,6 +118,14 @@ class BgpTable : public RouteTable { ExtCommunityPtr community) = 0; static bool PathSelection(const Path &path1, const Path &path2); + bool IsAsPathLoop(const RibOut *ribout, const BgpAttr *attr) const; + void CreateAsPath4Byte(BgpAttr *attr, as_t local_as) const; + void CreateAsPath2Byte(BgpAttr *attr, as_t local_as) const; + void PrependAsToAsPath4Byte(BgpAttr *attr, as_t asn) const; + void PrependAsToAsPath2Byte(BgpAttr *attr, as_t asn) const; + void PrependAsToAsPath2Byte(BgpAttr *attr, as2_t asn) const; + void PrependAsToAs4Path(BgpAttr* attr, As4PathSpec::PathSegment *as4ps, + As4PathSpec *as4_path, as_t asn, bool update = false) const; UpdateInfo *GetUpdateInfo(RibOut *ribout, BgpRoute *route, const RibPeerSet &peerset); void ProcessDefaultTunnelEncapsulation(const RibOut *ribout, @@ -194,7 +202,12 @@ class BgpTable : public RouteTable { class DeleteActor; + void PrependLocalAs(const RibOut *ribout, BgpAttr *attr, const IPeer*) const; + void ProcessAsOverride(const RibOut *ribout, BgpAttr *attr) const; void ProcessRemovePrivate(const RibOut *ribout, BgpAttr *attr) const; + void RemovePrivateAs(const RibOut *ribout, BgpAttr *attr) const; + void RemovePrivate4ByteAs(const RibOut *ribout, BgpAttr *attr) const; + void RemovePrivateAs4(const RibOut *ribout, BgpAttr *attr) const; void ProcessLlgrState(const RibOut *ribout, const BgpPath *path, BgpAttr *attr, bool llgr_stale_comm); virtual BgpRoute *TableFind(DBTablePartition *rtp, diff --git a/src/bgp/bgp_xmpp_channel.cc b/src/bgp/bgp_xmpp_channel.cc index 3c2f0f14ed0..115030c8a17 100644 --- a/src/bgp/bgp_xmpp_channel.cc +++ b/src/bgp/bgp_xmpp_channel.cc @@ -371,6 +371,7 @@ class BgpXmppChannel::XmppPeer : public IPeer { virtual int GetTotalPathCount() const { return total_path_count_; } + virtual bool IsAs4Supported() const { return true; } virtual void UpdatePrimaryPathCount(int count, Address::Family family) const { primary_path_count_ += count; @@ -1274,10 +1275,18 @@ bool BgpXmppChannel::ProcessItem(string vrf_name, } // Process tag list. + uint16_t tag_index = 0; for (TagListType::const_iterator tit = nit->tag_list.begin(); tit != nit->tag_list.end(); ++tit) { - Tag tag(bgp_server_->autonomous_system(), *tit); - ext.communities.push_back(tag.GetExtCommunityValue()); + if (bgp_server_->autonomous_system() <= 0xFFFF) { + Tag tag(bgp_server_->autonomous_system(), *tit); + ext.communities.push_back(tag.GetExtCommunityValue()); + } else { + Tag tag(tag_index, *tit); + Tag4ByteAs tag4(bgp_server_->autonomous_system(), tag_index++); + ext.communities.push_back(tag4.GetExtCommunityValue()); + ext.communities.push_back(tag.GetExtCommunityValue()); + } } BgpAttrLocalPref local_pref(item.entry.local_preference); @@ -1294,8 +1303,7 @@ bool BgpXmppChannel::ProcessItem(string vrf_name, attrs.push_back(&med); // Process community tags. - const CommunityTagListType &ict_list = - item.entry.community_tag_list; + 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; @@ -1326,12 +1334,20 @@ bool BgpXmppChannel::ProcessItem(string vrf_name, } // Process security group list. - const SecurityGroupListType &isg_list = - item.entry.security_group_list; + uint16_t sg_index = 0; + const SecurityGroupListType &isg_list = item.entry.security_group_list; for (SecurityGroupListType::const_iterator sit = isg_list.begin(); sit != isg_list.end(); ++sit) { - SecurityGroup sg(bgp_server_->autonomous_system(), *sit); - ext.communities.push_back(sg.GetExtCommunityValue()); + if (bgp_server_->autonomous_system() <= 0xFFFF) { + SecurityGroup sg(bgp_server_->autonomous_system(), *sit); + ext.communities.push_back(sg.GetExtCommunityValue()); + } else { + SecurityGroup sg(sg_index, *sit); + SecurityGroup4ByteAs sg4(bgp_server_->autonomous_system(), + sg_index++); + ext.communities.push_back(sg4.GetExtCommunityValue()); + ext.communities.push_back(sg.GetExtCommunityValue()); + } } if (item.entry.mobility.seqno) { @@ -1569,10 +1585,19 @@ bool BgpXmppChannel::ProcessInet6Item(string vrf_name, } // Process tag list. + uint16_t tag_index = 0; for (TagListType::const_iterator tit = nit->tag_list.begin(); tit != nit->tag_list.end(); ++tit) { - Tag tag(bgp_server_->autonomous_system(), *tit); - ext.communities.push_back(tag.GetExtCommunityValue()); + if (bgp_server_->autonomous_system() <= 0xFFFF) { + Tag tag(bgp_server_->autonomous_system(), *tit); + ext.communities.push_back(tag.GetExtCommunityValue()); + } else { + Tag tag(tag_index, *tit); + Tag4ByteAs tag4(bgp_server_->autonomous_system(), + tag_index++); + ext.communities.push_back(tag.GetExtCommunityValue()); + ext.communities.push_back(tag4.GetExtCommunityValue()); + } } BgpAttrLocalPref local_pref(item.entry.local_preference); @@ -1622,10 +1647,19 @@ bool BgpXmppChannel::ProcessInet6Item(string vrf_name, // Process security group list. const SecurityGroupListType &isg_list = item.entry.security_group_list; + uint16_t sg_index = 0; for (SecurityGroupListType::const_iterator sit = isg_list.begin(); sit != isg_list.end(); ++sit) { - SecurityGroup sg(bgp_server_->autonomous_system(), *sit); - ext.communities.push_back(sg.GetExtCommunityValue()); + if (bgp_server_->autonomous_system() <= 0xFFFF) { + SecurityGroup sg(bgp_server_->autonomous_system(), *sit); + ext.communities.push_back(sg.GetExtCommunityValue()); + } else { + SecurityGroup sg(sg_index, *sit); + SecurityGroup4ByteAs sg4(bgp_server_->autonomous_system(), + sg_index++); + ext.communities.push_back(sg4.GetExtCommunityValue()); + ext.communities.push_back(sg.GetExtCommunityValue()); + } } if (item.entry.mobility.seqno) { @@ -1886,10 +1920,18 @@ bool BgpXmppChannel::ProcessEnetItem(string vrf_name, } // Process tag list. + uint16_t tag_index = 0; for (TagListType::const_iterator tit = nit->tag_list.begin(); tit != nit->tag_list.end(); ++tit) { - Tag tag(bgp_server_->autonomous_system(), *tit); - ext.communities.push_back(tag.GetExtCommunityValue()); + if (bgp_server_->autonomous_system() <= 0xFFFF) { + Tag tag(bgp_server_->autonomous_system(), *tit); + ext.communities.push_back(tag.GetExtCommunityValue()); + } else { + Tag tag(tag_index, *tit); + Tag4ByteAs tag4(bgp_server_->autonomous_system(), tag_index++); + ext.communities.push_back(tag.GetExtCommunityValue()); + ext.communities.push_back(tag4.GetExtCommunityValue()); + } } BgpAttrLocalPref local_pref(item.entry.local_preference); diff --git a/src/bgp/bgp_xmpp_rtarget_manager.cc b/src/bgp/bgp_xmpp_rtarget_manager.cc index 0554d57cd59..75cfa8d29b8 100644 --- a/src/bgp/bgp_xmpp_rtarget_manager.cc +++ b/src/bgp/bgp_xmpp_rtarget_manager.cc @@ -96,7 +96,7 @@ uint32_t BgpXmppRTargetManager::GetRTargetRouteFlag( return flags; } -void BgpXmppRTargetManager::RTargetRouteOp(as4_t asn, +void BgpXmppRTargetManager::RTargetRouteOp(as_t asn, const RouteTarget &rtarget, BgpAttrPtr attr, bool add_change, uint32_t flags) const { @@ -120,7 +120,7 @@ void BgpXmppRTargetManager::RTargetRouteOp(as4_t asn, void BgpXmppRTargetManager::ASNUpdateCallback(as_t old_asn, as_t old_local_asn) const { - if (local_autonomous_system() == old_local_asn) + if (local_autonomous_system() == (int)old_local_asn) return; if (IsSubscriptionEmpty()) return; diff --git a/src/bgp/bgp_xmpp_rtarget_manager.h b/src/bgp/bgp_xmpp_rtarget_manager.h index 57b411b1f76..f041afe754c 100644 --- a/src/bgp/bgp_xmpp_rtarget_manager.h +++ b/src/bgp/bgp_xmpp_rtarget_manager.h @@ -37,7 +37,7 @@ class BgpXmppRTargetManager { const RouteTargetList &targets, uint32_t flags) const; protected: - virtual void RTargetRouteOp(as4_t asn, const RouteTarget &rtarget, + virtual void RTargetRouteOp(as_t asn, const RouteTarget &rtarget, BgpAttrPtr attr, bool add_change, uint32_t flags = 0) const; diff --git a/src/bgp/community.cc b/src/bgp/community.cc index 9f397b5e6b0..e55636742f8 100644 --- a/src/bgp/community.cc +++ b/src/bgp/community.cc @@ -23,6 +23,7 @@ #include "bgp/extended-community/source_as.h" #include "bgp/extended-community/tag.h" #include "bgp/extended-community/vrf_route_import.h" +#include "bgp/tunnel_encap/tunnel_encap.h" #include "bgp/origin-vn/origin_vn.h" #include "bgp/rtarget/rtarget_address.h" #include "bgp/security_group/security_group.h" @@ -360,6 +361,26 @@ bool ExtCommunity::ContainsOriginVn(const ExtCommunityValue &val) const { return false; } +bool ExtCommunity::ContainsOriginVn4(const ExtCommunityValue &val) const { + for (ExtCommunityList::const_iterator it = communities_.begin(); + it != communities_.end(); ++it) { + if (ExtCommunity::is_origin_vn4(*it) && *it == val) + return true; + } + return false; +} + +bool ExtCommunity::ContainsOriginVn(as_t asn, uint32_t vn_index) const { + if (asn <= 0xffffffff) { + OriginVn origin_vn(asn, vn_index); + return ContainsOriginVn(origin_vn.GetExtCommunity()); + } + OriginVn4ByteAs origin_vn4(asn, AS_TRANS); + OriginVn origin_vn(AS_TRANS, vn_index); + return (ContainsOriginVn(origin_vn.GetExtCommunity()) && + ContainsOriginVn(origin_vn4.GetExtCommunity())); +} + bool ExtCommunity::ContainsSourceAs(const ExtCommunityValue &val) const { for (ExtCommunityList::const_iterator it = communities_.begin(); it != communities_.end(); ++it) { @@ -392,7 +413,8 @@ void ExtCommunity::RemoveRTarget() { void ExtCommunity::RemoveSGID() { for (ExtCommunityList::iterator it = communities_.begin(); it != communities_.end(); ) { - if (ExtCommunity::is_security_group(*it)) { + if (ExtCommunity::is_security_group(*it) || + ExtCommunity::is_security_group4(*it)) { it = communities_.erase(it); } else { ++it; @@ -403,7 +425,7 @@ void ExtCommunity::RemoveSGID() { void ExtCommunity::RemoveTag() { for (ExtCommunityList::iterator it = communities_.begin(); it != communities_.end(); ) { - if (ExtCommunity::is_tag(*it)) { + if (ExtCommunity::is_tag(*it) || ExtCommunity::is_tag4(*it)) { it = communities_.erase(it); } else { ++it; @@ -446,7 +468,8 @@ void ExtCommunity::RemoveVrfRouteImport() { void ExtCommunity::RemoveOriginVn() { for (ExtCommunityList::iterator it = communities_.begin(); it != communities_.end(); ) { - if (ExtCommunity::is_origin_vn(*it)) { + if (ExtCommunity::is_origin_vn(*it) || + ExtCommunity::is_origin_vn4(*it)) { it = communities_.erase(it); } else { ++it; @@ -495,7 +518,7 @@ vector ExtCommunity::GetTunnelEncap() const { return encap_list; } -vector ExtCommunity::GetTagList(as_t asn) const { +vector ExtCommunity::GetTagList(as2_t asn) const { vector tag_list; for (ExtCommunityList::const_iterator iter = communities_.begin(); iter != communities_.end(); ++iter) { @@ -513,6 +536,29 @@ vector ExtCommunity::GetTagList(as_t asn) const { return tag_list; } +vector ExtCommunity::GetTag4List(as_t asn) const { + vector tag_list; + for (ExtCommunityList::const_iterator iter = communities_.begin(); + iter != communities_.end(); ++iter) { + if (!ExtCommunity::is_tag4(*iter)) + continue; + Tag4ByteAs tag_comm(*iter); + if (asn && tag_comm.as_number() != asn && !tag_comm.IsGlobal()) + continue; + vector matching_tag_list = GetTagList(tag_comm.tag()); + tag_list.insert(tag_list.end(), matching_tag_list.begin(), + matching_tag_list.end()); + tag_list.push_back(tag_comm.tag()); + } + if ((asn <= 0xffffffff) && tag_list.size() == 0) + tag_list = GetTagList(asn); + + sort(tag_list.begin(), tag_list.end()); + vector::iterator tag_iter = unique(tag_list.begin(), tag_list.end()); + tag_list.erase(tag_iter, tag_list.end()); + return tag_list; +} + bool ExtCommunity::ContainsTunnelEncapVxlan() const { for (ExtCommunityList::const_iterator iter = communities_.begin(); iter != communities_.end(); ++iter) { @@ -528,10 +574,10 @@ bool ExtCommunity::ContainsTunnelEncapVxlan() const { int ExtCommunity::GetOriginVnIndex() const { for (ExtCommunityList::const_iterator iter = communities_.begin(); iter != communities_.end(); ++iter) { - if (!ExtCommunity::is_origin_vn(*iter)) - continue; - OriginVn origin_vn(*iter); - return origin_vn.vn_index(); + if (ExtCommunity::is_origin_vn(*iter)) { + OriginVn origin_vn(*iter); + return origin_vn.vn_index(); + } } return -1; } diff --git a/src/bgp/community.h b/src/bgp/community.h index ad2c2952bbe..32d15508a73 100644 --- a/src/bgp/community.h +++ b/src/bgp/community.h @@ -166,7 +166,9 @@ class ExtCommunity { virtual void Remove(); int CompareTo(const ExtCommunity &rhs) const; + bool ContainsOriginVn(as_t asn, uint32_t vn_index) const; bool ContainsOriginVn(const ExtCommunityValue &val) const; + bool ContainsOriginVn4(const ExtCommunityValue &val) const; bool ContainsVrfRouteImport(const ExtCommunityValue &val) const; bool ContainsSourceAs(const ExtCommunityValue &val) const; @@ -176,11 +178,22 @@ class ExtCommunity { } std::vector GetTunnelEncap() const; - std::vector GetTagList(as_t asn = 0) const; + std::vector GetTagList(as2_t asn = 0) const; + std::vector GetTag4List(as_t asn = 0) const; bool ContainsTunnelEncapVxlan() const; int GetOriginVnIndex() const; static ExtCommunityList ExtCommunityFromString(const std::string &comm); + static bool is_origin_vn4(const ExtCommunityValue &val) { + // + // Origin VN extended community + // 2 Octet AS specific extended community + // + return (val[0] == BgpExtendedCommunityType::Experimental4ByteAs) && + (val[1] == + BgpExtendedCommunityExperimentalSubType::OriginVn); + } + static bool is_origin_vn(const ExtCommunityValue &val) { // // Origin VN extended community @@ -262,6 +275,15 @@ class ExtCommunity { (val[1] == BgpExtendedCommunityExperimentalSubType::SgId); } + static bool is_security_group4(const ExtCommunityValue &val) { + // + // SG ID extended community + // 2 Octet AS specific extended community + // + return (val[0] == BgpExtendedCommunityType::Experimental4ByteAs) && + (val[1] == BgpExtendedCommunityExperimentalSubType::SgId); + } + static bool is_site_of_origin(const ExtCommunityValue &val) { // // Site of Origin / Route Origin extended community @@ -313,6 +335,12 @@ class ExtCommunity { (val[1] == BgpExtendedCommunityExperimentalSubType::Tag); } + static bool is_tag4(const ExtCommunityValue &val) { + // Tag extended community + return (val[0] == BgpExtendedCommunityType::Experimental4ByteAs) && + (val[1] == BgpExtendedCommunityExperimentalSubType::Tag); + } + friend std::size_t hash_value(ExtCommunity const &comm) { size_t hash = 0; for (ExtCommunityList::const_iterator iter = comm.communities_.begin(); diff --git a/src/bgp/ermvpn/ermvpn_table.cc b/src/bgp/ermvpn/ermvpn_table.cc index 03194ccfc5d..3f45ee36f0b 100644 --- a/src/bgp/ermvpn/ermvpn_table.cc +++ b/src/bgp/ermvpn/ermvpn_table.cc @@ -88,9 +88,8 @@ BgpRoute *ErmVpnTable::RouteReplicate(BgpServer *server, return NULL; // Don't replicate to VRF from the VPN table if OriginVn doesn't match. - OriginVn origin_vn(server->autonomous_system(), - routing_instance()->virtual_network_index()); - if (!community->ContainsOriginVn(origin_vn.GetExtCommunity())) + if (!community->ContainsOriginVn(server->autonomous_system(), + routing_instance()->virtual_network_index())) return NULL; } diff --git a/src/bgp/evpn/evpn_table.cc b/src/bgp/evpn/evpn_table.cc index a81accd717b..39c29f575a7 100644 --- a/src/bgp/evpn/evpn_table.cc +++ b/src/bgp/evpn/evpn_table.cc @@ -144,9 +144,8 @@ BgpRoute *EvpnTable::RouteReplicate(BgpServer *server, return NULL; // Don't replicate to VRF from the VPN table if OriginVn doesn't match. - OriginVn origin_vn(server->autonomous_system(), - routing_instance()->virtual_network_index()); - if (!community->ContainsOriginVn(origin_vn.GetExtCommunity())) + if (!community->ContainsOriginVn(server->autonomous_system(), + routing_instance()->virtual_network_index())) return NULL; } diff --git a/src/bgp/extended-community/tag.cc b/src/bgp/extended-community/tag.cc index 3d495ac7fdb..8d080e213fc 100644 --- a/src/bgp/extended-community/tag.cc +++ b/src/bgp/extended-community/tag.cc @@ -19,17 +19,17 @@ Tag::Tag(const bytes_type &data) { copy(data.begin(), data.end(), data_.begin()); } -Tag::Tag(as_t asn, int tag) { +Tag::Tag(as2_t asn, int tag) { data_[0] = BgpExtendedCommunityType::Experimental; data_[1] = BgpExtendedCommunityExperimentalSubType::Tag; put_value(&data_[2], 2, asn); // ASN put_value(&data_[4], 4, tag); // Tag value } -as_t Tag::as_number() const { +as2_t Tag::as_number() const { if (data_[0] == BgpExtendedCommunityType::Experimental && data_[1] == BgpExtendedCommunityExperimentalSubType::Tag) { - as_t as_number = get_value(data_.data() + 2, 2); + as2_t as_number = get_value(data_.data() + 2, 2); return as_number; } return 0; @@ -53,3 +53,42 @@ string Tag::ToString() const { snprintf(temp, sizeof(temp), "tag:%u:%u", as_number(), tag()); return string(temp); } + +Tag4ByteAs::Tag4ByteAs(const bytes_type &data) { + copy(data.begin(), data.end(), data_.begin()); +} + +Tag4ByteAs::Tag4ByteAs(as_t asn, int tag) { + data_[0] = BgpExtendedCommunityType::Experimental4ByteAs; + data_[1] = BgpExtendedCommunityExperimentalSubType::Tag; + put_value(&data_[2], 4, asn); // ASN + put_value(&data_[4], 2, tag); // Tag value +} + +as_t Tag4ByteAs::as_number() const { + if (data_[0] == BgpExtendedCommunityType::Experimental4ByteAs && + data_[1] == BgpExtendedCommunityExperimentalSubType::Tag) { + as_t as_number = get_value(data_.data() + 2, 4); + return as_number; + } + return 0; +} + +int Tag4ByteAs::tag() const { + if (data_[0] == BgpExtendedCommunityType::Experimental4ByteAs && + data_[1] == BgpExtendedCommunityExperimentalSubType::Tag) { + int value = get_value(&data_[6], 2); + return value; + } + return 0; +} + +bool Tag4ByteAs::IsGlobal() const { + return (tag() >= kMinGlobalId); +} + +string Tag4ByteAs::ToString() const { + char temp[50]; + snprintf(temp, sizeof(temp), "tag:%u:%u", as_number(), tag()); + return string(temp); +} diff --git a/src/bgp/extended-community/tag.h b/src/bgp/extended-community/tag.h index e9793e4f640..2ac0bb95b92 100644 --- a/src/bgp/extended-community/tag.h +++ b/src/bgp/extended-community/tag.h @@ -19,7 +19,29 @@ class Tag { typedef boost::array bytes_type; explicit Tag(const bytes_type &data); - explicit Tag(as_t asn, int tag); + explicit Tag(as2_t asn, int tag); + std::string ToString() const; + + bool IsGlobal() const; + as2_t as_number() const; + int tag() const; + + const uint64_t GetExtCommunityValue() const { + return get_value(data_.begin(), 8); + } + +private: + bytes_type data_; +}; + +class Tag4ByteAs { +public: + static const int kSize = 8; + static const int kMinGlobalId = 8000000; + typedef boost::array bytes_type; + + explicit Tag4ByteAs(const bytes_type &data); + explicit Tag4ByteAs(as_t asn, int tag); std::string ToString() const; bool IsGlobal() const; diff --git a/src/bgp/extended-community/types.h b/src/bgp/extended-community/types.h index d4b32982bd2..41cc18cf9e5 100644 --- a/src/bgp/extended-community/types.h +++ b/src/bgp/extended-community/types.h @@ -13,6 +13,7 @@ struct BgpExtendedCommunityType { Opaque = 0x03, Evpn = 0x06, Experimental = 0x80, + Experimental4ByteAs = 0x82, }; }; diff --git a/src/bgp/ipeer.h b/src/bgp/ipeer.h index 73138f207d0..4b5f21963a8 100644 --- a/src/bgp/ipeer.h +++ b/src/bgp/ipeer.h @@ -208,6 +208,7 @@ class IPeer : public IPeerUpdate { virtual const std::string GetStateName() const = 0; virtual void UpdateTotalPathCount(int count) const = 0; virtual int GetTotalPathCount() const = 0; + virtual bool IsAs4Supported() const = 0; virtual void ProcessPathTunnelEncapsulation(const BgpPath *path, BgpAttr *attr, ExtCommunityDB *extcomm_db, const BgpTable *table) const = 0; diff --git a/src/bgp/l3vpn/test/inetvpn_peer_test.cc b/src/bgp/l3vpn/test/inetvpn_peer_test.cc index ebadcdbbaeb..bf92dbca515 100644 --- a/src/bgp/l3vpn/test/inetvpn_peer_test.cc +++ b/src/bgp/l3vpn/test/inetvpn_peer_test.cc @@ -495,9 +495,9 @@ TEST_P(L3VPNPeerTest, AsPathLoop) { // Verify that path is not replicated to VRF table // // Verify that path in bgp.l3vpn.0 is marked as infeasible // /////////////////////////////////////////////////////////////////////////// - AsPathSpec path_spec; - AsPathSpec::PathSegment *path_seg = new AsPathSpec::PathSegment; - path_seg->path_segment_type = AsPathSpec::PathSegment::AS_SEQUENCE; + AsPath4ByteSpec path_spec; + AsPath4ByteSpec::PathSegment *path_seg = new AsPath4ByteSpec::PathSegment; + path_seg->path_segment_type = AsPath4ByteSpec::PathSegment::AS_SEQUENCE; path_seg->path_segment.push_back(peer_type_ == "EBGP" ? 101 : 100); path_spec.path_segments.push_back(path_seg); BgpAttrSpec asloop_attrs; diff --git a/src/bgp/l3vpn/test/inetvpn_table_test.cc b/src/bgp/l3vpn/test/inetvpn_table_test.cc index 97fc824f6be..147b9e20d41 100644 --- a/src/bgp/l3vpn/test/inetvpn_table_test.cc +++ b/src/bgp/l3vpn/test/inetvpn_table_test.cc @@ -36,6 +36,7 @@ class BgpPeerMock : public IPeer { virtual const std::string GetStateName() const { return "UNKNOWN"; } virtual void UpdateTotalPathCount(int count) const { } virtual int GetTotalPathCount() const { return 0; } + virtual bool IsAs4Supported() const { return false; } virtual void UpdatePrimaryPathCount(int count, Address::Family family) const { } virtual int GetPrimaryPathCount() const { return 0; } diff --git a/src/bgp/origin-vn/origin_vn.cc b/src/bgp/origin-vn/origin_vn.cc index 1e3acd276f4..0f9f39ec0a6 100644 --- a/src/bgp/origin-vn/origin_vn.cc +++ b/src/bgp/origin-vn/origin_vn.cc @@ -2,6 +2,7 @@ * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved. */ +#include "bgp/extended-community/types.h" #include "bgp/origin-vn/origin_vn.h" #include @@ -18,9 +19,9 @@ OriginVn::OriginVn() { data_.fill(0); } -OriginVn::OriginVn(as_t asn, uint32_t vn_index) { - data_[0] = 0x80; - data_[1] = 0x71; +OriginVn::OriginVn(as2_t asn, uint32_t vn_index) { + data_[0] = BgpExtendedCommunityType::Experimental; + data_[1] = BgpExtendedCommunityExperimentalSubType::OriginVn; put_value(&data_[2], 2, asn); put_value(&data_[4], 4, vn_index); } @@ -86,24 +87,26 @@ OriginVn OriginVn::FromString(const string &str, return OriginVn::null_originvn; } - data[0] = 0x80; - data[1] = 0x71; + data[0] = BgpExtendedCommunityType::Experimental; + data[1] = BgpExtendedCommunityExperimentalSubType::OriginVn; put_value(&data[2], 2, asn); put_value(&data[4], 4, value); copy(&data[0], &data[OriginVn::kSize], origin_vn.data_.begin()); return origin_vn; } -as_t OriginVn::as_number() const { - if (data_[0] == 0x80 && data_[1] == 0x71) { - as_t as_number = get_value(data_.data() + 2, 2); +as2_t OriginVn::as_number() const { + if (data_[0] == BgpExtendedCommunityType::Experimental && + data_[1] == BgpExtendedCommunityExperimentalSubType::OriginVn) { + as2_t as_number = get_value(data_.data() + 2, 2); return as_number; } return 0; } int OriginVn::vn_index() const { - if (data_[0] == 0x80 && data_[1] == 0x71) { + if (data_[0] == BgpExtendedCommunityType::Experimental && + data_[1] == BgpExtendedCommunityExperimentalSubType::OriginVn) { int vn_index = get_value(data_.data() + 4, 4); return vn_index; } @@ -119,3 +122,113 @@ string OriginVn::ToString() { snprintf(temp, sizeof(temp), "originvn:%u:%u", as_number(), vn_index()); return string(temp); } + +OriginVn4ByteAs OriginVn4ByteAs::null_originvn; + +OriginVn4ByteAs::OriginVn4ByteAs() { + data_.fill(0); +} + +OriginVn4ByteAs::OriginVn4ByteAs(as_t asn, uint32_t vn_index) { + data_[0] = BgpExtendedCommunityType::Experimental4ByteAs; + data_[1] = BgpExtendedCommunityExperimentalSubType::OriginVn; + put_value(&data_[2], 4, asn); + put_value(&data_[4], 2, vn_index); +} + +OriginVn4ByteAs::OriginVn4ByteAs(const bytes_type &data) { + copy(data.begin(), data.end(), data_.begin()); +} + +OriginVn4ByteAs OriginVn4ByteAs::FromString(const string &str, + boost::system::error_code *errorp) { + OriginVn4ByteAs origin_vn; + uint8_t data[OriginVn4ByteAs::kSize]; + size_t pos = str.find(':'); + if (pos == string::npos) { + if (errorp != NULL) { + *errorp = make_error_code(boost::system::errc::invalid_argument); + } + return OriginVn4ByteAs::null_originvn; + } + + string first(str.substr(0, pos)); + if (first != "originvn") { + if (errorp != NULL) { + *errorp = make_error_code(boost::system::errc::invalid_argument); + } + return OriginVn4ByteAs::null_originvn; + } + + string rest(str.substr(pos+1)); + + pos = rest.find(':'); + if (pos == string::npos) { + if (errorp != NULL) { + *errorp = make_error_code(boost::system::errc::invalid_argument); + } + return OriginVn4ByteAs::null_originvn; + } + + string second(rest.substr(0, pos)); + char *endptr; + int64_t asn = strtol(second.c_str(), &endptr, 10); + if (asn == 0 || asn >= 65535 || *endptr != '\0') { + if (errorp != NULL) { + *errorp = make_error_code(boost::system::errc::invalid_argument); + } + return OriginVn4ByteAs::null_originvn; + } + + string third(rest.substr(pos+1)); + uint64_t value = strtol(third.c_str(), &endptr, 10); + if (*endptr != '\0') { + if (errorp != NULL) { + *errorp = make_error_code(boost::system::errc::invalid_argument); + } + return OriginVn4ByteAs::null_originvn; + } + + // Check assigned number. + if (value > 0xFFFFFFFF) { + if (errorp != NULL) { + *errorp = make_error_code(boost::system::errc::invalid_argument); + } + return OriginVn4ByteAs::null_originvn; + } + + data[0] = BgpExtendedCommunityType::Experimental4ByteAs; + data[1] = BgpExtendedCommunityExperimentalSubType::OriginVn; + put_value(&data[2], 4, asn); + put_value(&data[4], 2, value); + copy(&data[0], &data[OriginVn4ByteAs::kSize], origin_vn.data_.begin()); + return origin_vn; +} + +as_t OriginVn4ByteAs::as_number() const { + if (data_[0] == BgpExtendedCommunityType::Experimental4ByteAs && + data_[1] == BgpExtendedCommunityExperimentalSubType::OriginVn) { + as_t as_number = get_value(data_.data() + 2, 4); + return as_number; + } + return 0; +} + +int OriginVn4ByteAs::vn_index() const { + if (data_[0] == BgpExtendedCommunityType::Experimental && + data_[1] == BgpExtendedCommunityExperimentalSubType::OriginVn) { + int vn_index = get_value(data_.data() + 6, 2); + return vn_index; + } + return 0; +} + +bool OriginVn4ByteAs::IsGlobal() const { + return (vn_index() >= kMinGlobalId); +} + +string OriginVn4ByteAs::ToString() { + char temp[50]; + snprintf(temp, sizeof(temp), "originvn:%u:%u", as_number(), vn_index()); + return string(temp); +} diff --git a/src/bgp/origin-vn/origin_vn.h b/src/bgp/origin-vn/origin_vn.h index 5697b2c1dec..5908ae08608 100644 --- a/src/bgp/origin-vn/origin_vn.h +++ b/src/bgp/origin-vn/origin_vn.h @@ -21,13 +21,13 @@ class OriginVn { typedef boost::array bytes_type; OriginVn(); - OriginVn(as_t asn, uint32_t vn_idx); + OriginVn(as2_t asn, uint32_t vn_idx); explicit OriginVn(const bytes_type &data); bool IsNull() { return operator==(OriginVn::null_originvn); } bool IsGlobal() const; - as_t as_number() const; + as2_t as_number() const; int vn_index() const; const bytes_type &GetExtCommunity() const { @@ -53,4 +53,44 @@ class OriginVn { bytes_type data_; }; +class OriginVn4ByteAs { +public: + static const int kSize = 8; + static const int kMinGlobalId = 8000000; + static OriginVn4ByteAs null_originvn; + typedef boost::array bytes_type; + + OriginVn4ByteAs(); + OriginVn4ByteAs(as_t asn, uint32_t vn_idx); + explicit OriginVn4ByteAs(const bytes_type &data); + + bool IsNull() { return operator==(OriginVn4ByteAs::null_originvn); } + bool IsGlobal() const; + + as_t as_number() const; + int vn_index() const; + + const bytes_type &GetExtCommunity() const { + return data_; + } + + const uint64_t GetExtCommunityValue() const { + return get_value(data_.begin(), 8); + } + + bool operator<(const OriginVn4ByteAs &rhs) const { + return data_ < rhs.data_; + } + bool operator==(const OriginVn4ByteAs &rhs) const { + return data_ == rhs.data_; + } + + std::string ToString(); + static OriginVn4ByteAs FromString(const std::string &str, + boost::system::error_code *error = NULL); + +private: + bytes_type data_; +}; + #endif // SRC_BGP_ORIGIN_VN_ORIGIN_VN_H_ diff --git a/src/bgp/routing-instance/path_resolver.cc b/src/bgp/routing-instance/path_resolver.cc index 9c1ccdc395a..f8eefcc5af0 100644 --- a/src/bgp/routing-instance/path_resolver.cc +++ b/src/bgp/routing-instance/path_resolver.cc @@ -943,7 +943,8 @@ static ExtCommunityPtr UpdateExtendedCommunity(ExtCommunityDB *extcomm_db, ExtCommunity::ExtCommunityValue const *lb = NULL; BOOST_FOREACH(const ExtCommunity::ExtCommunityValue &value, nh_ext_community->communities()) { - if (ExtCommunity::is_security_group(value)) { + if (ExtCommunity::is_security_group(value) || + ExtCommunity::is_security_group4(value)) { sgid_list.push_back(value); } else if (ExtCommunity::is_tunnel_encap(value)) { encap_list.push_back(value); diff --git a/src/bgp/routing-instance/routing_instance.cc b/src/bgp/routing-instance/routing_instance.cc index f787cfc8c7b..4282eae9da6 100644 --- a/src/bgp/routing-instance/routing_instance.cc +++ b/src/bgp/routing-instance/routing_instance.cc @@ -1161,7 +1161,7 @@ void RoutingInstance::FlushRouteAggregationConfig() { } } -void RoutingInstance::DeleteMvpnRTargetRoute(as4_t asn, Ip4Address old_ip) { +void RoutingInstance::DeleteMvpnRTargetRoute(as_t asn, Ip4Address old_ip) { if (asn == 0) return; string id_str = "target:" + old_ip.to_string() + ":0"; @@ -1169,7 +1169,7 @@ void RoutingInstance::DeleteMvpnRTargetRoute(as4_t asn, Ip4Address old_ip) { DeleteRTargetRoute(asn, rtarget); } -void RoutingInstance::AddMvpnRTargetRoute(as4_t asn) { +void RoutingInstance::AddMvpnRTargetRoute(as_t asn) { if (asn == 0) return; const Ip4Address server_ip(server()->bgp_identifier()); @@ -1482,7 +1482,7 @@ void RoutingInstance::AddRTargetRoute(uint32_t asn, route, "Insert Local path with path id " << index_); } -void RoutingInstance::DeleteRTargetRoute(as4_t asn, +void RoutingInstance::DeleteRTargetRoute(as_t asn, const RouteTarget &rtarget) { CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper"); @@ -1512,7 +1512,7 @@ void RoutingInstance::DeleteRTargetRoute(as4_t asn, } } -void RoutingInstance::InitAllRTargetRoutes(as4_t asn) { +void RoutingInstance::InitAllRTargetRoutes(as_t asn) { if (is_master_) return; @@ -1523,7 +1523,7 @@ void RoutingInstance::InitAllRTargetRoutes(as4_t asn) { } } -void RoutingInstance::FlushAllRTargetRoutes(as4_t asn) { +void RoutingInstance::FlushAllRTargetRoutes(as_t asn) { if (is_master_) return; @@ -1533,7 +1533,7 @@ void RoutingInstance::FlushAllRTargetRoutes(as4_t asn) { } } -void RoutingInstance::ProcessIdentifierUpdate(as4_t asn) { +void RoutingInstance::ProcessIdentifierUpdate(as_t asn) { FlushAllRTargetRoutes(asn); InitAllRTargetRoutes(asn); rd_.reset(new RouteDistinguisher(server_->bgp_identifier(), index_)); diff --git a/src/bgp/routing-instance/routing_instance.h b/src/bgp/routing-instance/routing_instance.h index d7d243896c8..850e325ec28 100644 --- a/src/bgp/routing-instance/routing_instance.h +++ b/src/bgp/routing-instance/routing_instance.h @@ -198,14 +198,14 @@ class RoutingInstance { friend class RoutingInstanceMgr; class DeleteActor; - void AddMvpnRTargetRoute(as4_t asn); - void DeleteMvpnRTargetRoute(as4_t old_asn, Ip4Address old_ip); - - void AddRTargetRoute(as4_t asn, const RouteTarget &rtarget); - void DeleteRTargetRoute(as4_t asn, const RouteTarget &rtarget); - void InitAllRTargetRoutes(as4_t asn); - void FlushAllRTargetRoutes(as4_t asn); - void ProcessIdentifierUpdate(as4_t asn); + void AddMvpnRTargetRoute(as_t asn); + void DeleteMvpnRTargetRoute(as_t old_asn, Ip4Address old_ip); + + void AddRTargetRoute(as_t asn, const RouteTarget &rtarget); + void DeleteRTargetRoute(as_t asn, const RouteTarget &rtarget); + void InitAllRTargetRoutes(as_t asn); + void FlushAllRTargetRoutes(as_t asn); + void ProcessIdentifierUpdate(as_t asn); void AddRouteTarget(bool import, std::vector *change_list, RouteTargetList::const_iterator it); diff --git a/src/bgp/routing-instance/service_chaining.cc b/src/bgp/routing-instance/service_chaining.cc index 72dc0c76f9c..fb929646166 100644 --- a/src/bgp/routing-instance/service_chaining.cc +++ b/src/bgp/routing-instance/service_chaining.cc @@ -213,8 +213,9 @@ bool ServiceChain::Match(BgpServer *server, BgpTable *table, BgpRoute *route, server->autonomous_system(), src_vn_index); const OriginVnPath *ovnpath = attr ? attr->origin_vn_path() : NULL; - if (ovnpath && - ovnpath->Contains(src_origin_vn.GetExtCommunity())) { + if (ovnpath && ovnpath->Contains( + server->autonomous_system(), src_vn_index)) { + //ovnpath->Contains(src_origin_vn.GetExtCommunity())) { deleted = true; } } diff --git a/src/bgp/routing-policy/routing_policy_action.cc b/src/bgp/routing-policy/routing_policy_action.cc index 156f84f9676..1988cd099d3 100644 --- a/src/bgp/routing-policy/routing_policy_action.cc +++ b/src/bgp/routing-policy/routing_policy_action.cc @@ -18,23 +18,23 @@ using std::ostringstream; using std::string; using std::vector; -UpdateAsPath::UpdateAsPath(const vector &asn_list) +UpdateAsPath::UpdateAsPath(const vector &asn_list) : asn_list_(asn_list) { } void UpdateAsPath::operator()(BgpAttr *attr) const { if (!attr) return; - const AsPath *as_path = attr->as_path(); + const AsPath4Byte *as_path = attr->aspath_4byte(); if (as_path) { - const AsPathSpec &as_path_spec = as_path->path(); - AsPathSpec *as_path_spec_ptr = as_path_spec.Add(asn_list_); - attr->set_as_path(as_path_spec_ptr); + const AsPath4ByteSpec &as_path_spec = as_path->path(); + AsPath4ByteSpec *as_path_spec_ptr = as_path_spec.Add(asn_list_); + attr->set_aspath_4byte(as_path_spec_ptr); delete as_path_spec_ptr; } else { - AsPathSpec as_path_spec; - AsPathSpec *as_path_spec_ptr = as_path_spec.Add(asn_list_); - attr->set_as_path(as_path_spec_ptr); + AsPath4ByteSpec as_path_spec; + AsPath4ByteSpec *as_path_spec_ptr = as_path_spec.Add(asn_list_); + attr->set_aspath_4byte(as_path_spec_ptr); delete as_path_spec_ptr; } } @@ -42,7 +42,7 @@ void UpdateAsPath::operator()(BgpAttr *attr) const { string UpdateAsPath::ToString() const { ostringstream oss; oss << "as-path expand [ "; - BOOST_FOREACH(uint16_t asn, asn_list_) { + BOOST_FOREACH(uint32_t asn, asn_list_) { oss << asn << ","; } oss.seekp(-1, oss.cur); diff --git a/src/bgp/routing-policy/routing_policy_action.h b/src/bgp/routing-policy/routing_policy_action.h index 77d4628d739..bc0abe262d8 100644 --- a/src/bgp/routing-policy/routing_policy_action.h +++ b/src/bgp/routing-policy/routing_policy_action.h @@ -81,16 +81,16 @@ class RoutingPolicyNexTermAction : public RoutingPolicyAction { class UpdateAsPath : public RoutingPolicyUpdateAction { public: - UpdateAsPath(const std::vector &asn_list); + UpdateAsPath(const std::vector &asn_list); virtual ~UpdateAsPath() {} virtual void operator()(BgpAttr *out_attr) const; std::string ToString() const; virtual bool IsEqual(const RoutingPolicyAction &as_path) const; - const std::vector &asn_list() const { return asn_list_; } + const std::vector &asn_list() const { return asn_list_; } private: - std::vector asn_list_; + std::vector asn_list_; }; class UpdateCommunity : public RoutingPolicyUpdateAction { diff --git a/src/bgp/rtarget/rtarget_prefix.cc b/src/bgp/rtarget/rtarget_prefix.cc index 4665316a593..f8176513ffc 100644 --- a/src/bgp/rtarget/rtarget_prefix.cc +++ b/src/bgp/rtarget/rtarget_prefix.cc @@ -25,13 +25,13 @@ int RTargetPrefix::FromProtoPrefix(const BgpProtoPrefix &proto_prefix, return 0; } - size_t expected_nlri_size = sizeof(as4_t) + RouteTarget::kSize; + size_t expected_nlri_size = sizeof(as_t) + RouteTarget::kSize; if (nlri_size != expected_nlri_size) return -1; size_t as_offset = 0; - prefix->as_ = get_value(&proto_prefix.prefix[as_offset], sizeof(as4_t)); - size_t rtarget_offset = as_offset + sizeof(as4_t); + prefix->as_ = get_value(&proto_prefix.prefix[as_offset], sizeof(as_t)); + size_t rtarget_offset = as_offset + sizeof(as_t); RouteTarget::bytes_type bt = { { 0 } }; copy(proto_prefix.prefix.begin() + rtarget_offset, proto_prefix.prefix.end(), bt.begin()); @@ -57,12 +57,12 @@ void RTargetPrefix::BuildProtoPrefix(BgpProtoPrefix *proto_prefix) const { return; } - size_t nlri_size = sizeof(as4_t) + RouteTarget::kSize; + size_t nlri_size = sizeof(as_t) + RouteTarget::kSize; proto_prefix->prefix.resize(nlri_size); proto_prefix->prefixlen = nlri_size * 8; size_t as_offset = 0; - put_value(&proto_prefix->prefix[as_offset], sizeof(as4_t), as_); - size_t rtarget_offset = as_offset + sizeof(as4_t); + put_value(&proto_prefix->prefix[as_offset], sizeof(as_t), as_); + size_t rtarget_offset = as_offset + sizeof(as_t); put_value(&proto_prefix->prefix[rtarget_offset], RouteTarget::kSize, rtarget_.GetExtCommunityValue()); } @@ -81,7 +81,7 @@ RTargetPrefix RTargetPrefix::FromString(const string &str, error_code *errorp) { return prefix; } - as4_t as; + as_t as; string asstr = str.substr(0, pos); stringToInteger(asstr, as); diff --git a/src/bgp/rtarget/rtarget_prefix.h b/src/bgp/rtarget/rtarget_prefix.h index 5f5111bbca9..04a74a353a9 100644 --- a/src/bgp/rtarget/rtarget_prefix.h +++ b/src/bgp/rtarget/rtarget_prefix.h @@ -19,7 +19,7 @@ class RTargetPrefix { RTargetPrefix(); explicit RTargetPrefix(const BgpProtoPrefix &prefix); - RTargetPrefix(as4_t as, RouteTarget rtarget) + RTargetPrefix(as_t as, RouteTarget rtarget) : as_(as), rtarget_(rtarget) { } @@ -37,7 +37,7 @@ class RTargetPrefix { std::string ToString() const; RouteTarget rtarget() const { return rtarget_; } - as4_t as() const { return as_; } + as_t as() const { return as_; } void BuildProtoPrefix(BgpProtoPrefix *prefix) const; int CompareTo(const RTargetPrefix &rhs) const; bool operator==(const RTargetPrefix &rhs) const { @@ -45,7 +45,7 @@ class RTargetPrefix { } private: - as4_t as_; + as_t as_; RouteTarget rtarget_; }; diff --git a/src/bgp/security_group/security_group.cc b/src/bgp/security_group/security_group.cc index 0ff1dcc389b..d88672a4b1b 100644 --- a/src/bgp/security_group/security_group.cc +++ b/src/bgp/security_group/security_group.cc @@ -2,6 +2,7 @@ * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved. */ +#include "bgp/extended-community/types.h" #include "bgp/security_group/security_group.h" #include @@ -12,9 +13,9 @@ using std::copy; using std::string; -SecurityGroup::SecurityGroup(as_t asn, uint32_t sgid) { - data_[0] = 0x80; - data_[1] = 0x04; +SecurityGroup::SecurityGroup(as2_t asn, uint32_t sgid) { + data_[0] = BgpExtendedCommunityType::Experimental; + data_[1] = BgpExtendedCommunityExperimentalSubType::SgId; put_value(&data_[2], 2, asn); put_value(&data_[4], 4, sgid); } @@ -23,16 +24,18 @@ SecurityGroup::SecurityGroup(const bytes_type &data) { copy(data.begin(), data.end(), data_.begin()); } -as_t SecurityGroup::as_number() const { - if (data_[0] == 0x80 && data_[1] == 0x04) { - as_t as_number = get_value(&data_[2], 2); +as2_t SecurityGroup::as_number() const { + if (data_[0] == BgpExtendedCommunityType::Experimental && + data_[1] == BgpExtendedCommunityExperimentalSubType::SgId) { + as2_t as_number = get_value(&data_[2], 2); return as_number; } return 0; } uint32_t SecurityGroup::security_group_id() const { - if (data_[0] == 0x80 && data_[1] == 0x04) { + if (data_[0] == BgpExtendedCommunityType::Experimental && + data_[1] == BgpExtendedCommunityExperimentalSubType::SgId) { uint32_t num = get_value(&data_[4], 4); return num; } @@ -50,3 +53,44 @@ string SecurityGroup::ToString() { as_number(), security_group_id()); return string(temp); } + +SecurityGroup4ByteAs::SecurityGroup4ByteAs(as_t asn, uint32_t sgid) { + data_[0] = BgpExtendedCommunityType::Experimental4ByteAs; + data_[1] = BgpExtendedCommunityExperimentalSubType::SgId; + put_value(&data_[2], 4, asn); + put_value(&data_[4], 2, sgid); +} + +SecurityGroup4ByteAs::SecurityGroup4ByteAs(const bytes_type &data) { + copy(data.begin(), data.end(), data_.begin()); +} + +as_t SecurityGroup4ByteAs::as_number() const { + if (data_[0] == BgpExtendedCommunityType::Experimental4ByteAs && + data_[1] == BgpExtendedCommunityExperimentalSubType::SgId) { + as_t as_number = get_value(&data_[2], 4); + return as_number; + } + return 0; +} + +uint32_t SecurityGroup4ByteAs::security_group_id() const { + if (data_[0] == BgpExtendedCommunityType::Experimental4ByteAs && + data_[1] == BgpExtendedCommunityExperimentalSubType::SgId) { + uint32_t num = get_value(&data_[6], 2); + return num; + } + return 0; +} + +bool SecurityGroup4ByteAs::IsGlobal() const { + uint32_t sgid = security_group_id(); + return (sgid >= kMinGlobalId && sgid <= kMaxGlobalId); +} + +string SecurityGroup4ByteAs::ToString() { + char temp[50]; + snprintf(temp, sizeof(temp), "secgroup:%u:%u", + as_number(), security_group_id()); + return string(temp); +} diff --git a/src/bgp/security_group/security_group.h b/src/bgp/security_group/security_group.h index 998907156d3..9a0b87534e8 100644 --- a/src/bgp/security_group/security_group.h +++ b/src/bgp/security_group/security_group.h @@ -20,9 +20,36 @@ class SecurityGroup { static const uint32_t kMaxGlobalId = 7999999; typedef boost::array bytes_type; - SecurityGroup(as_t asn, uint32_t id); + SecurityGroup(as2_t asn, uint32_t id); explicit SecurityGroup(const bytes_type &data); + as2_t as_number() const; + uint32_t security_group_id() const; + bool IsGlobal() const; + + const bytes_type &GetExtCommunity() const { + return data_; + } + + const uint64_t GetExtCommunityValue() const { + return get_value(data_.begin(), 8); + } + std::string ToString(); + +private: + bytes_type data_; +}; + +class SecurityGroup4ByteAs { +public: + static const int kSize = 8; + static const uint32_t kMinGlobalId = 1; + static const uint32_t kMaxGlobalId = 7999999; + typedef boost::array bytes_type; + + SecurityGroup4ByteAs(as_t asn, uint32_t id); + explicit SecurityGroup4ByteAs(const bytes_type &data); + as_t as_number() const; uint32_t security_group_id() const; bool IsGlobal() const; diff --git a/src/bgp/test/bgp_attr_test.cc b/src/bgp/test/bgp_attr_test.cc index e5317f5c791..2a51af7fe4b 100644 --- a/src/bgp/test/bgp_attr_test.cc +++ b/src/bgp/test/bgp_attr_test.cc @@ -409,7 +409,7 @@ TEST_F(BgpAttrTest, AsPathAdd) { TEST_F(BgpAttrTest, AsPathAddList) { AsPathSpec path; - vector asn_list = list_of(1000)(2000); + vector asn_list = list_of(1000)(2000); // Add to an empty path. AsPathSpec *p2 = path.Add(asn_list); diff --git a/src/bgp/test/bgp_bgpaas_test.cc b/src/bgp/test/bgp_bgpaas_test.cc index da78cce46e6..05b8d657f62 100644 --- a/src/bgp/test/bgp_bgpaas_test.cc +++ b/src/bgp/test/bgp_bgpaas_test.cc @@ -280,9 +280,9 @@ class BGPaaSTest : public ::testing::TestWithParam{ if (nexthop_str != nexthop.to_string()) return false; if (!as_path.empty()) { - if (!path->GetAttr()->as_path()) + if (!path->GetAttr()->aspath_4byte()) return false; - if (as_path != path->GetAttr()->as_path()->path().ToString()) + if (as_path != path->GetAttr()->aspath_4byte()->path().ToString()) return false; } return true; @@ -337,9 +337,9 @@ class BGPaaSTest : public ::testing::TestWithParam{ if (nexthop_str != nexthop.to_string()) return false; if (!as_path.empty()) { - if (!path->GetAttr()->as_path()) + if (!path->GetAttr()->aspath_4byte()) return false; - if (as_path != path->GetAttr()->as_path()->path().ToString()) + if (as_path != path->GetAttr()->aspath_4byte()->path().ToString()) return false; } return true; diff --git a/src/bgp/test/bgp_evpn_aliasing_test.cc b/src/bgp/test/bgp_evpn_aliasing_test.cc index f5389c4c45e..be129f8ff2c 100644 --- a/src/bgp/test/bgp_evpn_aliasing_test.cc +++ b/src/bgp/test/bgp_evpn_aliasing_test.cc @@ -88,6 +88,7 @@ class PeerMock : public IPeer { } virtual void UpdateTotalPathCount(int count) { } virtual int GetTotalPathCount() const { return 0; } + virtual bool IsAs4Supported() const { return false; } virtual void UpdatePrimaryPathCount(int count, Address::Family family) const { } virtual int GetPrimaryPathCount() const { return 0; } diff --git a/src/bgp/test/bgp_evpn_manager_test.cc b/src/bgp/test/bgp_evpn_manager_test.cc index 1c13b2754c3..95c9a6783e1 100644 --- a/src/bgp/test/bgp_evpn_manager_test.cc +++ b/src/bgp/test/bgp_evpn_manager_test.cc @@ -121,6 +121,7 @@ class PeerMock : public IPeer { } virtual void UpdateTotalPathCount(int count) { } virtual int GetTotalPathCount() const { return 0; } + virtual bool IsAs4Supported() const { return false; } virtual void UpdatePrimaryPathCount(int count, Address::Family family) const { } virtual int GetPrimaryPathCount() const { return 0; } diff --git a/src/bgp/test/bgp_ip_test.cc b/src/bgp/test/bgp_ip_test.cc index 29f8c0090dd..7f968f8287f 100644 --- a/src/bgp/test/bgp_ip_test.cc +++ b/src/bgp/test/bgp_ip_test.cc @@ -52,6 +52,7 @@ class PeerMock : public IPeer { virtual const std::string GetStateName() const { return ""; } virtual void UpdateTotalPathCount(int count) const { } virtual int GetTotalPathCount() const { return 0; } + virtual bool IsAs4Supported() const { return false; } virtual void UpdatePrimaryPathCount(int count, Address::Family family) const { } virtual int GetPrimaryPathCount() const { return 0; } @@ -281,9 +282,10 @@ class BgpIpTest : public ::testing::Test { BgpAttrOrigin origin_spec(BgpAttrOrigin::IGP); attr_spec.push_back(&origin_spec); - AsPathSpec path_spec; - AsPathSpec::PathSegment *path_seg = new AsPathSpec::PathSegment; - path_seg->path_segment_type = AsPathSpec::PathSegment::AS_SEQUENCE; + AsPath4ByteSpec path_spec; + AsPath4ByteSpec::PathSegment *path_seg = + new AsPath4ByteSpec::PathSegment; + path_seg->path_segment_type = AsPath4ByteSpec::PathSegment::AS_SEQUENCE; path_seg->path_segment.push_back(64513); path_seg->path_segment.push_back(64514); path_seg->path_segment.push_back(64515); diff --git a/src/bgp/test/bgp_msg_builder_test.cc b/src/bgp/test/bgp_msg_builder_test.cc index af2f88ba412..422a7799329 100644 --- a/src/bgp/test/bgp_msg_builder_test.cc +++ b/src/bgp/test/bgp_msg_builder_test.cc @@ -84,9 +84,9 @@ TEST_F(BgpMsgBuilderTest, Build) { BgpAttrAggregator *agg = new BgpAttrAggregator(0xface, 0xcafebabe); attr.push_back(agg); - AsPathSpec *path_spec = new AsPathSpec; - AsPathSpec::PathSegment *ps = new AsPathSpec::PathSegment; - ps->path_segment_type = AsPathSpec::PathSegment::AS_SET; + AsPath4ByteSpec *path_spec = new AsPath4ByteSpec; + AsPath4ByteSpec::PathSegment *ps = new AsPath4ByteSpec::PathSegment; + ps->path_segment_type = AsPath4ByteSpec::PathSegment::AS_SET; ps->path_segment.push_back(20); ps->path_segment.push_back(21); ps->path_segment.push_back(22); @@ -125,7 +125,8 @@ TEST_F(BgpMsgBuilderTest, Build) { printf("\n"); const BgpProto::Update *result; - result = static_cast(BgpProto::Decode(data, length)); + result = static_cast( + BgpProto::Decode(data, length)); ASSERT_TRUE(result != NULL); EXPECT_EQ(attr.size(), result->path_attributes.size()); for (size_t i = 0; i < attr.size()-1; i++) { @@ -186,7 +187,7 @@ TEST_F(BgpMsgBuilderTest, Build) { delete lp; delete aa; delete agg; - delete path_spec; + //delete path_spec; delete community; delete ext_community; delete result; diff --git a/src/bgp/test/bgp_multicast_test.cc b/src/bgp/test/bgp_multicast_test.cc index 48a2df7c304..24aa7a62ec9 100644 --- a/src/bgp/test/bgp_multicast_test.cc +++ b/src/bgp/test/bgp_multicast_test.cc @@ -86,6 +86,7 @@ class XmppPeerMock : public IPeer { virtual bool SendUpdate(const uint8_t *msg, size_t msgsize) { return true; } virtual void UpdateTotalPathCount(int count) const { } virtual int GetTotalPathCount() const { return 0; } + virtual bool IsAs4Supported() const { return false; } virtual void UpdatePrimaryPathCount(int count, Address::Family family) const { } virtual int GetPrimaryPathCount() const { return 0; } diff --git a/src/bgp/test/bgp_mvpn_test.cc b/src/bgp/test/bgp_mvpn_test.cc index 2067135cb66..6401aaae183 100644 --- a/src/bgp/test/bgp_mvpn_test.cc +++ b/src/bgp/test/bgp_mvpn_test.cc @@ -124,6 +124,7 @@ class BgpPeerMock : public IPeer { virtual const std::string GetStateName() const { return "UNKNOWN"; } virtual void UpdateTotalPathCount(int count) const { } virtual int GetTotalPathCount() const { return 0; } + virtual bool IsAs4Supported() const { return false; } virtual void UpdatePrimaryPathCount(int count, Address::Family family) const { } virtual int GetPrimaryPathCount() const { return 0; } diff --git a/src/bgp/test/bgp_proto_test.cc b/src/bgp/test/bgp_proto_test.cc index 01037d11bde..4870d9199eb 100644 --- a/src/bgp/test/bgp_proto_test.cc +++ b/src/bgp/test/bgp_proto_test.cc @@ -20,7 +20,7 @@ class BgpProtoTest : public testing::Test { int subcode, std::string type, int offset, int err_size) { ParseErrorContext ec; const BgpProto::BgpMessage *result = - BgpProto::Decode(&data[0], size, &ec); + BgpProto::Decode(&data[0], size, &ec, false); EXPECT_TRUE(result == NULL); EXPECT_EQ(error, ec.error_code); @@ -58,7 +58,7 @@ class BgpProtoTest : public testing::Test { new_data[pos] = rand(); } - BgpProto::BgpMessage *msg = BgpProto::Decode(new_data, data_size); + BgpProto::BgpMessage *msg = BgpProto::Decode(new_data, data_size, NULL, false); if (msg) delete msg; } @@ -573,7 +573,7 @@ TEST_F(BgpProtoTest, Update) { BgpMessageTest::GenerateUpdateMessage(&update, BgpAf::IPv4, BgpAf::Unicast); uint8_t data[256]; - int res = BgpProto::Encode(&update, data, 256); + int res = BgpProto::Encode(&update, data, 256, NULL, false); EXPECT_NE(-1, res); if (detail::debug_) { for (int i = 0; i < res; i++) { @@ -583,7 +583,7 @@ TEST_F(BgpProtoTest, Update) { } const BgpProto::Update *result; - result = static_cast(BgpProto::Decode(data, res)); + result = static_cast(BgpProto::Decode(data, res, NULL, false)); EXPECT_TRUE(result != NULL); if (result) { EXPECT_EQ(0, result->CompareTo(update)); @@ -596,7 +596,7 @@ TEST_F(BgpProtoTest, L3VPNUpdate) { BgpMessageTest::GenerateUpdateMessage(&update, BgpAf::IPv4, BgpAf::Vpn); uint8_t data[256]; - int res = BgpProto::Encode(&update, data, 256); + int res = BgpProto::Encode(&update, data, 256, NULL, false); EXPECT_NE(-1, res); if (detail::debug_) { for (int i = 0; i < res; i++) { @@ -606,7 +606,7 @@ TEST_F(BgpProtoTest, L3VPNUpdate) { } const BgpProto::Update *result; - result = static_cast(BgpProto::Decode(data, res)); + result = static_cast(BgpProto::Decode(data, res, NULL, false)); EXPECT_TRUE(result != NULL); if (result) { EXPECT_EQ(0, result->CompareTo(update)); @@ -633,7 +633,7 @@ TEST_F(BgpProtoTest, 32PlusExtCommunities) { ext_community->communities.push_back(value + i); } - int res = BgpProto::Encode(&update, data, BgpProto::kMaxMessageSize); + int res = BgpProto::Encode(&update, data, BgpProto::kMaxMessageSize, NULL, false); EXPECT_NE(-1, res); if (detail::debug_) { for (int i = 0; i < res; i++) { @@ -643,7 +643,7 @@ TEST_F(BgpProtoTest, 32PlusExtCommunities) { } const BgpProto::Update *result; - result = static_cast(BgpProto::Decode(data, res)); + result = static_cast(BgpProto::Decode(data, res, NULL, false)); EXPECT_TRUE(result != NULL); if (result) { EXPECT_EQ(0, result->CompareTo(update)); @@ -665,7 +665,7 @@ TEST_F(BgpProtoTest, EvpnUpdate) { BgpMessageTest::GenerateUpdateMessage(&update, BgpAf::L2Vpn, BgpAf::EVpn); uint8_t data[256]; - int res = BgpProto::Encode(&update, data, 256); + int res = BgpProto::Encode(&update, data, 256, NULL, false); EXPECT_NE(-1, res); if (detail::debug_) { for (int i = 0; i < res; i++) { @@ -675,7 +675,7 @@ TEST_F(BgpProtoTest, EvpnUpdate) { } const BgpProto::Update *result; - result = static_cast(BgpProto::Decode(data, res)); + result = static_cast(BgpProto::Decode(data, res, NULL, false)); EXPECT_TRUE(result != NULL); if (result) { EXPECT_EQ(0, result->CompareTo(update)); @@ -703,7 +703,7 @@ TEST_F(BgpProtoTest, ClusterList) { ParseErrorContext context; boost::scoped_ptr update( static_cast( - BgpProto::Decode(data, sizeof(data), &context))); + BgpProto::Decode(data, sizeof(data), &context, false))); ASSERT_TRUE(update.get() != NULL); const ClusterListSpec *clist_spec = static_cast( @@ -713,7 +713,7 @@ TEST_F(BgpProtoTest, ClusterList) { EXPECT_EQ(0xcafed0d0ul, clist_spec->cluster_list[1]); uint8_t buffer[4096]; - int res = BgpProto::Encode(update.get(), buffer, sizeof(buffer)); + int res = BgpProto::Encode(update.get(), buffer, sizeof(buffer), NULL, false); EXPECT_EQ(sizeof(data), res); EXPECT_EQ(0, memcmp(buffer, data, sizeof(data))); } @@ -784,7 +784,7 @@ TEST_F(BgpProtoTest, UpdateError) { 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x04, 0x01, 0x0a, 0x01, 0x02 }; const BgpProto::Update *result = static_cast( - BgpProto::Decode(&data[0], sizeof(data))); + BgpProto::Decode(&data[0], sizeof(data), NULL, false)); EXPECT_TRUE(result != NULL); delete result; @@ -825,7 +825,7 @@ TEST_F(BgpProtoTest, UpdateError) { // Unknown optional attribute. data[30] |= BgpAttribute::Optional; result = static_cast( - BgpProto::Decode(&data[0], sizeof(data))); + BgpProto::Decode(&data[0], sizeof(data), NULL, false)); EXPECT_TRUE(result != NULL); BgpAttrUnknown *attr = static_cast(result->path_attributes[0]); EXPECT_EQ(20, attr->code); @@ -949,14 +949,22 @@ TEST_F(BgpProtoTest, UpdateScale) { BgpAttrAggregator *agg = new BgpAttrAggregator(0xface, 0xcafebabe); update.path_attributes.push_back(agg); - AsPathSpec *path_spec = new AsPathSpec; - AsPathSpec::PathSegment *ps = new AsPathSpec::PathSegment; - ps->path_segment_type = AsPathSpec::PathSegment::AS_SET; - ps->path_segment.push_back(20); - ps->path_segment.push_back(21); - ps->path_segment.push_back(22); - path_spec->path_segments.push_back(ps); - update.path_attributes.push_back(path_spec); + AsPath4ByteSpec *path4_spec = new AsPath4ByteSpec; + AsPath4ByteSpec::PathSegment *ps3 = new AsPath4ByteSpec::PathSegment; + ps3->path_segment_type = AsPath4ByteSpec::PathSegment::AS_SET; + ps3->path_segment.push_back(20); + ps3->path_segment.push_back(21); + path4_spec->path_segments.push_back(ps3); + update.path_attributes.push_back(path4_spec); + + As4PathSpec *path_spec4 = new As4PathSpec; + As4PathSpec::PathSegment *ps4 = new As4PathSpec::PathSegment; + ps4->path_segment_type = As4PathSpec::PathSegment::AS_SET; + ps4->path_segment.push_back(20); + ps4->path_segment.push_back(21); + ps4->path_segment.push_back(22); + path_spec4->path_segments.push_back(ps4); + update.path_attributes.push_back(path_spec4); CommunitySpec *community = new CommunitySpec; community->communities.push_back(0x87654321); @@ -985,7 +993,7 @@ TEST_F(BgpProtoTest, UpdateScale) { uint8_t data[4096]; - int res = BgpProto::Encode(&update, data, 4096); + int res = BgpProto::Encode(&update, data, 4096, NULL, true); EXPECT_NE(-1, res); if (detail::debug_) { cout << res << " Bytes encoded" << endl; @@ -996,7 +1004,7 @@ TEST_F(BgpProtoTest, UpdateScale) { } const BgpProto::Update *result; - result = static_cast(BgpProto::Decode(data, res)); + result = static_cast(BgpProto::Decode(data, res, NULL, true)); EXPECT_TRUE(result != NULL); if (result) { EXPECT_EQ(0, result->CompareTo(update)); @@ -1033,7 +1041,7 @@ TEST_F(BgpProtoTest, RandomUpdate) { for (int i = 0; i < count; i++) { BgpProto::Update update; BuildUpdateMessage::Generate(&update); - int msglen = BgpProto::Encode(&update, data, sizeof(data)); + int msglen = BgpProto::Encode(&update, data, sizeof(data), NULL, false); /* * Some message combinations will generate an update that is too * big. Ignore this for now since the test generates useful @@ -1046,7 +1054,7 @@ TEST_F(BgpProtoTest, RandomUpdate) { ParseErrorContext err; std::auto_ptr result( static_cast( - BgpProto::Decode(data, msglen, &err))); + BgpProto::Decode(data, msglen, &err, false))); EXPECT_TRUE(result.get() != NULL); if (result.get() != NULL) { EXPECT_EQ(0, result->CompareTo(update)); @@ -1087,7 +1095,7 @@ TEST_F(BgpProtoTest, RandomError) { for (int i = 0; i < count; i++) { BgpProto::Update update; BuildUpdateMessage::Generate(&update); - int msglen = BgpProto::Encode(&update, data, sizeof(data)); + int msglen = BgpProto::Encode(&update, data, sizeof(data), NULL, false); if (msglen == -1) { continue; } @@ -1109,7 +1117,7 @@ class EncodeLengthTest : public testing::Test { BgpProto::Update update; EncodeOffsets offsets; update.path_attributes.push_back(spec); - int msglen = BgpProto::Encode(&update, data_, sizeof(data_), &offsets); + int msglen = BgpProto::Encode(&update, data_, sizeof(data_), &offsets, false); EXPECT_LT(0, msglen); int offset = offsets.FindOffset("BgpPathAttribute"); diff --git a/src/bgp/test/bgp_route_test.cc b/src/bgp/test/bgp_route_test.cc index b4e42b6b369..8b51127d563 100644 --- a/src/bgp/test/bgp_route_test.cc +++ b/src/bgp/test/bgp_route_test.cc @@ -53,6 +53,7 @@ class PeerMock : public IPeer { virtual uint32_t bgp_identifier() const { return address_.to_ulong(); } virtual void UpdateTotalPathCount(int count) const { } virtual int GetTotalPathCount() const { return 0; } + virtual bool IsAs4Supported() const { return false; } virtual void UpdatePrimaryPathCount(int count, Address::Family family) const { } virtual int GetPrimaryPathCount() const { return 0; } diff --git a/src/bgp/test/bgp_server_test.cc b/src/bgp/test/bgp_server_test.cc index d8a6d7178b2..2a9d8c2d644 100644 --- a/src/bgp/test/bgp_server_test.cc +++ b/src/bgp/test/bgp_server_test.cc @@ -181,12 +181,12 @@ class BgpServerUnitTest : public ::testing::Test, bool admin_down1, bool admin_down2, bool nbr_admin_down1, bool nbr_admin_down2, bool nbr_passive1, bool nbr_passive2, - uint16_t as_num1, uint16_t as_num2, - uint16_t local_as_num1, uint16_t local_as_num2); + uint32_t as_num1, uint32_t as_num2, + uint32_t local_as_num1, uint32_t local_as_num2); void SetupPeers(int peer_count, unsigned short port_a, unsigned short port_b, bool verify_keepalives, - uint16_t as_num1 = BgpConfigManager::kDefaultAutonomousSystem, - uint16_t as_num2 = BgpConfigManager::kDefaultAutonomousSystem, + uint32_t as_num1 = BgpConfigManager::kDefaultAutonomousSystem, + uint32_t as_num2 = BgpConfigManager::kDefaultAutonomousSystem, string peer_address1 = "127.0.0.1", string peer_address2 = "127.0.0.1", string bgp_identifier1 = "192.168.0.10", @@ -199,13 +199,13 @@ class BgpServerUnitTest : public ::testing::Test, uint16_t nbr_hold_time2 = 0, uint32_t cluster_id = 0); void SetupPeers(int peer_count, unsigned short port_a, unsigned short port_b, bool verify_keepalives, - uint16_t as_num1, uint16_t as_num2, - uint16_t local_as_num1, uint16_t local_as_num2); + uint32_t as_num1, uint32_t as_num2, + uint32_t local_as_num1, uint32_t local_as_num2); void SetupPeers(BgpServerTest *server, int peer_count, unsigned short port_a, unsigned short port_b, bool verify_keepalives, - uint16_t as_num1 = BgpConfigManager::kDefaultAutonomousSystem, - uint16_t as_num2 = BgpConfigManager::kDefaultAutonomousSystem, + uint32_t as_num1 = BgpConfigManager::kDefaultAutonomousSystem, + uint32_t as_num2 = BgpConfigManager::kDefaultAutonomousSystem, string peer_address1 = "127.0.0.1", string peer_address2 = "127.0.0.1", string bgp_identifier1 = "192.168.0.10", @@ -217,8 +217,8 @@ class BgpServerUnitTest : public ::testing::Test, void SetupPeers(int peer_count, unsigned short port_a, unsigned short port_b, bool verify_keepalives, vector auth_keys, - uint16_t as_num1 = BgpConfigManager::kDefaultAutonomousSystem, - uint16_t as_num2 = BgpConfigManager::kDefaultAutonomousSystem, + uint32_t as_num1 = BgpConfigManager::kDefaultAutonomousSystem, + uint32_t as_num2 = BgpConfigManager::kDefaultAutonomousSystem, string peer_address1 = "127.0.0.1", string peer_address2 = "127.0.0.1", string bgp_identifier1 = "192.168.0.10", @@ -232,8 +232,8 @@ class BgpServerUnitTest : public ::testing::Test, unsigned short port_a, unsigned short port_b, bool verify_keepalives, vector auth_keys, - uint16_t as_num1 = BgpConfigManager::kDefaultAutonomousSystem, - uint16_t as_num2 = BgpConfigManager::kDefaultAutonomousSystem, + uint32_t as_num1 = BgpConfigManager::kDefaultAutonomousSystem, + uint32_t as_num2 = BgpConfigManager::kDefaultAutonomousSystem, string peer_address1 = "127.0.0.1", string peer_address2 = "127.0.0.1", string bgp_identifier1 = "192.168.0.10", @@ -242,15 +242,15 @@ class BgpServerUnitTest : public ::testing::Test, vector families2 = vector(), bool delete_config = false); void VerifyPeers(int peer_count, size_t verify_keepalives_count = 0, - uint16_t local_as_num1 = BgpConfigManager::kDefaultAutonomousSystem, - uint16_t local_as_num2 = BgpConfigManager::kDefaultAutonomousSystem); + uint32_t local_as_num1 = BgpConfigManager::kDefaultAutonomousSystem, + uint32_t local_as_num2 = BgpConfigManager::kDefaultAutonomousSystem); string GetConfigStr(int peer_count, unsigned short port_a, unsigned short port_b, bool admin_down1, bool admin_down2, bool nbr_admin_down1, bool nbr_admin_down2, bool nbr_passive1, bool nbr_passive2, - uint16_t as_num1, uint16_t as_num2, - uint16_t local_as_num1, uint16_t local_as_num2, + uint32_t as_num1, uint32_t as_num2, + uint32_t local_as_num1, uint32_t local_as_num2, string peer_address1, string peer_address2, string bgp_identifier1, string bgp_identifier2, vector families1, vector families2, @@ -2754,9 +2754,9 @@ void BgpServerUnitTest::GRTestCommon(bool hard_reset, BgpAttrOrigin origin(BgpAttrOrigin::IGP); attr_spec.push_back(&origin); - AsPathSpec path_spec; - AsPathSpec::PathSegment *path_seg = new AsPathSpec::PathSegment; - path_seg->path_segment_type = AsPathSpec::PathSegment::AS_SEQUENCE; + AsPath4ByteSpec path_spec; + AsPath4ByteSpec::PathSegment *path_seg = new AsPath4ByteSpec::PathSegment; + path_seg->path_segment_type = AsPath4ByteSpec::PathSegment::AS_SEQUENCE; path_seg->path_segment.push_back(65534); path_spec.path_segments.push_back(path_seg); attr_spec.push_back(&path_spec); @@ -3544,9 +3544,9 @@ TEST_P(BgpServerUnitTest, BasicAdvertiseWithdraw) { BgpAttrOrigin origin(BgpAttrOrigin::IGP); attr_spec.push_back(&origin); - AsPathSpec path_spec; - AsPathSpec::PathSegment *path_seg = new AsPathSpec::PathSegment; - path_seg->path_segment_type = AsPathSpec::PathSegment::AS_SEQUENCE; + AsPath4ByteSpec path_spec; + AsPath4ByteSpec::PathSegment *path_seg = new AsPath4ByteSpec::PathSegment; + path_seg->path_segment_type = AsPath4ByteSpec::PathSegment::AS_SEQUENCE; path_seg->path_segment.push_back(65534); path_spec.path_segments.push_back(path_seg); attr_spec.push_back(&path_spec); diff --git a/src/bgp/test/bgp_table_export_test.cc b/src/bgp/test/bgp_table_export_test.cc index f68be098f6a..03516832693 100644 --- a/src/bgp/test/bgp_table_export_test.cc +++ b/src/bgp/test/bgp_table_export_test.cc @@ -59,6 +59,7 @@ class BgpTestPeer : public IPeer { explicit BgpTestPeer(int index, bool internal) : index_(index), internal_(internal), + as4_supported_(false), cluster_id_(100), to_str_("Peer " + integerToString(index_)) { } @@ -86,6 +87,8 @@ class BgpTestPeer : public IPeer { virtual const string GetStateName() const { return ""; } virtual void UpdateTotalPathCount(int count) const { } virtual int GetTotalPathCount() const { return 0; } + virtual bool IsAs4Supported() const { return as4_supported_; } + void SetAs4Supported() { as4_supported_ = true; } virtual void UpdatePrimaryPathCount(int count, Address::Family family) const { } virtual int GetPrimaryPathCount() const { return 0; } @@ -122,6 +125,7 @@ class BgpTestPeer : public IPeer { private: int index_; bool internal_; + bool as4_supported_; uint32_t cluster_id_; std::string to_str_; }; @@ -223,11 +227,15 @@ class BgpTableExportTest : public ::testing::Test { attr_spec.push_back(&nexthop); AsPathSpec path_spec; + AsPath4ByteSpec path_spec4; + As4PathSpec path4_spec; BgpAttrLocalPref local_pref(100); BgpAttrMultiExitDisc med(100); if (internal_) { attr_spec.push_back(&path_spec); + attr_spec.push_back(&path_spec4); + attr_spec.push_back(&path4_spec); attr_spec.push_back(&local_pref); attr_spec.push_back(&med); } else { @@ -236,6 +244,17 @@ class BgpTableExportTest : public ::testing::Test { path_seg->path_segment.push_back(100); path_spec.path_segments.push_back(path_seg); attr_spec.push_back(&path_spec); + AsPath4ByteSpec::PathSegment *ps4 = + new AsPath4ByteSpec::PathSegment; + ps4->path_segment_type = AsPath4ByteSpec::PathSegment::AS_SEQUENCE; + ps4->path_segment.push_back(100); + path_spec4.path_segments.push_back(ps4); + attr_spec.push_back(&path_spec4); + As4PathSpec::PathSegment *path4_seg = new As4PathSpec::PathSegment; + path4_seg->path_segment_type = As4PathSpec::PathSegment::AS_SEQUENCE; + path4_seg->path_segment.push_back(100); + path4_spec.path_segments.push_back(path4_seg); + attr_spec.push_back(&path4_spec); attr_spec.push_back(&med); } @@ -256,20 +275,22 @@ class BgpTableExportTest : public ::testing::Test { void CreateRibOut(BgpProto::BgpPeerType type, RibExportPolicy::Encoding encoding, as_t as_number = 0, - as_t local_as = 0, uint32_t cluster_id = 0) { - RibExportPolicy policy(type, encoding, as_number, false, false, -1, - cluster_id, local_as); + as_t local_as = 0, uint32_t cluster_id = 0, + bool as4_supported = false) { + RibExportPolicy policy(type, encoding, as_number, false, false, + as4_supported, -1, cluster_id, local_as); ribout_ = table_->RibOutLocate(sender_, policy); RegisterRibOutPeers(); } void CreateRibOut(BgpProto::BgpPeerType type, RibExportPolicy::Encoding encoding, as_t as_number, - bool as_override, IpAddress nexthop, uint32_t cluster_id = 0) { + bool as_override, IpAddress nexthop, uint32_t cluster_id = 0, + bool as4_supported = false) { vector default_tunnel_encap_list; RibExportPolicy policy( - type, encoding, as_number, as_override, false, nexthop, -1, - cluster_id, default_tunnel_encap_list); + type, encoding, as_number, as_override, false, as4_supported, + nexthop, -1, cluster_id, default_tunnel_encap_list); ribout_ = table_->RibOutLocate(sender_, policy); RegisterRibOutPeers(); } @@ -278,7 +299,7 @@ class BgpTableExportTest : public ::testing::Test { RibExportPolicy::Encoding encoding, as_t as_number, as_t local_as, bool llgr) { RibExportPolicy policy( - type, encoding, as_number, false, llgr, -1, local_as); + type, encoding, as_number, false, llgr, false, -1, local_as); ribout_ = table_->RibOutLocate(sender_, policy); RegisterRibOutPeers(); } @@ -319,12 +340,36 @@ class BgpTableExportTest : public ::testing::Test { attr_ptr_ = server_.attr_db()->Locate(attr); } + void SetAttrAsPath4(as_t as_number) { + BgpAttr *attr = new BgpAttr(*attr_ptr_); + const AsPath4ByteSpec &path_spec = attr_ptr_->aspath_4byte()->path(); + AsPath4ByteSpec *path_spec_ptr = path_spec.Add(as_number); + attr->set_aspath_4byte(path_spec_ptr); + delete path_spec_ptr; + attr_ptr_ = server_.attr_db()->Locate(attr); + } + + void SetAttrAs4Path(as_t as_number) { + BgpAttr *attr = new BgpAttr(*attr_ptr_); + const As4PathSpec &path_spec = attr_ptr_->as4_path()->path(); + As4PathSpec *path_spec_ptr = path_spec.Add(as_number); + attr->set_as4_path(path_spec_ptr); + delete path_spec_ptr; + attr_ptr_ = server_.attr_db()->Locate(attr); + } + void ResetAttrAsPath() { BgpAttr *attr = new BgpAttr(*attr_ptr_); attr->set_as_path(NULL); attr_ptr_ = server_.attr_db()->Locate(attr); } + void ResetAttrAsPath4() { + BgpAttr *attr = new BgpAttr(*attr_ptr_); + attr->set_aspath_4byte(NULL); + attr_ptr_ = server_.attr_db()->Locate(attr); + } + void SetAttrClusterList(const vector cluster_list) { BgpAttr *attr = new BgpAttr(*attr_ptr_); ClusterListSpec clist_spec; @@ -372,7 +417,9 @@ class BgpTableExportTest : public ::testing::Test { attr_ptr_ = server_.attr_db()->Locate(attr); } - BgpPath *AddPath() { + BgpPath *AddPath(bool as4_supported = false) { + if (as4_supported) + peer_->SetAs4Supported(); BgpPath *path = new BgpPath(peer_.get(), BgpPath::BGP_XMPP, attr_ptr_, 0, 0); rt_.InsertPath(path); @@ -431,6 +478,18 @@ class BgpTableExportTest : public ::testing::Test { EXPECT_EQ(count, attr->as_path_count()); } + void VerifyAttrAs4PathCount(uint32_t count) { + const UpdateInfo &uinfo = uinfo_slist_->front(); + const BgpAttr *attr = uinfo.roattr.attr(); + EXPECT_EQ(count, attr->as4_path_count()); + } + + void VerifyAttrAs4BytePathCount(uint32_t count) { + const UpdateInfo &uinfo = uinfo_slist_->front(); + const BgpAttr *attr = uinfo.roattr.attr(); + EXPECT_EQ(count, attr->aspath_4byte_count()); + } + void VerifyAttrAsPrepend(as_t local_as = 0) { const UpdateInfo &uinfo = uinfo_slist_->front(); const BgpAttr *attr = uinfo.roattr.attr(); @@ -442,6 +501,38 @@ class BgpTableExportTest : public ::testing::Test { EXPECT_FALSE(as_path->path().AsLeftMostMatch(my_as)); } + void VerifyAttrAs4Prepend(as_t local_as = 0) { + const UpdateInfo &uinfo = uinfo_slist_->front(); + const BgpAttr *attr = uinfo.roattr.attr(); + const AsPath4Byte *as_path = attr->aspath_4byte(); + as_t my_as = server_.autonomous_system(); + as_t my_local_as = local_as ?: server_.local_autonomous_system(); + EXPECT_TRUE(as_path->path().AsLeftMostMatch(my_local_as)); + if (my_as != my_local_as) + EXPECT_FALSE(as_path->path().AsLeftMostMatch(my_as)); + } + + void VerifyAttrAs4BytePrepend(as_t local_as = 0) { + const UpdateInfo &uinfo = uinfo_slist_->front(); + const BgpAttr *attr = uinfo.roattr.attr(); + const AsPath4Byte *as_path = attr->aspath_4byte(); + as_t my_as = server_.autonomous_system(); + as_t my_local_as = local_as ?: server_.local_autonomous_system(); + EXPECT_TRUE(as_path->path().AsLeftMostMatch(my_local_as)); + if (my_as != my_local_as) + EXPECT_FALSE(as_path->path().AsLeftMostMatch(my_as)); + } + + void VerifyAttrNoAs4Prepend() { + const UpdateInfo &uinfo = uinfo_slist_->front(); + const BgpAttr *attr = uinfo.roattr.attr(); + const As4Path *as_path = attr->as4_path(); + as_t my_as = server_.autonomous_system(); + as_t my_local_as = server_.local_autonomous_system(); + EXPECT_FALSE(as_path->path().AsLeftMostMatch(my_as)); + EXPECT_FALSE(as_path->path().AsLeftMostMatch(my_local_as)); + } + void VerifyAttrNoAsPrepend() { const UpdateInfo &uinfo = uinfo_slist_->front(); const BgpAttr *attr = uinfo.roattr.attr(); @@ -459,6 +550,13 @@ class BgpTableExportTest : public ::testing::Test { EXPECT_FALSE(as_path->path().AsPathLoop(as_number, 0)); } + void VerifyAttrNoAs4PathLoop(as_t as_number) { + const UpdateInfo &uinfo = uinfo_slist_->front(); + const BgpAttr *attr = uinfo.roattr.attr(); + const AsPath4Byte *as_path = attr->aspath_4byte(); + EXPECT_FALSE(as_path->path().AsPathLoop(as_number, 0)); + } + void VerifyAttrAsPathAsCount(as_t as_number, uint8_t count) { const UpdateInfo &uinfo = uinfo_slist_->front(); const BgpAttr *attr = uinfo.roattr.attr(); @@ -468,6 +566,24 @@ class BgpTableExportTest : public ::testing::Test { EXPECT_TRUE(as_path->path().AsPathLoop(as_number, count - 1)); } + void VerifyAttrAs4BytePathAsCount(as_t as_number, uint8_t count) { + const UpdateInfo &uinfo = uinfo_slist_->front(); + const BgpAttr *attr = uinfo.roattr.attr(); + const AsPath4Byte *as_path = attr->aspath_4byte(); + EXPECT_FALSE(as_path->path().AsPathLoop(as_number, count)); + if (count) + EXPECT_TRUE(as_path->path().AsPathLoop(as_number, count - 1)); + } + + void VerifyAttrAs4PathAsCount(as_t as_number, uint8_t count) { + const UpdateInfo &uinfo = uinfo_slist_->front(); + const BgpAttr *attr = uinfo.roattr.attr(); + const As4Path *as_path = attr->as4_path(); + EXPECT_FALSE(as_path->path().AsPathLoop(as_number, count)); + if (count) + EXPECT_TRUE(as_path->path().AsPathLoop(as_number, count - 1)); + } + void VerifyAttrNoClusterList() { const UpdateInfo &uinfo = uinfo_slist_->front(); const BgpAttr *attr = uinfo.roattr.attr(); @@ -731,7 +847,7 @@ TEST_P(BgpTableExportParamTest1, AsOverride) { // TEST_P(BgpTableExportParamTest1, RemovePrivateAll) { RibExportPolicy policy( - BgpProto::EBGP, RibExportPolicy::BGP, 300, false, false, -1, 0); + BgpProto::EBGP, RibExportPolicy::BGP, 300, false, false, false, -1, 0); bool all = true; bool replace = false; bool peer_loop_check = true; policy.SetRemovePrivatePolicy(all, replace, peer_loop_check); CreateRibOut(policy); @@ -748,6 +864,25 @@ TEST_P(BgpTableExportParamTest1, RemovePrivateAll) { VerifyAttrAsPathAsCount(PeerAsNumber(), 1); } +TEST_P(BgpTableExportParamTest1, RemovePrivateAllAs4) { + RibExportPolicy policy( + BgpProto::EBGP, RibExportPolicy::BGP, 300, false, false, true, -1, 0); + bool all = true; bool replace = false; bool peer_loop_check = true; + policy.SetRemovePrivatePolicy(all, replace, peer_loop_check); + CreateRibOut(policy); + + SetAttrAsPath4(4294967294); + SetAttrAsPath4(65535); + AddPath(); + RunExport(); + VerifyExportAccept(); + VerifyAttrAs4BytePrepend(); + VerifyAttrAs4BytePathCount(PeerIsInternal() ? 1 : 2); + VerifyAttrAs4BytePathAsCount(LocalAsNumber(), 1); + if (!PeerIsInternal()) + VerifyAttrAs4BytePathAsCount(PeerAsNumber(), 1); +} + // // Table : inet.0, bgp.l3vpn.0 // Source: eBGP, iBGP @@ -757,7 +892,7 @@ TEST_P(BgpTableExportParamTest1, RemovePrivateAll) { // TEST_P(BgpTableExportParamTest1, RemovePrivateAllReplace1) { RibExportPolicy policy( - BgpProto::EBGP, RibExportPolicy::BGP, 300, false, false, -1, 0); + BgpProto::EBGP, RibExportPolicy::BGP, 300, false, false, false, -1, 0); bool all = true; bool replace = true; bool peer_loop_check = true; policy.SetRemovePrivatePolicy(all, replace, peer_loop_check); CreateRibOut(policy); @@ -774,6 +909,26 @@ TEST_P(BgpTableExportParamTest1, RemovePrivateAllReplace1) { VerifyAttrAsPathAsCount(PeerAsNumber(), 1); } +TEST_P(BgpTableExportParamTest1, RemovePrivateAllAs4Replace1) { + bool as4_supported = true; + RibExportPolicy policy( + BgpProto::EBGP, RibExportPolicy::BGP, 300, false, false, true, -1, 0); + bool all = true; bool replace = true; bool peer_loop_check = true; + policy.SetRemovePrivatePolicy(all, replace, peer_loop_check); + CreateRibOut(policy); + + SetAttrAsPath4(4294967294); + SetAttrAsPath4(4200000000); + AddPath(as4_supported); + RunExport(); + VerifyExportAccept(); + VerifyAttrAs4BytePrepend(); + VerifyAttrAs4BytePathCount(PeerIsInternal() ? 3 : 4); + VerifyAttrAs4BytePathAsCount(LocalAsNumber(), 3); + if (!PeerIsInternal()) + VerifyAttrAs4BytePathAsCount(PeerAsNumber(), 1); +} + // // Table : inet.0, bgp.l3vpn.0 // Source: eBGP, iBGP @@ -784,7 +939,7 @@ TEST_P(BgpTableExportParamTest1, RemovePrivateAllReplace1) { // TEST_P(BgpTableExportParamTest1, RemovePrivateAllReplace2) { RibExportPolicy policy( - BgpProto::EBGP, RibExportPolicy::BGP, 300, false, false, -1, 0); + BgpProto::EBGP, RibExportPolicy::BGP, 300, false, false, false, -1, 0); bool all = true; bool replace = true; bool peer_loop_check = true; policy.SetRemovePrivatePolicy(all, replace, peer_loop_check); CreateRibOut(policy); @@ -804,6 +959,29 @@ TEST_P(BgpTableExportParamTest1, RemovePrivateAllReplace2) { VerifyAttrAsPathAsCount(PeerAsNumber(), 1); } +TEST_P(BgpTableExportParamTest1, RemovePrivateAllAs4Replace2) { + bool as4_supported = true; + RibExportPolicy policy( + BgpProto::EBGP, RibExportPolicy::BGP, 300, false, false, true, -1, 0); + bool all = true; bool replace = true; bool peer_loop_check = true; + policy.SetRemovePrivatePolicy(all, replace, peer_loop_check); + CreateRibOut(policy); + + SetAttrAsPath4(4294967294); // replaced by nearest public as (500) + SetAttrAsPath4(500); + SetAttrAsPath4(4200000000); // replaced by local as + SetAttrAsPath4(4225000000); // replaced by local as + AddPath(as4_supported); + RunExport(); + VerifyExportAccept(); + VerifyAttrAs4BytePrepend(); + VerifyAttrAs4BytePathCount(PeerIsInternal() ? 5 : 6); + VerifyAttrAs4BytePathAsCount(LocalAsNumber(), 3); + VerifyAttrAs4BytePathAsCount(500, 2); + if (!PeerIsInternal()) + VerifyAttrAs4BytePathAsCount(PeerAsNumber(), 1); +} + // // Table : inet.0, bgp.l3vpn.0 // Source: eBGP, iBGP @@ -826,6 +1004,23 @@ TEST_P(BgpTableExportParamTest1, NoRemovePrivate) { VerifyAttrAsPathAsCount(PeerAsNumber(), 1); } +TEST_P(BgpTableExportParamTest1, NoRemovePrivateAs4) { + CreateRibOut(BgpProto::EBGP, RibExportPolicy::BGP, 300, true, IpAddress(), + 0, true); + SetAttrAsPath4(4294967294); + SetAttrAsPath4(4200000000); + AddPath(true); + RunExport(); + VerifyExportAccept(); + VerifyAttrAs4BytePrepend(); + VerifyAttrAs4BytePathCount(PeerIsInternal() ? 3 : 4); + VerifyAttrAs4BytePathAsCount(LocalAsNumber(), 1); + VerifyAttrAs4BytePathAsCount(4200000000, 1); + VerifyAttrAs4BytePathAsCount(4294967294, 1); + if (!PeerIsInternal()) + VerifyAttrAs4BytePathAsCount(PeerAsNumber(), 1); +} + INSTANTIATE_TEST_CASE_P(Instance, BgpTableExportParamTest1, ::testing::Combine( ::testing::Values("inet.0", "bgp.l3vpn.0"), @@ -970,7 +1165,7 @@ TEST_P(BgpTableExportParamTest2, EBgpRetainMed2) { // TEST_P(BgpTableExportParamTest2, EBgpNoRetainMed) { CreateRibOut(BgpProto::EBGP, RibExportPolicy::BGP, 300); - SetAttrAsPath(100); + SetAttrAsPath4(100); AddPath(); RunExport(); VerifyExportAccept(); @@ -1006,7 +1201,7 @@ TEST_P(BgpTableExportParamTest2, EBgpStripNonTransitive) { // TEST_P(BgpTableExportParamTest2, RemovePrivateAll1) { RibExportPolicy policy( - BgpProto::EBGP, RibExportPolicy::BGP, 300, false, false, -1, 0); + BgpProto::EBGP, RibExportPolicy::BGP, 300, false, false, false, -1, 0); bool all = true; bool replace = false; bool peer_loop_check = true; policy.SetRemovePrivatePolicy(all, replace, peer_loop_check); CreateRibOut(policy); @@ -1019,19 +1214,35 @@ TEST_P(BgpTableExportParamTest2, RemovePrivateAll1) { VerifyAttrAsPathAsCount(LocalAsNumber(), 1); } +TEST_P(BgpTableExportParamTest2, RemovePrivateAll1As4) { + RibExportPolicy policy( + BgpProto::EBGP, RibExportPolicy::BGP, 300, false, false, true, -1, 0); + bool all = true; bool replace = false; bool peer_loop_check = true; + policy.SetRemovePrivatePolicy(all, replace, peer_loop_check); + CreateRibOut(policy); + ResetAttrAsPath4(); + AddPath(true); + RunExport(); + VerifyExportAccept(); + VerifyAttrAs4BytePrepend(); + VerifyAttrAs4BytePathCount(1); + VerifyAttrAs4BytePathAsCount(LocalAsNumber(), 1); +} + // // Table : inet.0, bgp.l3vpn.0 // Source: iBGP // RibOut: eBGP // Intent: Remove private all is handled gracefully when AsPath has no // segments. -// +// policy and peer do not understand as4 TEST_P(BgpTableExportParamTest2, RemovePrivateAll2) { RibExportPolicy policy( - BgpProto::EBGP, RibExportPolicy::BGP, 300, false, false, -1, 0); + BgpProto::EBGP, RibExportPolicy::BGP, 300, false, false, false, -1, 0); bool all = true; bool replace = false; bool peer_loop_check = true; policy.SetRemovePrivatePolicy(all, replace, peer_loop_check); CreateRibOut(policy); + ResetAttrAsPath4(); AddPath(); RunExport(); VerifyExportAccept(); @@ -1040,6 +1251,51 @@ TEST_P(BgpTableExportParamTest2, RemovePrivateAll2) { VerifyAttrAsPathAsCount(LocalAsNumber(), 1); } +TEST_P(BgpTableExportParamTest2, RemovePrivateAll2As4) { + RibExportPolicy policy( + BgpProto::EBGP, RibExportPolicy::BGP, 300, false, false, true, -1, 0); + bool all = true; bool replace = false; bool peer_loop_check = true; + policy.SetRemovePrivatePolicy(all, replace, peer_loop_check); + CreateRibOut(policy); + ResetAttrAsPath(); + AddPath(true); + RunExport(); + VerifyExportAccept(); + VerifyAttrAs4BytePrepend(); + VerifyAttrAs4BytePathCount(1); + VerifyAttrAs4BytePathAsCount(LocalAsNumber(), 1); +} + +TEST_P(BgpTableExportParamTest2, RemovePrivateAll3) { + RibExportPolicy policy( + BgpProto::EBGP, RibExportPolicy::BGP, 300, false, false, false, -1, 0); + bool all = true; bool replace = false; bool peer_loop_check = true; + policy.SetRemovePrivatePolicy(all, replace, peer_loop_check); + CreateRibOut(policy); + ResetAttrAsPath(); + AddPath(true); + RunExport(); + VerifyExportAccept(); + VerifyAttrAsPrepend(); + VerifyAttrAsPathCount(1); + VerifyAttrAsPathAsCount(LocalAsNumber(), 1); +} + +TEST_P(BgpTableExportParamTest2, RemovePrivateAll3As4) { + RibExportPolicy policy( + BgpProto::EBGP, RibExportPolicy::BGP, 300, false, false, true, -1, 0); + bool all = true; bool replace = false; bool peer_loop_check = true; + policy.SetRemovePrivatePolicy(all, replace, peer_loop_check); + CreateRibOut(policy); + ResetAttrAsPath4(); + AddPath(); + RunExport(); + VerifyExportAccept(); + VerifyAttrAs4BytePrepend(); + VerifyAttrAs4BytePathCount(1); + VerifyAttrAs4BytePathAsCount(LocalAsNumber(), 1); +} + INSTANTIATE_TEST_CASE_P(Instance, BgpTableExportParamTest2, ::testing::Values("inet.0", "bgp.l3vpn.0")); @@ -1122,6 +1378,17 @@ TEST_P(BgpTableExportParamTest3, IBgpNoAsPrepend1) { VerifyAttrNoAsPrepend(); } +TEST_P(BgpTableExportParamTest3, IBgpNoAsPrepend1As4) { + CreateRibOut(BgpProto::IBGP, RibExportPolicy::BGP, LocalAsNumber(), 0, 0, + true); + AddPath(); + RunExport(); + VerifyExportAccept(); + VerifyAttrLocalPref(100); + VerifyAttrMed(100); + VerifyAttrNoAs4Prepend(); +} + // // Table : inet.0, bgp.l3vpn.0 // Source: eBGP @@ -1131,13 +1398,13 @@ TEST_P(BgpTableExportParamTest3, IBgpNoAsPrepend1) { // TEST_P(BgpTableExportParamTest3, IBgpNoAsPrepend2) { CreateRibOut(BgpProto::IBGP, RibExportPolicy::BGP, LocalAsNumber()); - ResetAttrAsPath(); + ResetAttrAsPath4(); AddPath(); RunExport(); VerifyExportAccept(); VerifyAttrLocalPref(100); VerifyAttrMed(100); - VerifyAttrNoAsPrepend(); + VerifyAttrNoAs4Prepend(); } // @@ -1207,6 +1474,19 @@ TEST_P(BgpTableExportParamTest3, AsOverride) { UnregisterRibOut(); } +TEST_P(BgpTableExportParamTest3, As4Override) { + CreateRibOut(BgpProto::EBGP, RibExportPolicy::BGP, 100, true, IpAddress(), + 0, true); + RegisterRibOut(); + AddPath(true); + RunExport(); + VerifyExportAccept(); + VerifyAttrAs4Prepend(); + VerifyAttrAs4BytePathCount(PeerIsInternal() ? 1 : 2); + VerifyAttrNoAs4PathLoop(100); + UnregisterRibOut(); +} + // // Table : inet.0, bgp.l3vpn.0 // Source: eBGP @@ -1242,7 +1522,7 @@ TEST_P(BgpTableExportParamTest3, AsOverrideAndRewriteNexthop) { // TEST_P(BgpTableExportParamTest3, RemovePrivateAll) { RibExportPolicy policy(BgpProto::IBGP, RibExportPolicy::BGP, - LocalAsNumber(), false, false, -1, 0); + LocalAsNumber(), false, false, false, -1, 0); bool all = true; bool replace = false; bool peer_loop_check = true; policy.SetRemovePrivatePolicy(all, replace, peer_loop_check); CreateRibOut(policy); @@ -1265,7 +1545,7 @@ TEST_P(BgpTableExportParamTest3, RemovePrivateAll) { // TEST_P(BgpTableExportParamTest3, RemovePrivateAllReplace1) { RibExportPolicy policy(BgpProto::IBGP, RibExportPolicy::BGP, - LocalAsNumber(), false, false, -1, 0); + LocalAsNumber(), false, false, false, -1, 0); bool all = true; bool replace = true; bool peer_loop_check = true; policy.SetRemovePrivatePolicy(all, replace, peer_loop_check); CreateRibOut(policy); @@ -1290,7 +1570,7 @@ TEST_P(BgpTableExportParamTest3, RemovePrivateAllReplace1) { // TEST_P(BgpTableExportParamTest3, RemovePrivateAllReplace2) { RibExportPolicy policy(BgpProto::IBGP, RibExportPolicy::BGP, - LocalAsNumber(), false, false, -1, 0); + LocalAsNumber(), false, false, false, -1, 0); bool all = true; bool replace = true; bool peer_loop_check = true; policy.SetRemovePrivatePolicy(all, replace, peer_loop_check); CreateRibOut(policy); @@ -1319,7 +1599,7 @@ TEST_P(BgpTableExportParamTest3, RemovePrivateAllReplace2) { // TEST_P(BgpTableExportParamTest3, RemovePrivateAllReplace3) { RibExportPolicy policy(BgpProto::IBGP, RibExportPolicy::BGP, - LocalAsNumber(), false, false, -1, 0); + LocalAsNumber(), false, false, false, -1, 0); bool all = true; bool replace = true; bool peer_loop_check = true; policy.SetRemovePrivatePolicy(all, replace, peer_loop_check); CreateRibOut(policy); diff --git a/src/bgp/test/bgp_table_test.cc b/src/bgp/test/bgp_table_test.cc index 16235a1ff97..f5787b73746 100644 --- a/src/bgp/test/bgp_table_test.cc +++ b/src/bgp/test/bgp_table_test.cc @@ -252,11 +252,11 @@ TEST_F(BgpTableTest, RiboutClusterId) { TEST_F(BgpTableTest, RiboutAS) { RibOut *ribout1 = NULL, *ribout2 = NULL, *ribout3 = NULL, *temp = NULL; RibExportPolicy policy1( - BgpProto::EBGP, RibExportPolicy::BGP, 101, false, false, -1, 0); + BgpProto::EBGP, RibExportPolicy::BGP, 101, false, false, false, -1, 0); RibExportPolicy policy2( - BgpProto::EBGP, RibExportPolicy::BGP, 102, false, false, -1, 0); + BgpProto::EBGP, RibExportPolicy::BGP, 102, false, false, false, -1, 0); RibExportPolicy policy3( - BgpProto::EBGP, RibExportPolicy::BGP, 103, false, false, -1, 0); + BgpProto::EBGP, RibExportPolicy::BGP, 103, false, false, false, -1, 0); // Create 3 ribouts. ribout1 = rt_table_->RibOutLocate(&sender_, policy1); @@ -294,9 +294,9 @@ TEST_F(BgpTableTest, RiboutAS) { TEST_F(BgpTableTest, RiboutASOverride) { RibOut *ribout1 = NULL, *ribout2 = NULL, *temp = NULL; RibExportPolicy policy1( - BgpProto::EBGP, RibExportPolicy::BGP, 100, true, false, -1, 0); + BgpProto::EBGP, RibExportPolicy::BGP, 100, true, false, false, -1, 0); RibExportPolicy policy2( - BgpProto::EBGP, RibExportPolicy::BGP, 100, false, false, -1, 0); + BgpProto::EBGP, RibExportPolicy::BGP, 100, false, false, false, -1, 0); // Create 2 ribouts. ribout1 = rt_table_->RibOutLocate(&sender_, policy1); @@ -332,11 +332,14 @@ TEST_F(BgpTableTest, RiboutNexthop) { RibOut *ribout1 = NULL, *ribout2 = NULL, *ribout3 = NULL, *temp = NULL; vector default_tunnel_encap_list; RibExportPolicy policy1(BgpProto::EBGP, RibExportPolicy::BGP, 100, true, - false, nexthop1, -1, 0, default_tunnel_encap_list); + false, false, nexthop1, -1, 0, + default_tunnel_encap_list); RibExportPolicy policy2(BgpProto::EBGP, RibExportPolicy::BGP, 100, true, - false, nexthop2, -1, 0, default_tunnel_encap_list); + false, false, nexthop2, -1, 0, + default_tunnel_encap_list); RibExportPolicy policy3(BgpProto::EBGP, RibExportPolicy::BGP, 100, true, - false, nexthop3, -1, 0, default_tunnel_encap_list); + false, false, nexthop3, -1, 0, + default_tunnel_encap_list); // Create 3 ribouts. ribout1 = rt_table_->RibOutLocate(&sender_, policy1); @@ -374,9 +377,9 @@ TEST_F(BgpTableTest, RiboutNexthop) { TEST_F(BgpTableTest, RiboutLlgrDisabled) { RibOut *ribout1 = NULL, *ribout2 = NULL, *temp = NULL; RibExportPolicy policy1( - BgpProto::EBGP, RibExportPolicy::BGP, 100, false, false, -1, 0); + BgpProto::EBGP, RibExportPolicy::BGP, 100, false, false, false, -1, 0); RibExportPolicy policy2( - BgpProto::EBGP, RibExportPolicy::BGP, 100, false, false, -1, 0); + BgpProto::EBGP, RibExportPolicy::BGP, 100, false, false, false, -1, 0); // Create 2 ribouts. ribout1 = rt_table_->RibOutLocate(&sender_, policy1); @@ -407,9 +410,9 @@ TEST_F(BgpTableTest, RiboutLlgrDisabled) { TEST_F(BgpTableTest, RiboutLlgrEnabled) { RibOut *ribout1 = NULL, *ribout2 = NULL, *temp = NULL; RibExportPolicy policy1( - BgpProto::EBGP, RibExportPolicy::BGP, 100, false, true, -1, 0); + BgpProto::EBGP, RibExportPolicy::BGP, 100, false, true, false, -1, 0); RibExportPolicy policy2( - BgpProto::EBGP, RibExportPolicy::BGP, 100, false, false, -1, 0); + BgpProto::EBGP, RibExportPolicy::BGP, 100, false, false, false, -1, 0); // Create 2 ribouts. ribout1 = rt_table_->RibOutLocate(&sender_, policy1); diff --git a/src/bgp/test/bgp_xmpp_rtarget_manager_test.cc b/src/bgp/test/bgp_xmpp_rtarget_manager_test.cc index dae3efb9835..3f21c5e9583 100644 --- a/src/bgp/test/bgp_xmpp_rtarget_manager_test.cc +++ b/src/bgp/test/bgp_xmpp_rtarget_manager_test.cc @@ -91,7 +91,7 @@ class BgpXmppRTargetManagerTest : public BgpXmppRTargetManager { } RouteTargetList *rtarget_list() { return &rtarget_list_; } - virtual void RTargetRouteOp(as4_t asn, const RouteTarget &rtarget, + virtual void RTargetRouteOp(as_t asn, const RouteTarget &rtarget, BgpAttrPtr attr, bool add_change, uint32_t flags) const { BgpXmppRTargetManager::RTargetRouteOp(asn, rtarget, attr, add_change, diff --git a/src/bgp/test/bgp_xmpp_rtarget_test.cc b/src/bgp/test/bgp_xmpp_rtarget_test.cc index 12173cf4bd1..b90919b16a1 100644 --- a/src/bgp/test/bgp_xmpp_rtarget_test.cc +++ b/src/bgp/test/bgp_xmpp_rtarget_test.cc @@ -276,6 +276,31 @@ class BgpXmppRTargetTest : public ::testing::Test { task_util::WaitForIdle(); } + bool WalkCallback(DBTablePartBase *tpart, DBEntryBase *db_entry) { + CHECK_CONCURRENCY("db::DBTable"); + BgpRoute *route = static_cast(db_entry); + std::cout << route->ToString() << std::endl; + return true; + } + + void WalkDoneCallback(DBTable::DBTableWalkRef ref, + DBTableBase *table, bool *complete) { + if (complete) + *complete = true; + } + + void WalkTable(BgpTable *table) { + bool complete = false; + DBTable::DBTableWalkRef walk_ref = table->AllocWalker( + boost::bind(&BgpXmppRTargetTest::WalkCallback, this, _1, _2), + boost::bind(&BgpXmppRTargetTest::WalkDoneCallback, this, _1, _2, + &complete)); + std::cout << "Table " << table->name() << " walk start\n"; + table->WalkTable(walk_ref); + TASK_UTIL_EXPECT_TRUE(complete); + std::cout << "Table " << table->name() << " walk end\n"; + } + void AddDeleteRTargetRoute(BgpServer *server, bool add_change, const string &rt_prefix_str) { RoutingInstanceMgr *instance_mgr = server->routing_instance_mgr(); @@ -400,8 +425,9 @@ class BgpXmppRTargetTest : public ::testing::Test { return peer; } - void Configure(int cn1_asn, int cn2_asn, int mx_asn, - int cn1_local_asn = 0, int cn2_local_asn = 0, int mx_local_asn = 0) { + void Configure(as_t cn1_asn, as_t cn2_asn, as_t mx_asn, + as_t cn1_local_asn = 0, as_t cn2_local_asn = 0, + as_t mx_local_asn = 0) { if (cn1_local_asn == 0) cn1_local_asn = cn1_asn; if (cn2_local_asn == 0) @@ -509,8 +535,9 @@ class BgpXmppRTargetTest : public ::testing::Test { task_util::WaitForIdle(); } - void UpdateASN(int cn1_asn, int cn2_asn, int mx_asn, - int cn1_local_asn = 0, int cn2_local_asn = 0, int mx_local_asn = 0) { + void UpdateASN(as_t cn1_asn, as_t cn2_asn, as_t mx_asn, + as_t cn1_local_asn = 0, as_t cn2_local_asn = 0, + as_t mx_local_asn = 0) { if (cn1_local_asn == 0) cn1_local_asn = cn1_asn; if (cn2_local_asn == 0) @@ -542,8 +569,8 @@ class BgpXmppRTargetTest : public ::testing::Test { TASK_UTIL_EXPECT_EQ(mx_local_asn, mx_->local_autonomous_system()); } - void UpdateIdentifier(int cn1_asn, int cn2_asn, int mx_asn, - int cn1_local_asn, int cn2_local_asn, int mx_local_asn) { + void UpdateIdentifier(as_t cn1_asn, as_t cn2_asn, as_t mx_asn, + as_t cn1_local_asn, as_t cn2_local_asn, as_t mx_local_asn) { char config[4096]; snprintf(config, sizeof(config), config_template1, cn1_asn, cn1_local_asn, cn1_->session_manager()->GetPort(), diff --git a/src/bgp/test/path_resolver_test.cc b/src/bgp/test/path_resolver_test.cc index 12e3d9a4850..6ba1436524d 100644 --- a/src/bgp/test/path_resolver_test.cc +++ b/src/bgp/test/path_resolver_test.cc @@ -67,6 +67,7 @@ class PeerMock : public IPeer { virtual const std::string GetStateName() const { return ""; } virtual void UpdateTotalPathCount(int count) const { } virtual int GetTotalPathCount() const { return 0; } + virtual bool IsAs4Supported() const { return false; } virtual void UpdatePrimaryPathCount(int count, Address::Family family) const { } virtual int GetPrimaryPathCount() const { return 0; } diff --git a/src/bgp/test/ribout_attributes_test.cc b/src/bgp/test/ribout_attributes_test.cc index 39a5c86484b..a2e8ea021fd 100644 --- a/src/bgp/test/ribout_attributes_test.cc +++ b/src/bgp/test/ribout_attributes_test.cc @@ -35,6 +35,7 @@ class BgpPeerMock : public IPeer { virtual const std::string GetStateName() const { return "UNKNOWN"; } virtual void UpdateTotalPathCount(int count) const { } virtual int GetTotalPathCount() const { return 0; } + virtual bool IsAs4Supported() const { return false; } virtual void UpdatePrimaryPathCount(int count, Address::Family family) const { } virtual int GetPrimaryPathCount() const { return 0; } diff --git a/src/bgp/test/route_aggregator_test.cc b/src/bgp/test/route_aggregator_test.cc index a2c01f82952..d7a375f0a52 100644 --- a/src/bgp/test/route_aggregator_test.cc +++ b/src/bgp/test/route_aggregator_test.cc @@ -95,6 +95,7 @@ class BgpPeerMock : public IPeer { } virtual void UpdateTotalPathCount(int count) const { } virtual int GetTotalPathCount() const { return 0; } + virtual bool IsAs4Supported() const { return false; } virtual void UpdatePrimaryPathCount(int count, Address::Family family) const { } virtual int GetPrimaryPathCount() const { return 0; } diff --git a/src/bgp/test/routepath_replicator_random_test.cc b/src/bgp/test/routepath_replicator_random_test.cc index e9cc886819d..09f0535e661 100644 --- a/src/bgp/test/routepath_replicator_random_test.cc +++ b/src/bgp/test/routepath_replicator_random_test.cc @@ -103,6 +103,7 @@ class BgpPeerMock : public IPeer { } virtual void UpdateTotalPathCount(int count) const { } virtual int GetTotalPathCount() const { return 0; } + virtual bool IsAs4Supported() const { return false; } virtual void UpdatePrimaryPathCount(int count, Address::Family family) const { } virtual int GetPrimaryPathCount() const { return 0; } diff --git a/src/bgp/test/routepath_replicator_test.cc b/src/bgp/test/routepath_replicator_test.cc index 93fcc5e737e..141173e7530 100644 --- a/src/bgp/test/routepath_replicator_test.cc +++ b/src/bgp/test/routepath_replicator_test.cc @@ -73,6 +73,7 @@ class BgpPeerMock : public IPeer { } virtual void UpdateTotalPathCount(int count) const { } virtual int GetTotalPathCount() const { return 0; } + virtual bool IsAs4Supported() const { return false; } virtual void UpdatePrimaryPathCount(int count, Address::Family family) const { } virtual int GetPrimaryPathCount() const { return 0; } diff --git a/src/bgp/test/routing_policy_action_test.cc b/src/bgp/test/routing_policy_action_test.cc index e5435dc9f91..8ff5285cf57 100644 --- a/src/bgp/test/routing_policy_action_test.cc +++ b/src/bgp/test/routing_policy_action_test.cc @@ -112,15 +112,15 @@ class UpdateAsPathTest : public ::testing::Test { }; TEST_F(UpdateAsPathTest, ToString) { - vector asn_list = list_of(1000)(2000); + vector asn_list = list_of(1000)(2000); UpdateAsPath action(asn_list); EXPECT_EQ(asn_list, action.asn_list()); EXPECT_EQ("as-path expand [ 1000,2000 ]", action.ToString()); } TEST_F(UpdateAsPathTest, IsEqual1) { - vector asn_list1 = list_of(1000)(2000); - vector asn_list2 = list_of(1000)(2000); + vector asn_list1 = list_of(1000)(2000); + vector asn_list2 = list_of(1000)(2000); UpdateAsPath action1(asn_list1); UpdateAsPath action2(asn_list2); EXPECT_TRUE(action1.IsEqual(action2)); @@ -128,8 +128,8 @@ TEST_F(UpdateAsPathTest, IsEqual1) { } TEST_F(UpdateAsPathTest, IsEqual2) { - vector asn_list1 = list_of(1000)(2000); - vector asn_list2 = list_of(1000)(3000); + vector asn_list1 = list_of(1000)(2000); + vector asn_list2 = list_of(1000)(3000); UpdateAsPath action1(asn_list1); UpdateAsPath action2(asn_list2); EXPECT_FALSE(action1.IsEqual(action2)); @@ -137,15 +137,15 @@ TEST_F(UpdateAsPathTest, IsEqual2) { } TEST_F(UpdateAsPathTest, UpdateNull) { - vector asn_list = list_of(1000)(2000); + vector asn_list = list_of(1000)(2000); UpdateAsPath action(asn_list); EXPECT_EQ(asn_list, action.asn_list()); BgpAttr attr(attr_db_); action(&attr); - const AsPath *as_path = attr.as_path(); + const AsPath4Byte *as_path = attr.aspath_4byte(); EXPECT_TRUE(as_path != NULL); - const AsPathSpec &as_path_spec = as_path->path(); + const AsPath4ByteSpec &as_path_spec = as_path->path(); EXPECT_EQ(1, as_path_spec.path_segments.size()); EXPECT_EQ(2, as_path_spec.path_segments[0]->path_segment.size()); EXPECT_EQ(1000, as_path_spec.path_segments[0]->path_segment[0]); @@ -153,23 +153,23 @@ TEST_F(UpdateAsPathTest, UpdateNull) { } TEST_F(UpdateAsPathTest, UpdateNonNull) { - vector asn_list = list_of(1000)(2000); + vector asn_list = list_of(1000)(2000); UpdateAsPath action(asn_list); EXPECT_EQ(asn_list, action.asn_list()); BgpAttrSpec spec; - AsPathSpec path; - AsPathSpec::PathSegment *ps = new AsPathSpec::PathSegment; - ps->path_segment_type = AsPathSpec::PathSegment::AS_SEQUENCE; + AsPath4ByteSpec path; + AsPath4ByteSpec::PathSegment *ps = new AsPath4ByteSpec::PathSegment; + ps->path_segment_type = AsPath4ByteSpec::PathSegment::AS_SEQUENCE; ps->path_segment = list_of(3000)(4000); path.path_segments.push_back(ps); spec.push_back(&path); BgpAttr attr(attr_db_, spec); action(&attr); - const AsPath *as_path = attr.as_path(); + const AsPath4Byte *as_path = attr.aspath_4byte(); EXPECT_TRUE(as_path != NULL); - const AsPathSpec &as_path_spec = as_path->path(); + const AsPath4ByteSpec &as_path_spec = as_path->path(); EXPECT_EQ(1, as_path_spec.path_segments.size()); EXPECT_EQ(4, as_path_spec.path_segments[0]->path_segment.size()); EXPECT_EQ(1000, as_path_spec.path_segments[0]->path_segment[0]); diff --git a/src/bgp/test/routing_policy_match_test.cc b/src/bgp/test/routing_policy_match_test.cc index a2a101e5b19..5fced9b02bb 100644 --- a/src/bgp/test/routing_policy_match_test.cc +++ b/src/bgp/test/routing_policy_match_test.cc @@ -54,6 +54,7 @@ class PeerMock : public IPeer { virtual const std::string GetStateName() const { return ""; } virtual void UpdateTotalPathCount(int count) const { } virtual int GetTotalPathCount() const { return 0; } + virtual bool IsAs4Supported() const { return false; } virtual void UpdatePrimaryPathCount(int count, Address::Family family) const { } virtual int GetPrimaryPathCount() const { return 0; } diff --git a/src/bgp/test/routing_policy_test.cc b/src/bgp/test/routing_policy_test.cc index f81f61e0fb3..d7c78b05c20 100644 --- a/src/bgp/test/routing_policy_test.cc +++ b/src/bgp/test/routing_policy_test.cc @@ -97,6 +97,7 @@ class BgpPeerMock : public IPeer { } virtual void UpdateTotalPathCount(int count) const { } virtual int GetTotalPathCount() const { return 0; } + virtual bool IsAs4Supported() const { return false; } virtual void UpdatePrimaryPathCount(int count, Address::Family family) const { } virtual int GetPrimaryPathCount() const { return 0; } @@ -603,12 +604,13 @@ TEST_F(RoutingPolicyTest, PolicyNoMatchUpdateAsPath) { ASSERT_TRUE(rt != NULL); VERIFY_EQ(peers_[0], rt->BestPath()->GetPeer()); const BgpAttr *attr = rt->BestPath()->GetAttr(); - ASSERT_EQ(1, attr->as_path()->path().path_segments.size()); - ASSERT_EQ(2, attr->as_path()->path().path_segments[0]->path_segment.size()); + ASSERT_EQ(1, attr->aspath_4byte()->path().path_segments.size()); + ASSERT_EQ(2, + attr->aspath_4byte()->path().path_segments[0]->path_segment.size()); ASSERT_EQ(1000, - attr->as_path()->path().path_segments[0]->path_segment[0]); + attr->aspath_4byte()->path().path_segments[0]->path_segment[0]); ASSERT_EQ(2000, - attr->as_path()->path().path_segments[0]->path_segment[1]); + attr->aspath_4byte()->path().path_segments[0]->path_segment[1]); DeleteRoute(peers_[0], "test.inet.0", "10.0.1.1/32"); } diff --git a/src/bgp/test/service_chain_test.cc b/src/bgp/test/service_chain_test.cc index 0554032079a..302f62933c5 100644 --- a/src/bgp/test/service_chain_test.cc +++ b/src/bgp/test/service_chain_test.cc @@ -110,6 +110,7 @@ class BgpPeerMock : public IPeer { } virtual void UpdateTotalPathCount(int count) const { } virtual int GetTotalPathCount() const { return 0; } + virtual bool IsAs4Supported() const { return false; } virtual void UpdatePrimaryPathCount(int count, Address::Family family) const { } virtual int GetPrimaryPathCount() const { return 0; } diff --git a/src/bgp/test/static_route_test.cc b/src/bgp/test/static_route_test.cc index 191c6f4cdc4..d067d17561c 100644 --- a/src/bgp/test/static_route_test.cc +++ b/src/bgp/test/static_route_test.cc @@ -103,6 +103,7 @@ class BgpPeerMock : public IPeer { } virtual void UpdateTotalPathCount(int count) const { } virtual int GetTotalPathCount() const { return 0; } + virtual bool IsAs4Supported() const { return false; } virtual void UpdatePrimaryPathCount(int count, Address::Family family) const { } virtual int GetPrimaryPathCount() const { return 0; } diff --git a/src/bgp/xmpp_message_builder.cc b/src/bgp/xmpp_message_builder.cc index 4aa156bd07e..5e1b7bad869 100644 --- a/src/bgp/xmpp_message_builder.cc +++ b/src/bgp/xmpp_message_builder.cc @@ -588,6 +588,11 @@ void BgpXmppMessage::ProcessExtCommunity(const ExtCommunity *ext_community) { if (sg.as_number() != as_number && !sg.IsGlobal()) continue; security_group_list_.push_back(sg.security_group_id()); + } else if (ExtCommunity::is_security_group4(*iter)) { + SecurityGroup4ByteAs sg(*iter); + if (sg.as_number() != as_number && !sg.IsGlobal()) + continue; + security_group_list_.push_back(sg.security_group_id()); } else if (ExtCommunity::is_mac_mobility(*iter)) { MacMobility mm(*iter); mobility_.sequence_number = mm.sequence_number();