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 82347 : ErmVpnPrefix::ErmVpnPrefix() : type_(ErmVpnPrefix::Invalid) {
35 82347 : }
36 :
37 2514 : ErmVpnPrefix::ErmVpnPrefix(uint8_t type, const RouteDistinguisher &rd,
38 2514 : const Ip4Address &group, const Ip4Address &source)
39 2514 : : type_(type), rd_(rd), group_(group), source_(source) {
40 2514 : }
41 :
42 2272 : ErmVpnPrefix::ErmVpnPrefix(uint8_t type, const RouteDistinguisher &rd,
43 : const Ip4Address &router_id,
44 2272 : const Ip4Address &group, const Ip4Address &source)
45 2272 : : type_(type), rd_(rd), router_id_(router_id),
46 2272 : group_(group), source_(source) {
47 2272 : }
48 :
49 4725 : int ErmVpnPrefix::FromProtoPrefix(const BgpProtoPrefix &proto_prefix,
50 : ErmVpnPrefix *prefix) {
51 4725 : size_t rd_size = RouteDistinguisher::kSize;
52 4725 : size_t rtid_size = Address::kMaxV4Bytes;
53 4725 : size_t nlri_size = proto_prefix.prefix.size();
54 4725 : size_t expected_nlri_size =
55 4725 : rd_size + rtid_size + 2 * (Address::kMaxV4Bytes + 1);
56 :
57 4725 : if (!IsValidForBgp(proto_prefix.type))
58 3 : return -1;
59 4722 : if (nlri_size != expected_nlri_size)
60 3 : return -1;
61 :
62 4719 : prefix->type_ = proto_prefix.type;
63 4719 : size_t rd_offset = 0;
64 4719 : prefix->rd_ = RouteDistinguisher(&proto_prefix.prefix[rd_offset]);
65 4719 : size_t rtid_offset = rd_offset + rd_size;
66 : prefix->router_id_ =
67 4719 : Ip4Address(get_value(&proto_prefix.prefix[rtid_offset], rtid_size));
68 :
69 4719 : size_t source_offset = rtid_offset + rtid_size + 1;
70 4719 : if (proto_prefix.prefix[source_offset - 1] != Address::kMaxV4PrefixLen)
71 4 : return -1;
72 4715 : prefix->source_ = Ip4Address(
73 9430 : get_value(&proto_prefix.prefix[source_offset], Address::kMaxV4Bytes));
74 :
75 4715 : size_t group_offset = source_offset + Address::kMaxV4Bytes + 1;
76 4715 : if (proto_prefix.prefix[group_offset - 1] != Address::kMaxV4PrefixLen)
77 4 : return -1;
78 4711 : prefix->group_ = Ip4Address(
79 9422 : get_value(&proto_prefix.prefix[group_offset], Address::kMaxV4Bytes));
80 :
81 4711 : return 0;
82 : }
83 :
84 4709 : 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 4709 : return FromProtoPrefix(proto_prefix, prefix);
92 : }
93 :
94 4129 : void ErmVpnPrefix::BuildProtoPrefix(BgpProtoPrefix *proto_prefix) const {
95 4129 : assert(IsValidForBgp(type_));
96 :
97 4129 : size_t rd_size = RouteDistinguisher::kSize;
98 4129 : size_t rtid_size = Address::kMaxV4Bytes;
99 :
100 4129 : proto_prefix->type = type_;
101 4129 : proto_prefix->prefix.clear();
102 4129 : proto_prefix->prefixlen =
103 4129 : (rd_size + rtid_size + 2 * (1 + Address::kMaxV4Bytes)) * 8;
104 4129 : proto_prefix->prefix.resize(proto_prefix->prefixlen / 8, 0);
105 :
106 4129 : size_t rd_offset = 0;
107 4129 : copy(rd_.GetData(), rd_.GetData() + rd_size,
108 4129 : proto_prefix->prefix.begin() + rd_offset);
109 :
110 4129 : size_t rtid_offset = rd_offset + rd_size;
111 4129 : const Ip4Address::bytes_type &rtid_bytes = router_id_.to_bytes();
112 4129 : copy(rtid_bytes.begin(), rtid_bytes.begin() + Address::kMaxV4Bytes,
113 4129 : proto_prefix->prefix.begin() + rtid_offset);
114 :
115 4129 : size_t source_offset = rtid_offset + rtid_size + 1;
116 4129 : proto_prefix->prefix[source_offset - 1] = Address::kMaxV4PrefixLen;
117 4129 : const Ip4Address::bytes_type &source_bytes = source_.to_bytes();
118 4129 : copy(source_bytes.begin(), source_bytes.begin() + Address::kMaxV4Bytes,
119 4129 : proto_prefix->prefix.begin() + source_offset);
120 :
121 4129 : size_t group_offset = source_offset + Address::kMaxV4Bytes + 1;
122 4129 : proto_prefix->prefix[group_offset - 1] = Address::kMaxV4PrefixLen;
123 4129 : const Ip4Address::bytes_type &group_bytes = group_.to_bytes();
124 4129 : copy(group_bytes.begin(), group_bytes.begin() + Address::kMaxV4Bytes,
125 4129 : proto_prefix->prefix.begin() + group_offset);
126 4129 : }
127 :
128 38813 : ErmVpnPrefix ErmVpnPrefix::FromString(const string &str,
129 : boost::system::error_code *errorp) {
130 38813 : ErmVpnPrefix prefix, null_prefix;
131 38813 : string temp_str;
132 :
133 : // Look for Type.
134 38813 : size_t pos1 = str.find('-');
135 38813 : 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 38812 : temp_str = str.substr(0, pos1);
142 38812 : stringToInteger(temp_str, prefix.type_);
143 38812 : 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 38811 : size_t pos2 = str.find('-', pos1 + 1);
152 38811 : 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 38810 : temp_str = str.substr(pos1 + 1, pos2 - pos1 - 1);
159 38810 : boost::system::error_code rd_err;
160 38810 : prefix.rd_ = RouteDistinguisher::FromString(temp_str, &rd_err);
161 38810 : 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 38809 : size_t pos3 = str.find(',', pos2 + 1);
170 38809 : 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 38808 : temp_str = str.substr(pos2 + 1, pos3 - pos2 - 1);
177 38808 : boost::system::error_code rtid_err;
178 38808 : prefix.router_id_ = Ip4Address::from_string(temp_str, rtid_err);
179 38808 : 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 38807 : size_t pos4 = str.find(',', pos3 + 1);
188 38807 : 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 38806 : temp_str = str.substr(pos3 + 1, pos4 - pos3 - 1);
195 38806 : boost::system::error_code group_err;
196 38806 : prefix.group_ = Ip4Address::from_string(temp_str, group_err);
197 38806 : 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 38805 : temp_str = str.substr(pos4 + 1, string::npos);
206 38805 : boost::system::error_code source_err;
207 38805 : prefix.source_ = Ip4Address::from_string(temp_str, source_err);
208 38805 : if (source_err.failed()) {
209 1 : if (errorp != NULL) {
210 1 : *errorp = source_err;
211 : }
212 1 : return null_prefix;
213 : }
214 :
215 38804 : return prefix;
216 38813 : }
217 :
218 46130 : string ErmVpnPrefix::ToString() const {
219 46130 : string repr = integerToString(type_);
220 46130 : repr += "-" + rd_.ToString();
221 46130 : repr += "-" + router_id_.to_string();
222 46130 : repr += "," + group_.to_string();
223 46130 : repr += "," + source_.to_string();
224 46130 : 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 47020 : bool ErmVpnPrefix::IsValidForBgp(uint8_t type) {
236 47020 : return (type == LocalTreeRoute || type == GlobalTreeRoute);
237 : }
238 :
239 38818 : bool ErmVpnPrefix::IsValid(uint8_t type) {
240 38818 : 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 69790 : ErmVpnRoute::ErmVpnRoute(const ErmVpnPrefix &prefix) : prefix_(prefix) {
253 69787 : }
254 :
255 245929 : int ErmVpnRoute::CompareTo(const Route &rhs) const {
256 245929 : const ErmVpnRoute &other = static_cast<const ErmVpnRoute &>(rhs);
257 245929 : KEY_COMPARE(prefix_.source(), other.prefix_.source());
258 243992 : KEY_COMPARE(prefix_.group(), other.prefix_.group());
259 136237 : KEY_COMPARE(prefix_.type(), other.prefix_.type());
260 106853 : KEY_COMPARE(
261 : prefix_.route_distinguisher(), other.prefix_.route_distinguisher());
262 79600 : KEY_COMPARE(prefix_.router_id(), other.prefix_.router_id());
263 65582 : return 0;
264 : }
265 :
266 46118 : string ErmVpnRoute::ToString() const {
267 46118 : return prefix_.ToString();
268 : }
269 :
270 2862 : string ErmVpnRoute::ToXmppIdString() const {
271 2862 : if (xmpp_id_str_.empty())
272 581 : xmpp_id_str_ = prefix_.ToXmppIdString();
273 2862 : return xmpp_id_str_;
274 : }
275 :
276 22255 : bool ErmVpnRoute::IsValid() const {
277 22255 : if (!BgpRoute::IsValid())
278 5161 : return false;
279 :
280 17094 : const BgpAttr *attr = BestPath()->GetAttr();
281 17094 : switch (prefix_.type()) {
282 5584 : case ErmVpnPrefix::NativeRoute:
283 5584 : return attr->label_block().get() != NULL;
284 5165 : case ErmVpnPrefix::LocalTreeRoute:
285 5165 : return attr->edge_discovery() != NULL;
286 6345 : case ErmVpnPrefix::GlobalTreeRoute:
287 6345 : 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 4129 : void ErmVpnRoute::BuildProtoPrefix(BgpProtoPrefix *prefix,
302 : const BgpAttr *attr, uint32_t label, uint32_t l3_label) const {
303 4129 : prefix_.BuildProtoPrefix(prefix);
304 4129 : }
305 :
306 2763 : void ErmVpnRoute::BuildBgpProtoNextHop(
307 : vector<uint8_t> &nh, IpAddress nexthop) const {
308 2763 : nh.resize(4);
309 2763 : const Ip4Address::bytes_type &addr_bytes = nexthop.to_v4().to_bytes();
310 2763 : copy(addr_bytes.begin(), addr_bytes.end(), nh.begin());
311 2763 : }
312 :
313 729 : DBEntryBase::KeyPtr ErmVpnRoute::GetDBRequestKey() const {
314 : ErmVpnTable::RequestKey *key;
315 729 : key = new ErmVpnTable::RequestKey(GetPrefix(), NULL);
316 729 : return KeyPtr(key);
317 : }
318 :
319 9090 : const std::string ErmVpnPrefix::GetType() const {
320 9090 : switch (type_) {
321 374 : case NativeRoute:
322 374 : return "NativeRoute";
323 0 : case LocalTreeRoute:
324 0 : return "LocalTreeRoute";
325 8716 : case GlobalTreeRoute:
326 8716 : return "GlobalTreeRoute";
327 0 : case Invalid:
328 0 : return "Invalid";
329 : }
330 0 : return "";
331 : }
332 :
333 9090 : const std::string ErmVpnRoute::GetType() const {
334 9090 : return GetPrefix().GetType();
335 : }
|