diff --git a/src/bgp/bgp_attr.cc b/src/bgp/bgp_attr.cc index 38119d0b39d..148c0833436 100644 --- a/src/bgp/bgp_attr.cc +++ b/src/bgp/bgp_attr.cc @@ -9,6 +9,7 @@ #include "bgp/bgp_server.h" #include "bgp/extended-community/mac_mobility.h" +#include "bgp/extended-community/router_mac.h" #include "net/bgp_af.h" using std::sort; @@ -966,6 +967,20 @@ uint32_t BgpAttr::sequence_number() const { return 0; } +MacAddress BgpAttr::mac_address() const { + if (!ext_community_) + return MacAddress::kZeroMac; + for (ExtCommunity::ExtCommunityList::const_iterator it = + ext_community_->communities().begin(); + it != ext_community_->communities().end(); ++it) { + if (ExtCommunity::is_router_mac(*it)) { + RouterMac router_mac(*it); + return router_mac.mac_address(); + } + } + return MacAddress::kZeroMac; +} + void BgpAttr::Remove() { attr_db_->Delete(this); } diff --git a/src/bgp/bgp_attr.h b/src/bgp/bgp_attr.h index 3f2b9255bba..4c329943b35 100644 --- a/src/bgp/bgp_attr.h +++ b/src/bgp/bgp_attr.h @@ -21,6 +21,7 @@ #include "bgp/community.h" #include "net/address.h" #include "net/esi.h" +#include "net/mac_address.h" #include "net/rd.h" class BgpAttr; @@ -852,6 +853,7 @@ class BgpAttr { BgpOListPtr leaf_olist() const { return leaf_olist_; } BgpAttrDB *attr_db() const { return attr_db_; } uint32_t sequence_number() const; + MacAddress mac_address() const; private: friend class BgpAttrDB; diff --git a/src/bgp/community.h b/src/bgp/community.h index 3d211dc1206..4b18c274887 100644 --- a/src/bgp/community.h +++ b/src/bgp/community.h @@ -217,6 +217,14 @@ class ExtCommunity { (val[1] == BgpExtendedCommunityEvpnSubType::MacMobility); } + static bool is_router_mac(const ExtCommunityValue &val) { + // + // Router MAC extended community + // + return (val[0] == BgpExtendedCommunityType::Evpn) && + (val[1] == BgpExtendedCommunityEvpnSubType::RouterMac); + } + static bool is_route_target(const ExtCommunityValue &val) { // // Route target extended community diff --git a/src/bgp/extended-community/SConscript b/src/bgp/extended-community/SConscript index f94a2e69cc8..5cd6adfbbbe 100644 --- a/src/bgp/extended-community/SConscript +++ b/src/bgp/extended-community/SConscript @@ -18,6 +18,7 @@ libextended_community = env.Library('extended_community', 'esi_label.cc', 'load_balance.cc', 'mac_mobility.cc', + 'router_mac.cc', 'site_of_origin.cc']) extended_community_test_cases = env.SConscript('test/SConscript', exports='BuildEnv', diff --git a/src/bgp/extended-community/router_mac.cc b/src/bgp/extended-community/router_mac.cc new file mode 100644 index 00000000000..dbdf6c3a86a --- /dev/null +++ b/src/bgp/extended-community/router_mac.cc @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2016 Juniper Networks, Inc. All rights reserved. + */ + +#include "bgp/extended-community/router_mac.h" + +#include +#include + +using std::copy; +using std::string; + +RouterMac::RouterMac(const MacAddress &mac_addr) { + data_[0] = BgpExtendedCommunityType::Evpn; + data_[1] = BgpExtendedCommunityEvpnSubType::RouterMac; + copy(mac_addr.GetData(), mac_addr.GetData() + 6, data_.begin() + 2); +} + +RouterMac::RouterMac(const bytes_type &data) { + copy(data.begin(), data.end(), data_.begin()); +} + +MacAddress RouterMac::mac_address() const { + uint8_t data[RouterMac::kSize]; + copy(data_.begin(), data_.end(), &data[0]); + if (data[0] == BgpExtendedCommunityType::Evpn && + data[1] == BgpExtendedCommunityEvpnSubType::RouterMac) { + return MacAddress(&data[2]); + } + return MacAddress::kZeroMac; +} + +string RouterMac::ToString() { + return string("rtrmac:") + mac_address().ToString(); +} diff --git a/src/bgp/extended-community/router_mac.h b/src/bgp/extended-community/router_mac.h new file mode 100644 index 00000000000..d5306aad037 --- /dev/null +++ b/src/bgp/extended-community/router_mac.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2016 Juniper Networks, Inc. All rights reserved. + */ + +#ifndef SRC_BGP_EXTENDED_COMMUNITY_ROUTER_MAC_H_ +#define SRC_BGP_EXTENDED_COMMUNITY_ROUTER_MAC_H_ + +#include +#include + +#include + +#include "base/parse_object.h" +#include "bgp/extended-community/types.h" +#include "net/mac_address.h" + +class RouterMac { +public: + static const int kSize = 8; + typedef boost::array bytes_type; + + explicit RouterMac(const MacAddress &mac_addr); + explicit RouterMac(const bytes_type &data); + + MacAddress mac_address() 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_; +}; + +#endif // SRC_BGP_EXTENDED_COMMUNITY_ROUTER_MAC_H_ diff --git a/src/bgp/extended-community/test/SConscript b/src/bgp/extended-community/test/SConscript index 6577101c2b1..0629782db1e 100644 --- a/src/bgp/extended-community/test/SConscript +++ b/src/bgp/extended-community/test/SConscript @@ -35,6 +35,10 @@ mac_mobility_test = env.UnitTest('mac_mobility_test', ['mac_mobility_test.cc']) env.Alias('src/bgp/extended-community:mac_mobility_test', mac_mobility_test) +router_mac_test = env.UnitTest('router_mac_test', + ['router_mac_test.cc']) +env.Alias('src/bgp/extended-community:router_mac_test', router_mac_test) + site_of_origin_test = env.UnitTest('site_of_origin_test', ['site_of_origin_test.cc']) env.Alias('src/bgp/extended-community:site_of_origin_test', site_of_origin_test) @@ -49,6 +53,7 @@ test_suite = [ esi_label_test, load_balance_test, mac_mobility_test, + router_mac_test, site_of_origin_test, ] diff --git a/src/bgp/extended-community/test/router_mac_test.cc b/src/bgp/extended-community/test/router_mac_test.cc new file mode 100644 index 00000000000..0e6387112e1 --- /dev/null +++ b/src/bgp/extended-community/test/router_mac_test.cc @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved. + */ + +#include "bgp/extended-community/router_mac.h" + +#include "bgp/community.h" +#include "testing/gunit.h" + +using namespace std; + +class RouterMacTest : public ::testing::Test { +}; + +TEST_F(RouterMacTest, ByteArray_1) { + RouterMac::bytes_type data = { { + BgpExtendedCommunityType::Evpn, + BgpExtendedCommunityEvpnSubType::RouterMac, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 + } }; + RouterMac router_mac(data); + EXPECT_TRUE(ExtCommunity::is_router_mac(router_mac.GetExtCommunity())); + EXPECT_EQ("rtrmac:01:02:03:04:05:06", router_mac.ToString()); +} + +TEST_F(RouterMacTest, ByteArray_2) { + RouterMac::bytes_type data = { { + BgpExtendedCommunityType::Evpn, + BgpExtendedCommunityEvpnSubType::RouterMac, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f + } }; + RouterMac router_mac(data); + EXPECT_TRUE(ExtCommunity::is_router_mac(router_mac.GetExtCommunity())); + EXPECT_EQ("rtrmac:0a:0b:0c:0d:0e:0f", router_mac.ToString()); +} + +TEST_F(RouterMacTest, MacAddress_1) { + boost::system::error_code ec; + MacAddress mac_addr = MacAddress::FromString("01:02:03:04:05:06", &ec); + EXPECT_EQ(0, ec.value()); + RouterMac router_mac(mac_addr); + EXPECT_TRUE(ExtCommunity::is_router_mac(router_mac.GetExtCommunity())); + EXPECT_EQ("rtrmac:01:02:03:04:05:06", router_mac.ToString()); + EXPECT_EQ(mac_addr, router_mac.mac_address()); + RouterMac router_mac2(router_mac.GetExtCommunity()); + EXPECT_EQ(router_mac.GetExtCommunityValue(), + router_mac2.GetExtCommunityValue()); +} + +TEST_F(RouterMacTest, MacAddress_2) { + boost::system::error_code ec; + MacAddress mac_addr = MacAddress::FromString("0a:0b:0c:0d:0e:0f", &ec); + EXPECT_EQ(0, ec.value()); + RouterMac router_mac(mac_addr); + EXPECT_TRUE(ExtCommunity::is_router_mac(router_mac.GetExtCommunity())); + EXPECT_EQ("rtrmac:0a:0b:0c:0d:0e:0f", router_mac.ToString()); + EXPECT_EQ(mac_addr, router_mac.mac_address()); + RouterMac router_mac2(router_mac.GetExtCommunity()); + EXPECT_EQ(router_mac.GetExtCommunityValue(), + router_mac2.GetExtCommunityValue()); +} + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + int result = RUN_ALL_TESTS(); + return result; +} diff --git a/src/bgp/extended-community/types.h b/src/bgp/extended-community/types.h index bee782a2f8c..e72e44ab2c9 100644 --- a/src/bgp/extended-community/types.h +++ b/src/bgp/extended-community/types.h @@ -36,6 +36,7 @@ struct BgpExtendedCommunityEvpnSubType { MacMobility = 0x00, EsiMplsLabel = 0x01, EsImport = 0x02, + RouterMac = 0x03, }; }; diff --git a/src/bgp/test/bgp_attr_test.cc b/src/bgp/test/bgp_attr_test.cc index d1244d3e158..52aa533c582 100644 --- a/src/bgp/test/bgp_attr_test.cc +++ b/src/bgp/test/bgp_attr_test.cc @@ -14,9 +14,11 @@ #include "bgp/bgp_server.h" #include "bgp/evpn/evpn_route.h" #include "bgp/extended-community/mac_mobility.h" +#include "bgp/extended-community/router_mac.h" #include "bgp/origin-vn/origin_vn.h" #include "control-node/control_node.h" #include "net/community_type.h" +#include "net/mac_address.h" using boost::assign::list_of; using boost::system::error_code; @@ -1140,6 +1142,30 @@ TEST_F(BgpAttrTest, SequenceNumber2) { EXPECT_EQ(13, attr->sequence_number()); } +TEST_F(BgpAttrTest, RouterMac1) { + BgpAttrSpec attr_spec; + ExtCommunitySpec spec; + for (int idx = 1; idx < 5; idx++) + spec.communities.push_back(100 * idx); + attr_spec.push_back(&spec); + BgpAttrPtr attr = attr_db_->Locate(attr_spec); + EXPECT_TRUE(attr->mac_address().IsZero()); +} + +TEST_F(BgpAttrTest, RouterMac2) { + BgpAttrSpec attr_spec; + boost::system::error_code ec; + MacAddress mac_addr = MacAddress::FromString("01:02:03:04:05:06", &ec); + EXPECT_EQ(0, ec.value()); + RouterMac router_mac(mac_addr); + ExtCommunitySpec spec; + spec.communities.push_back(router_mac.GetExtCommunityValue()); + attr_spec.push_back(&spec); + BgpAttrPtr attr = attr_db_->Locate(attr_spec); + EXPECT_FALSE(attr->mac_address().IsZero()); + EXPECT_EQ(mac_addr, attr->mac_address()); +} + TEST_F(BgpAttrTest, OriginVnPathToString) { OriginVnPathSpec spec; for (int idx = 1; idx < 5; idx++)