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 79919 : ErmVpnPrefix::ErmVpnPrefix() : type_(ErmVpnPrefix::Invalid) {
35 79919 : }
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 2509 : }
41 :
42 2264 : ErmVpnPrefix::ErmVpnPrefix(uint8_t type, const RouteDistinguisher &rd,
43 : const Ip4Address &router_id,
44 2264 : const Ip4Address &group, const Ip4Address &source)
45 2264 : : type_(type), rd_(rd), router_id_(router_id),
46 2264 : group_(group), source_(source) {
47 2264 : }
48 :
49 4917 : int ErmVpnPrefix::FromProtoPrefix(const BgpProtoPrefix &proto_prefix,
50 : ErmVpnPrefix *prefix) {
51 4917 : size_t rd_size = RouteDistinguisher::kSize;
52 4917 : size_t rtid_size = Address::kMaxV4Bytes;
53 4917 : size_t nlri_size = proto_prefix.prefix.size();
54 4917 : size_t expected_nlri_size =
55 4917 : rd_size + rtid_size + 2 * (Address::kMaxV4Bytes + 1);
56 :
57 4917 : if (!IsValidForBgp(proto_prefix.type))
58 3 : return -1;
59 4914 : if (nlri_size != expected_nlri_size)
60 3 : return -1;
61 :
62 4911 : prefix->type_ = proto_prefix.type;
63 4911 : size_t rd_offset = 0;
64 4911 : prefix->rd_ = RouteDistinguisher(&proto_prefix.prefix[rd_offset]);
65 4911 : size_t rtid_offset = rd_offset + rd_size;
66 : prefix->router_id_ =
67 4911 : Ip4Address(get_value(&proto_prefix.prefix[rtid_offset], rtid_size));
68 :
69 4911 : size_t source_offset = rtid_offset + rtid_size + 1;
70 4911 : if (proto_prefix.prefix[source_offset - 1] != Address::kMaxV4PrefixLen)
71 4 : return -1;
72 4907 : prefix->source_ = Ip4Address(
73 9814 : get_value(&proto_prefix.prefix[source_offset], Address::kMaxV4Bytes));
74 :
75 4907 : size_t group_offset = source_offset + Address::kMaxV4Bytes + 1;
76 4907 : if (proto_prefix.prefix[group_offset - 1] != Address::kMaxV4PrefixLen)
77 4 : return -1;
78 4903 : prefix->group_ = Ip4Address(
79 9805 : get_value(&proto_prefix.prefix[group_offset], Address::kMaxV4Bytes));
80 :
81 4902 : return 0;
82 : }
83 :
84 4901 : 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 4901 : return FromProtoPrefix(proto_prefix, prefix);
92 : }
93 :
94 4330 : void ErmVpnPrefix::BuildProtoPrefix(BgpProtoPrefix *proto_prefix) const {
95 4330 : assert(IsValidForBgp(type_));
96 :
97 4330 : size_t rd_size = RouteDistinguisher::kSize;
98 4330 : size_t rtid_size = Address::kMaxV4Bytes;
99 :
100 4330 : proto_prefix->type = type_;
101 4330 : proto_prefix->prefix.clear();
102 4330 : proto_prefix->prefixlen =
103 4330 : (rd_size + rtid_size + 2 * (1 + Address::kMaxV4Bytes)) * 8;
104 4330 : proto_prefix->prefix.resize(proto_prefix->prefixlen / 8, 0);
105 :
106 4330 : size_t rd_offset = 0;
107 4330 : copy(rd_.GetData(), rd_.GetData() + rd_size,
108 4330 : proto_prefix->prefix.begin() + rd_offset);
109 :
110 4330 : size_t rtid_offset = rd_offset + rd_size;
111 4330 : const Ip4Address::bytes_type &rtid_bytes = router_id_.to_bytes();
112 4330 : copy(rtid_bytes.begin(), rtid_bytes.begin() + Address::kMaxV4Bytes,
113 4330 : proto_prefix->prefix.begin() + rtid_offset);
114 :
115 4330 : size_t source_offset = rtid_offset + rtid_size + 1;
116 4330 : proto_prefix->prefix[source_offset - 1] = Address::kMaxV4PrefixLen;
117 4330 : const Ip4Address::bytes_type &source_bytes = source_.to_bytes();
118 4330 : copy(source_bytes.begin(), source_bytes.begin() + Address::kMaxV4Bytes,
119 4330 : proto_prefix->prefix.begin() + source_offset);
120 :
121 4330 : size_t group_offset = source_offset + Address::kMaxV4Bytes + 1;
122 4330 : proto_prefix->prefix[group_offset - 1] = Address::kMaxV4PrefixLen;
123 4330 : const Ip4Address::bytes_type &group_bytes = group_.to_bytes();
124 4330 : copy(group_bytes.begin(), group_bytes.begin() + Address::kMaxV4Bytes,
125 4330 : proto_prefix->prefix.begin() + group_offset);
126 4330 : }
127 :
128 37503 : ErmVpnPrefix ErmVpnPrefix::FromString(const string &str,
129 : boost::system::error_code *errorp) {
130 37503 : ErmVpnPrefix prefix, null_prefix;
131 37503 : string temp_str;
132 :
133 : // Look for Type.
134 37503 : size_t pos1 = str.find('-');
135 37503 : 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 37502 : temp_str = str.substr(0, pos1);
142 37502 : stringToInteger(temp_str, prefix.type_);
143 37502 : 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 37501 : size_t pos2 = str.find('-', pos1 + 1);
152 37501 : 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 37500 : temp_str = str.substr(pos1 + 1, pos2 - pos1 - 1);
159 37500 : boost::system::error_code rd_err;
160 37500 : prefix.rd_ = RouteDistinguisher::FromString(temp_str, &rd_err);
161 37500 : 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 37499 : size_t pos3 = str.find(',', pos2 + 1);
170 37499 : 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 37498 : temp_str = str.substr(pos2 + 1, pos3 - pos2 - 1);
177 37498 : boost::system::error_code rtid_err;
178 37498 : prefix.router_id_ = Ip4Address::from_string(temp_str, rtid_err);
179 37498 : 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 37497 : size_t pos4 = str.find(',', pos3 + 1);
188 37497 : 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 37496 : temp_str = str.substr(pos3 + 1, pos4 - pos3 - 1);
195 37496 : boost::system::error_code group_err;
196 37496 : prefix.group_ = Ip4Address::from_string(temp_str, group_err);
197 37496 : 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 37495 : temp_str = str.substr(pos4 + 1, string::npos);
206 37495 : boost::system::error_code source_err;
207 37495 : prefix.source_ = Ip4Address::from_string(temp_str, source_err);
208 37495 : if (source_err.failed()) {
209 1 : if (errorp != NULL) {
210 1 : *errorp = source_err;
211 : }
212 1 : return null_prefix;
213 : }
214 :
215 37494 : return prefix;
216 37503 : }
217 :
218 46116 : string ErmVpnPrefix::ToString() const {
219 46116 : string repr = integerToString(type_);
220 46116 : repr += "-" + rd_.ToString();
221 46116 : repr += "-" + router_id_.to_string();
222 46116 : repr += "," + group_.to_string();
223 46116 : repr += "," + source_.to_string();
224 46116 : return repr;
225 0 : }
226 :
227 588 : string ErmVpnPrefix::ToXmppIdString() const {
228 588 : assert(type_ == 0);
229 588 : string repr = rd_.ToString();
230 588 : repr += ":" + group_.to_string();
231 588 : repr += "," + source_.to_string();
232 588 : return repr;
233 0 : }
234 :
235 46103 : bool ErmVpnPrefix::IsValidForBgp(uint8_t type) {
236 46103 : return (type == LocalTreeRoute || type == GlobalTreeRoute);
237 : }
238 :
239 37508 : bool ErmVpnPrefix::IsValid(uint8_t type) {
240 37508 : 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 68810 : ErmVpnRoute::ErmVpnRoute(const ErmVpnPrefix &prefix) : prefix_(prefix) {
253 68810 : }
254 :
255 245187 : int ErmVpnRoute::CompareTo(const Route &rhs) const {
256 245187 : const ErmVpnRoute &other = static_cast<const ErmVpnRoute &>(rhs);
257 245187 : KEY_COMPARE(prefix_.source(), other.prefix_.source());
258 243368 : KEY_COMPARE(prefix_.group(), other.prefix_.group());
259 137439 : KEY_COMPARE(prefix_.type(), other.prefix_.type());
260 107972 : KEY_COMPARE(
261 : prefix_.route_distinguisher(), other.prefix_.route_distinguisher());
262 80534 : KEY_COMPARE(prefix_.router_id(), other.prefix_.router_id());
263 66214 : return 0;
264 : }
265 :
266 46104 : string ErmVpnRoute::ToString() const {
267 46104 : return prefix_.ToString();
268 : }
269 :
270 2892 : string ErmVpnRoute::ToXmppIdString() const {
271 2892 : if (xmpp_id_str_.empty())
272 586 : xmpp_id_str_ = prefix_.ToXmppIdString();
273 2892 : return xmpp_id_str_;
274 : }
275 :
276 22253 : bool ErmVpnRoute::IsValid() const {
277 22253 : if (!BgpRoute::IsValid())
278 5150 : return false;
279 :
280 17103 : const BgpAttr *attr = BestPath()->GetAttr();
281 17103 : switch (prefix_.type()) {
282 5508 : case ErmVpnPrefix::NativeRoute:
283 5508 : return attr->label_block().get() != NULL;
284 5209 : case ErmVpnPrefix::LocalTreeRoute:
285 5209 : return attr->edge_discovery() != NULL;
286 6386 : case ErmVpnPrefix::GlobalTreeRoute:
287 6386 : 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 4330 : void ErmVpnRoute::BuildProtoPrefix(BgpProtoPrefix *prefix,
302 : const BgpAttr *attr, uint32_t label, uint32_t l3_label) const {
303 4330 : prefix_.BuildProtoPrefix(prefix);
304 4330 : }
305 :
306 2897 : void ErmVpnRoute::BuildBgpProtoNextHop(
307 : vector<uint8_t> &nh, IpAddress nexthop) const {
308 2897 : nh.resize(4);
309 2897 : const Ip4Address::bytes_type &addr_bytes = nexthop.to_v4().to_bytes();
310 2897 : copy(addr_bytes.begin(), addr_bytes.end(), nh.begin());
311 2897 : }
312 :
313 776 : DBEntryBase::KeyPtr ErmVpnRoute::GetDBRequestKey() const {
314 : ErmVpnTable::RequestKey *key;
315 776 : key = new ErmVpnTable::RequestKey(GetPrefix(), NULL);
316 776 : return KeyPtr(key);
317 : }
318 :
319 9104 : const std::string ErmVpnPrefix::GetType() const {
320 9104 : switch (type_) {
321 386 : case NativeRoute:
322 386 : 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 9104 : const std::string ErmVpnRoute::GetType() const {
334 9104 : return GetPrefix().GetType();
335 : }
|