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 84071 : ErmVpnPrefix::ErmVpnPrefix() : type_(ErmVpnPrefix::Invalid) {
35 84071 : }
36 :
37 2519 : ErmVpnPrefix::ErmVpnPrefix(uint8_t type, const RouteDistinguisher &rd,
38 2519 : const Ip4Address &group, const Ip4Address &source)
39 2519 : : type_(type), rd_(rd), group_(group), source_(source) {
40 2519 : }
41 :
42 2147 : ErmVpnPrefix::ErmVpnPrefix(uint8_t type, const RouteDistinguisher &rd,
43 : const Ip4Address &router_id,
44 2147 : const Ip4Address &group, const Ip4Address &source)
45 2147 : : type_(type), rd_(rd), router_id_(router_id),
46 2147 : group_(group), source_(source) {
47 2147 : }
48 :
49 4707 : int ErmVpnPrefix::FromProtoPrefix(const BgpProtoPrefix &proto_prefix,
50 : ErmVpnPrefix *prefix) {
51 4707 : size_t rd_size = RouteDistinguisher::kSize;
52 4707 : size_t rtid_size = Address::kMaxV4Bytes;
53 4707 : size_t nlri_size = proto_prefix.prefix.size();
54 4707 : size_t expected_nlri_size =
55 4707 : rd_size + rtid_size + 2 * (Address::kMaxV4Bytes + 1);
56 :
57 4707 : if (!IsValidForBgp(proto_prefix.type))
58 3 : return -1;
59 4704 : if (nlri_size != expected_nlri_size)
60 3 : return -1;
61 :
62 4701 : prefix->type_ = proto_prefix.type;
63 4701 : size_t rd_offset = 0;
64 4701 : prefix->rd_ = RouteDistinguisher(&proto_prefix.prefix[rd_offset]);
65 4701 : size_t rtid_offset = rd_offset + rd_size;
66 : prefix->router_id_ =
67 4701 : Ip4Address(get_value(&proto_prefix.prefix[rtid_offset], rtid_size));
68 :
69 4701 : size_t source_offset = rtid_offset + rtid_size + 1;
70 4701 : if (proto_prefix.prefix[source_offset - 1] != Address::kMaxV4PrefixLen)
71 4 : return -1;
72 4697 : prefix->source_ = Ip4Address(
73 9394 : get_value(&proto_prefix.prefix[source_offset], Address::kMaxV4Bytes));
74 :
75 4697 : size_t group_offset = source_offset + Address::kMaxV4Bytes + 1;
76 4697 : if (proto_prefix.prefix[group_offset - 1] != Address::kMaxV4PrefixLen)
77 4 : return -1;
78 4693 : prefix->group_ = Ip4Address(
79 9386 : get_value(&proto_prefix.prefix[group_offset], Address::kMaxV4Bytes));
80 :
81 4693 : return 0;
82 : }
83 :
84 4691 : 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 4691 : return FromProtoPrefix(proto_prefix, prefix);
92 : }
93 :
94 4123 : void ErmVpnPrefix::BuildProtoPrefix(BgpProtoPrefix *proto_prefix) const {
95 4123 : assert(IsValidForBgp(type_));
96 :
97 4123 : size_t rd_size = RouteDistinguisher::kSize;
98 4123 : size_t rtid_size = Address::kMaxV4Bytes;
99 :
100 4123 : proto_prefix->type = type_;
101 4123 : proto_prefix->prefix.clear();
102 4123 : proto_prefix->prefixlen =
103 4123 : (rd_size + rtid_size + 2 * (1 + Address::kMaxV4Bytes)) * 8;
104 4123 : proto_prefix->prefix.resize(proto_prefix->prefixlen / 8, 0);
105 :
106 4123 : size_t rd_offset = 0;
107 4123 : copy(rd_.GetData(), rd_.GetData() + rd_size,
108 4123 : proto_prefix->prefix.begin() + rd_offset);
109 :
110 4123 : size_t rtid_offset = rd_offset + rd_size;
111 4123 : const Ip4Address::bytes_type &rtid_bytes = router_id_.to_bytes();
112 4123 : copy(rtid_bytes.begin(), rtid_bytes.begin() + Address::kMaxV4Bytes,
113 4123 : proto_prefix->prefix.begin() + rtid_offset);
114 :
115 4123 : size_t source_offset = rtid_offset + rtid_size + 1;
116 4123 : proto_prefix->prefix[source_offset - 1] = Address::kMaxV4PrefixLen;
117 4123 : const Ip4Address::bytes_type &source_bytes = source_.to_bytes();
118 4123 : copy(source_bytes.begin(), source_bytes.begin() + Address::kMaxV4Bytes,
119 4123 : proto_prefix->prefix.begin() + source_offset);
120 :
121 4123 : size_t group_offset = source_offset + Address::kMaxV4Bytes + 1;
122 4123 : proto_prefix->prefix[group_offset - 1] = Address::kMaxV4PrefixLen;
123 4123 : const Ip4Address::bytes_type &group_bytes = group_.to_bytes();
124 4123 : copy(group_bytes.begin(), group_bytes.begin() + Address::kMaxV4Bytes,
125 4123 : proto_prefix->prefix.begin() + group_offset);
126 4123 : }
127 :
128 39684 : ErmVpnPrefix ErmVpnPrefix::FromString(const string &str,
129 : boost::system::error_code *errorp) {
130 39684 : ErmVpnPrefix prefix, null_prefix;
131 39684 : string temp_str;
132 :
133 : // Look for Type.
134 39684 : size_t pos1 = str.find('-');
135 39684 : 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 39683 : temp_str = str.substr(0, pos1);
142 39683 : stringToInteger(temp_str, prefix.type_);
143 39683 : 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 39682 : size_t pos2 = str.find('-', pos1 + 1);
152 39682 : 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 39681 : temp_str = str.substr(pos1 + 1, pos2 - pos1 - 1);
159 39681 : boost::system::error_code rd_err;
160 39681 : prefix.rd_ = RouteDistinguisher::FromString(temp_str, &rd_err);
161 39681 : 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 39680 : size_t pos3 = str.find(',', pos2 + 1);
170 39680 : 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 39679 : temp_str = str.substr(pos2 + 1, pos3 - pos2 - 1);
177 39679 : boost::system::error_code rtid_err;
178 39679 : prefix.router_id_ = Ip4Address::from_string(temp_str, rtid_err);
179 39679 : 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 39678 : size_t pos4 = str.find(',', pos3 + 1);
188 39678 : 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 39677 : temp_str = str.substr(pos3 + 1, pos4 - pos3 - 1);
195 39677 : boost::system::error_code group_err;
196 39677 : prefix.group_ = Ip4Address::from_string(temp_str, group_err);
197 39677 : 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 39676 : temp_str = str.substr(pos4 + 1, string::npos);
206 39676 : boost::system::error_code source_err;
207 39676 : prefix.source_ = Ip4Address::from_string(temp_str, source_err);
208 39676 : if (source_err.failed()) {
209 1 : if (errorp != NULL) {
210 1 : *errorp = source_err;
211 : }
212 1 : return null_prefix;
213 : }
214 :
215 39675 : return prefix;
216 39684 : }
217 :
218 46024 : string ErmVpnPrefix::ToString() const {
219 46024 : string repr = integerToString(type_);
220 46024 : repr += "-" + rd_.ToString();
221 46024 : repr += "-" + router_id_.to_string();
222 46024 : repr += "," + group_.to_string();
223 46024 : repr += "," + source_.to_string();
224 46024 : return repr;
225 0 : }
226 :
227 585 : string ErmVpnPrefix::ToXmppIdString() const {
228 585 : assert(type_ == 0);
229 585 : string repr = rd_.ToString();
230 585 : repr += ":" + group_.to_string();
231 585 : repr += "," + source_.to_string();
232 585 : return repr;
233 0 : }
234 :
235 47867 : bool ErmVpnPrefix::IsValidForBgp(uint8_t type) {
236 47867 : return (type == LocalTreeRoute || type == GlobalTreeRoute);
237 : }
238 :
239 39689 : bool ErmVpnPrefix::IsValid(uint8_t type) {
240 39689 : 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 70380 : ErmVpnRoute::ErmVpnRoute(const ErmVpnPrefix &prefix) : prefix_(prefix) {
253 70335 : }
254 :
255 243328 : int ErmVpnRoute::CompareTo(const Route &rhs) const {
256 243328 : const ErmVpnRoute &other = static_cast<const ErmVpnRoute &>(rhs);
257 243328 : KEY_COMPARE(prefix_.source(), other.prefix_.source());
258 241407 : KEY_COMPARE(prefix_.group(), other.prefix_.group());
259 133914 : KEY_COMPARE(prefix_.type(), other.prefix_.type());
260 105484 : KEY_COMPARE(
261 : prefix_.route_distinguisher(), other.prefix_.route_distinguisher());
262 79135 : KEY_COMPARE(prefix_.router_id(), other.prefix_.router_id());
263 65205 : return 0;
264 : }
265 :
266 46012 : string ErmVpnRoute::ToString() const {
267 46012 : return prefix_.ToString();
268 : }
269 :
270 2801 : string ErmVpnRoute::ToXmppIdString() const {
271 2801 : if (xmpp_id_str_.empty())
272 583 : xmpp_id_str_ = prefix_.ToXmppIdString();
273 2801 : return xmpp_id_str_;
274 : }
275 :
276 21403 : bool ErmVpnRoute::IsValid() const {
277 21403 : if (!BgpRoute::IsValid())
278 5133 : return false;
279 :
280 16270 : const BgpAttr *attr = BestPath()->GetAttr();
281 16270 : switch (prefix_.type()) {
282 4951 : case ErmVpnPrefix::NativeRoute:
283 4951 : return attr->label_block().get() != NULL;
284 5089 : case ErmVpnPrefix::LocalTreeRoute:
285 5089 : return attr->edge_discovery() != NULL;
286 6230 : case ErmVpnPrefix::GlobalTreeRoute:
287 6230 : 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 4123 : void ErmVpnRoute::BuildProtoPrefix(BgpProtoPrefix *prefix,
302 : const BgpAttr *attr, uint32_t label, uint32_t l3_label) const {
303 4123 : prefix_.BuildProtoPrefix(prefix);
304 4123 : }
305 :
306 2786 : void ErmVpnRoute::BuildBgpProtoNextHop(
307 : vector<uint8_t> &nh, IpAddress nexthop) const {
308 2786 : nh.resize(4);
309 2786 : const Ip4Address::bytes_type &addr_bytes = nexthop.to_v4().to_bytes();
310 2786 : copy(addr_bytes.begin(), addr_bytes.end(), nh.begin());
311 2786 : }
312 :
313 765 : DBEntryBase::KeyPtr ErmVpnRoute::GetDBRequestKey() const {
314 : ErmVpnTable::RequestKey *key;
315 765 : key = new ErmVpnTable::RequestKey(GetPrefix(), NULL);
316 765 : return KeyPtr(key);
317 : }
318 :
319 9066 : const std::string ErmVpnPrefix::GetType() const {
320 9066 : switch (type_) {
321 364 : case NativeRoute:
322 364 : return "NativeRoute";
323 0 : case LocalTreeRoute:
324 0 : return "LocalTreeRoute";
325 8702 : case GlobalTreeRoute:
326 8702 : return "GlobalTreeRoute";
327 0 : case Invalid:
328 0 : return "Invalid";
329 : }
330 0 : return "";
331 : }
332 :
333 9066 : const std::string ErmVpnRoute::GetType() const {
334 9066 : return GetPrefix().GetType();
335 : }
|