Line data Source code
1 : /*
2 : * Copyright (c) 2019 Juniper Networks, Inc. All rights reserved.
3 : * Copyright Contributors to the OpenSDN project
4 : */
5 :
6 : #include "bgp/extended-community/sub_cluster.h"
7 :
8 : #include <algorithm>
9 :
10 : #include "base/address.h"
11 :
12 : using std::copy;
13 : using std::string;
14 :
15 : SubCluster SubCluster::null_sub_cluster;
16 :
17 175 : SubCluster::SubCluster() {
18 175 : data_.fill(0);
19 175 : }
20 :
21 9 : SubCluster::SubCluster(const bytes_type &data) {
22 9 : copy(data.begin(), data.end(), data_.begin());
23 9 : }
24 :
25 4 : SubCluster::SubCluster(as_t asn, const uint32_t id) {
26 4 : if (asn <= AS2_MAX) {
27 3 : data_[0] = BgpExtendedCommunityType::Experimental;
28 3 : put_value(&data_[2], 2, asn);
29 3 : put_value(&data_[4], 4, id);
30 : } else {
31 1 : data_[0] = BgpExtendedCommunityType::Experimental4ByteAs;
32 1 : put_value(&data_[2], 4, asn);
33 1 : put_value(&data_[6], SubCluster::kSize - 6, id);
34 : }
35 4 : data_[1] = BgpExtendedCommunitySubType::SubCluster;
36 4 : }
37 :
38 5 : uint32_t SubCluster::GetId() const {
39 5 : if (data_[0] == BgpExtendedCommunityType::Experimental) {
40 4 : return get_value(&data_[4], 4);
41 : }
42 :
43 1 : if (data_[0] == BgpExtendedCommunityType::Experimental4ByteAs) {
44 1 : return get_value(&data_[6], 2);
45 : }
46 0 : return 0;
47 : }
48 :
49 2 : uint32_t SubCluster::GetAsn() const {
50 2 : if (data_[0] == BgpExtendedCommunityType::Experimental) {
51 1 : return get_value(&data_[2], 2);
52 : }
53 :
54 1 : if (data_[0] == BgpExtendedCommunityType::Experimental4ByteAs) {
55 1 : return get_value(&data_[2], 4);
56 : }
57 0 : return 0;
58 : }
59 :
60 10 : string SubCluster::ToString() const {
61 : uint8_t data[SubCluster::kSize];
62 10 : copy(data_.begin(), data_.end(), &data[0]);
63 : char temp[50];
64 :
65 10 : if (data_[0] == BgpExtendedCommunityType::Experimental) {
66 7 : uint16_t asn = get_value(data + 2, 2);
67 7 : uint32_t id = get_value(data + 4, 4);
68 7 : snprintf(temp, sizeof(temp), "subcluster:%u:%u", asn, id);
69 7 : return string(temp);
70 : }
71 :
72 3 : if (data_[0] == BgpExtendedCommunityType::Experimental4ByteAs) {
73 3 : uint32_t asn = get_value(data + 2, 4);
74 3 : uint16_t id = get_value(data + 6, 2);
75 3 : snprintf(temp, sizeof(temp), "subcluster:%u:%u", asn, id);
76 3 : return string(temp);
77 : }
78 0 : return "";
79 : }
80 :
81 15 : SubCluster SubCluster::FromString(const string &str,
82 : boost::system::error_code *errorp) {
83 15 : SubCluster sc;
84 : uint8_t data[SubCluster::kSize];
85 :
86 : // subcluster:1:2
87 15 : size_t pos = str.find(':');
88 15 : if (pos == string::npos) {
89 0 : if (errorp != NULL) {
90 0 : *errorp = make_error_code(boost::system::errc::invalid_argument);
91 : }
92 0 : return SubCluster::null_sub_cluster;
93 : }
94 :
95 15 : string first(str.substr(0, pos));
96 15 : if (first != "subcluster") {
97 0 : if (errorp != NULL) {
98 0 : *errorp = make_error_code(boost::system::errc::invalid_argument);
99 : }
100 0 : return SubCluster::null_sub_cluster;
101 : }
102 :
103 15 : string rest(str.substr(pos+1));
104 :
105 15 : pos = rest.find(':');
106 15 : if (pos == string::npos) {
107 1 : if (errorp != NULL) {
108 1 : *errorp = make_error_code(boost::system::errc::invalid_argument);
109 : }
110 1 : return SubCluster::null_sub_cluster;
111 : }
112 :
113 14 : boost::system::error_code ec;
114 14 : string second(rest.substr(0, pos));
115 14 : int offset = 6;
116 : char *endptr;
117 : // Get ASN
118 14 : uint64_t asn = strtoll(second.c_str(), &endptr, 10);
119 14 : if (asn == 0 || asn > 0xFFFFFFFF || *endptr != '\0') {
120 3 : if (errorp != NULL) {
121 3 : *errorp = make_error_code(boost::system::errc::invalid_argument);
122 : }
123 3 : return SubCluster::null_sub_cluster;
124 : }
125 :
126 11 : string third(rest.substr(pos+1));
127 11 : uint64_t id = strtoll(third.c_str(), &endptr, 10);
128 11 : if (*endptr != '\0') {
129 1 : if (errorp != NULL) {
130 1 : *errorp = make_error_code(boost::system::errc::invalid_argument);
131 : }
132 1 : return SubCluster::null_sub_cluster;
133 : }
134 :
135 : // Check assigned number.
136 10 : if ((asn > AS2_MAX && id > 0xFFFF) || id == 0 || id > 0xFFFFFFFF) {
137 6 : if (errorp != NULL) {
138 6 : *errorp = make_error_code(boost::system::errc::invalid_argument);
139 : }
140 6 : return SubCluster::null_sub_cluster;
141 : }
142 :
143 4 : if (asn <= AS2_MAX) {
144 3 : data[0] = BgpExtendedCommunityType::Experimental;
145 3 : put_value(&data[2], 2, asn);
146 3 : offset = 4;
147 : } else {
148 1 : data[0] = BgpExtendedCommunityType::Experimental4ByteAs;
149 1 : put_value(&data[2], 4, asn);
150 1 : offset = 6;
151 : }
152 4 : data[1] = BgpExtendedCommunitySubType::SubCluster;
153 4 : put_value(&data[offset], SubCluster::kSize - offset, id);
154 4 : copy(&data[0], &data[SubCluster::kSize], sc.data_.begin());
155 4 : return sc;
156 15 : }
|