Line data Source code
1 : /*
2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3 : */
4 :
5 : #include "bgp/ermvpn/ermvpn_route.h"
6 :
7 : #include <algorithm>
8 : #include <string>
9 : #include <vector>
10 :
11 : #include "base/string_util.h"
12 : #include "bgp/ermvpn/ermvpn_table.h"
13 :
14 : using std::copy;
15 : using std::string;
16 : using std::vector;
17 :
18 : // BgpProtoPrefix format for erm-vpn prefix.
19 : //
20 : // +------------------------------------+
21 : // | RD (8 octets) |
22 : // +------------------------------------+
23 : // | Router-Id (4 octets) |
24 : // +------------------------------------+
25 : // | Multicast Source length (1 octet) |
26 : // +------------------------------------+
27 : // | Multicast Source (4) |
28 : // +------------------------------------+
29 : // | Multicast Group length (1 octet) |
30 : // +------------------------------------+
31 : // | Multicast Group (4) |
32 : // +------------------------------------+
33 :
34 80336 : ErmVpnPrefix::ErmVpnPrefix() : type_(ErmVpnPrefix::Invalid) {
35 80336 : }
36 :
37 2510 : ErmVpnPrefix::ErmVpnPrefix(uint8_t type, const RouteDistinguisher &rd,
38 2510 : const Ip4Address &group, const Ip4Address &source)
39 2510 : : type_(type), rd_(rd), group_(group), source_(source) {
40 2510 : }
41 :
42 2240 : ErmVpnPrefix::ErmVpnPrefix(uint8_t type, const RouteDistinguisher &rd,
43 : const Ip4Address &router_id,
44 2240 : const Ip4Address &group, const Ip4Address &source)
45 2240 : : type_(type), rd_(rd), router_id_(router_id),
46 2240 : group_(group), source_(source) {
47 2240 : }
48 :
49 4774 : int ErmVpnPrefix::FromProtoPrefix(const BgpProtoPrefix &proto_prefix,
50 : ErmVpnPrefix *prefix) {
51 4774 : size_t rd_size = RouteDistinguisher::kSize;
52 4774 : size_t rtid_size = Address::kMaxV4Bytes;
53 4774 : size_t nlri_size = proto_prefix.prefix.size();
54 4774 : size_t expected_nlri_size =
55 4774 : rd_size + rtid_size + 2 * (Address::kMaxV4Bytes + 1);
56 :
57 4774 : if (!IsValidForBgp(proto_prefix.type))
58 3 : return -1;
59 4771 : if (nlri_size != expected_nlri_size)
60 3 : return -1;
61 :
62 4768 : prefix->type_ = proto_prefix.type;
63 4768 : size_t rd_offset = 0;
64 4768 : prefix->rd_ = RouteDistinguisher(&proto_prefix.prefix[rd_offset]);
65 4768 : size_t rtid_offset = rd_offset + rd_size;
66 : prefix->router_id_ =
67 4768 : Ip4Address(get_value(&proto_prefix.prefix[rtid_offset], rtid_size));
68 :
69 4768 : size_t source_offset = rtid_offset + rtid_size + 1;
70 4768 : if (proto_prefix.prefix[source_offset - 1] != Address::kMaxV4PrefixLen)
71 4 : return -1;
72 4764 : prefix->source_ = Ip4Address(
73 9528 : get_value(&proto_prefix.prefix[source_offset], Address::kMaxV4Bytes));
74 :
75 4764 : size_t group_offset = source_offset + Address::kMaxV4Bytes + 1;
76 4764 : if (proto_prefix.prefix[group_offset - 1] != Address::kMaxV4PrefixLen)
77 4 : return -1;
78 4760 : prefix->group_ = Ip4Address(
79 9520 : get_value(&proto_prefix.prefix[group_offset], Address::kMaxV4Bytes));
80 :
81 4760 : return 0;
82 : }
83 :
84 4758 : int ErmVpnPrefix::FromProtoPrefix(BgpServer *server,
85 : const BgpProtoPrefix &proto_prefix,
86 : const BgpAttr *attr,
87 : const Address::Family family,
88 : ErmVpnPrefix *prefix,
89 : BgpAttrPtr *new_attr, uint32_t *label,
90 : uint32_t *l3_label) {
91 4758 : return FromProtoPrefix(proto_prefix, prefix);
92 : }
93 :
94 4199 : void ErmVpnPrefix::BuildProtoPrefix(BgpProtoPrefix *proto_prefix) const {
95 4199 : assert(IsValidForBgp(type_));
96 :
97 4199 : size_t rd_size = RouteDistinguisher::kSize;
98 4199 : size_t rtid_size = Address::kMaxV4Bytes;
99 :
100 4199 : proto_prefix->type = type_;
101 4199 : proto_prefix->prefix.clear();
102 4199 : proto_prefix->prefixlen =
103 4199 : (rd_size + rtid_size + 2 * (1 + Address::kMaxV4Bytes)) * 8;
104 4199 : proto_prefix->prefix.resize(proto_prefix->prefixlen / 8, 0);
105 :
106 4199 : size_t rd_offset = 0;
107 4199 : copy(rd_.GetData(), rd_.GetData() + rd_size,
108 4199 : proto_prefix->prefix.begin() + rd_offset);
109 :
110 4199 : size_t rtid_offset = rd_offset + rd_size;
111 4199 : const Ip4Address::bytes_type &rtid_bytes = router_id_.to_bytes();
112 4199 : copy(rtid_bytes.begin(), rtid_bytes.begin() + Address::kMaxV4Bytes,
113 4199 : proto_prefix->prefix.begin() + rtid_offset);
114 :
115 4199 : size_t source_offset = rtid_offset + rtid_size + 1;
116 4199 : proto_prefix->prefix[source_offset - 1] = Address::kMaxV4PrefixLen;
117 4199 : const Ip4Address::bytes_type &source_bytes = source_.to_bytes();
118 4199 : copy(source_bytes.begin(), source_bytes.begin() + Address::kMaxV4Bytes,
119 4199 : proto_prefix->prefix.begin() + source_offset);
120 :
121 4199 : size_t group_offset = source_offset + Address::kMaxV4Bytes + 1;
122 4199 : proto_prefix->prefix[group_offset - 1] = Address::kMaxV4PrefixLen;
123 4199 : const Ip4Address::bytes_type &group_bytes = group_.to_bytes();
124 4199 : copy(group_bytes.begin(), group_bytes.begin() + Address::kMaxV4Bytes,
125 4199 : proto_prefix->prefix.begin() + group_offset);
126 4199 : }
127 :
128 37783 : ErmVpnPrefix ErmVpnPrefix::FromString(const string &str,
129 : boost::system::error_code *errorp) {
130 37783 : ErmVpnPrefix prefix, null_prefix;
131 37783 : string temp_str;
132 :
133 : // Look for Type.
134 37783 : size_t pos1 = str.find('-');
135 37783 : if (pos1 == string::npos) {
136 1 : if (errorp != NULL) {
137 1 : *errorp = make_error_code(boost::system::errc::invalid_argument);
138 : }
139 1 : return null_prefix;
140 : }
141 37782 : temp_str = str.substr(0, pos1);
142 37782 : stringToInteger(temp_str, prefix.type_);
143 37782 : if (!IsValid(prefix.type_)) {
144 1 : if (errorp != NULL) {
145 1 : *errorp = make_error_code(boost::system::errc::invalid_argument);
146 : }
147 1 : return null_prefix;
148 : }
149 :
150 : // Look for RD.
151 37781 : size_t pos2 = str.find('-', pos1 + 1);
152 37781 : if (pos2 == string::npos) {
153 1 : if (errorp != NULL) {
154 1 : *errorp = make_error_code(boost::system::errc::invalid_argument);
155 : }
156 1 : return null_prefix;
157 : }
158 37780 : temp_str = str.substr(pos1 + 1, pos2 - pos1 - 1);
159 37780 : boost::system::error_code rd_err;
160 37780 : prefix.rd_ = RouteDistinguisher::FromString(temp_str, &rd_err);
161 37780 : if (rd_err.failed()) {
162 1 : if (errorp != NULL) {
163 1 : *errorp = rd_err;
164 : }
165 1 : return null_prefix;
166 : }
167 :
168 : // Look for router-id.
169 37779 : size_t pos3 = str.find(',', pos2 + 1);
170 37779 : if (pos3 == string::npos) {
171 1 : if (errorp != NULL) {
172 1 : *errorp = make_error_code(boost::system::errc::invalid_argument);
173 : }
174 1 : return null_prefix;
175 : }
176 37778 : temp_str = str.substr(pos2 + 1, pos3 - pos2 - 1);
177 37778 : boost::system::error_code rtid_err;
178 37778 : prefix.router_id_ = Ip4Address::from_string(temp_str, rtid_err);
179 37778 : if (rtid_err.failed()) {
180 1 : if (errorp != NULL) {
181 1 : *errorp = rtid_err;
182 : }
183 1 : return null_prefix;
184 : }
185 :
186 : // Look for group.
187 37777 : size_t pos4 = str.find(',', pos3 + 1);
188 37777 : if (pos4 == string::npos) {
189 1 : if (errorp != NULL) {
190 1 : *errorp = make_error_code(boost::system::errc::invalid_argument);
191 : }
192 1 : return null_prefix;
193 : }
194 37776 : temp_str = str.substr(pos3 + 1, pos4 - pos3 - 1);
195 37776 : boost::system::error_code group_err;
196 37776 : prefix.group_ = Ip4Address::from_string(temp_str, group_err);
197 37776 : if (group_err.failed()) {
198 1 : if (errorp != NULL) {
199 1 : *errorp = group_err;
200 : }
201 1 : return null_prefix;
202 : }
203 :
204 : // Rest is source.
205 37775 : temp_str = str.substr(pos4 + 1, string::npos);
206 37775 : boost::system::error_code source_err;
207 37775 : prefix.source_ = Ip4Address::from_string(temp_str, source_err);
208 37775 : if (source_err.failed()) {
209 1 : if (errorp != NULL) {
210 1 : *errorp = source_err;
211 : }
212 1 : return null_prefix;
213 : }
214 :
215 37774 : return prefix;
216 37783 : }
217 :
218 46028 : string ErmVpnPrefix::ToString() const {
219 46028 : string repr = integerToString(type_);
220 46028 : repr += "-" + rd_.ToString();
221 46028 : repr += "-" + router_id_.to_string();
222 46028 : repr += "," + group_.to_string();
223 46028 : repr += "," + source_.to_string();
224 46028 : return repr;
225 0 : }
226 :
227 583 : string ErmVpnPrefix::ToXmppIdString() const {
228 583 : assert(type_ == 0);
229 583 : string repr = rd_.ToString();
230 583 : repr += ":" + group_.to_string();
231 583 : repr += "," + source_.to_string();
232 583 : return repr;
233 0 : }
234 :
235 46109 : bool ErmVpnPrefix::IsValidForBgp(uint8_t type) {
236 46109 : return (type == LocalTreeRoute || type == GlobalTreeRoute);
237 : }
238 :
239 37788 : bool ErmVpnPrefix::IsValid(uint8_t type) {
240 37788 : return (type == NativeRoute || IsValidForBgp(type));
241 : }
242 :
243 14 : bool ErmVpnPrefix::operator==(const ErmVpnPrefix &rhs) const {
244 : return (
245 28 : type_ == rhs.type_ &&
246 28 : rd_ == rhs.rd_ &&
247 28 : router_id_ == rhs.router_id_ &&
248 42 : group_ == rhs.group_ &&
249 28 : source_ == rhs.source_);
250 : }
251 :
252 68881 : ErmVpnRoute::ErmVpnRoute(const ErmVpnPrefix &prefix) : prefix_(prefix) {
253 68867 : }
254 :
255 244265 : int ErmVpnRoute::CompareTo(const Route &rhs) const {
256 244265 : const ErmVpnRoute &other = static_cast<const ErmVpnRoute &>(rhs);
257 244265 : KEY_COMPARE(prefix_.source(), other.prefix_.source());
258 242454 : KEY_COMPARE(prefix_.group(), other.prefix_.group());
259 136071 : KEY_COMPARE(prefix_.type(), other.prefix_.type());
260 107094 : KEY_COMPARE(
261 : prefix_.route_distinguisher(), other.prefix_.route_distinguisher());
262 80024 : KEY_COMPARE(prefix_.router_id(), other.prefix_.router_id());
263 65805 : return 0;
264 : }
265 :
266 46016 : string ErmVpnRoute::ToString() const {
267 46016 : return prefix_.ToString();
268 : }
269 :
270 2895 : string ErmVpnRoute::ToXmppIdString() const {
271 2895 : if (xmpp_id_str_.empty())
272 581 : xmpp_id_str_ = prefix_.ToXmppIdString();
273 2895 : return xmpp_id_str_;
274 : }
275 :
276 21932 : bool ErmVpnRoute::IsValid() const {
277 21932 : if (!BgpRoute::IsValid())
278 5164 : return false;
279 :
280 16768 : const BgpAttr *attr = BestPath()->GetAttr();
281 16768 : switch (prefix_.type()) {
282 5266 : case ErmVpnPrefix::NativeRoute:
283 5266 : return attr->label_block().get() != NULL;
284 5132 : case ErmVpnPrefix::LocalTreeRoute:
285 5132 : return attr->edge_discovery() != NULL;
286 6370 : case ErmVpnPrefix::GlobalTreeRoute:
287 6370 : return attr->edge_forwarding() != NULL;
288 0 : case ErmVpnPrefix::Invalid:
289 0 : break;
290 : }
291 :
292 0 : return false;
293 : }
294 :
295 3 : void ErmVpnRoute::SetKey(const DBRequestKey *reqkey) {
296 3 : const ErmVpnTable::RequestKey *key =
297 : static_cast<const ErmVpnTable::RequestKey *>(reqkey);
298 3 : prefix_ = key->prefix;
299 3 : }
300 :
301 4199 : void ErmVpnRoute::BuildProtoPrefix(BgpProtoPrefix *prefix,
302 : const BgpAttr *attr, uint32_t label, uint32_t l3_label) const {
303 4199 : prefix_.BuildProtoPrefix(prefix);
304 4199 : }
305 :
306 2839 : void ErmVpnRoute::BuildBgpProtoNextHop(
307 : vector<uint8_t> &nh, IpAddress nexthop) const {
308 2839 : nh.resize(4);
309 2839 : const Ip4Address::bytes_type &addr_bytes = nexthop.to_v4().to_bytes();
310 2839 : copy(addr_bytes.begin(), addr_bytes.end(), nh.begin());
311 2839 : }
312 :
313 826 : DBEntryBase::KeyPtr ErmVpnRoute::GetDBRequestKey() const {
314 : ErmVpnTable::RequestKey *key;
315 826 : key = new ErmVpnTable::RequestKey(GetPrefix(), NULL);
316 826 : return KeyPtr(key);
317 : }
318 :
319 9110 : const std::string ErmVpnPrefix::GetType() const {
320 9110 : switch (type_) {
321 392 : case NativeRoute:
322 392 : return "NativeRoute";
323 0 : case LocalTreeRoute:
324 0 : return "LocalTreeRoute";
325 8718 : case GlobalTreeRoute:
326 8718 : return "GlobalTreeRoute";
327 0 : case Invalid:
328 0 : return "Invalid";
329 : }
330 0 : return "";
331 : }
332 :
333 9110 : const std::string ErmVpnRoute::GetType() const {
334 9110 : return GetPrefix().GetType();
335 : }
|