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