Line data Source code
1 : /*
2 : * Copyright (c) 2015 Juniper Networks, Inc. All rights reserved.
3 : * Copyright Contributors to the OpenSDN project
4 : */
5 :
6 : #include "bgp/routing-policy/routing_policy_match.h"
7 :
8 : #include <boost/foreach.hpp>
9 : #include <boost/assign/list_of.hpp>
10 :
11 : #include <algorithm>
12 : #include <map>
13 : #include <sstream>
14 : #include <vector>
15 :
16 : #include "bgp/ipeer.h"
17 : #include "bgp/bgp_attr.h"
18 : #include "bgp/bgp_path.h"
19 : #include "bgp/extended-community/default_gateway.h"
20 : #include "bgp/extended-community/es_import.h"
21 : #include "bgp/extended-community/esi_label.h"
22 : #include "bgp/extended-community/etree.h"
23 : #include "bgp/extended-community/load_balance.h"
24 : #include "bgp/extended-community/mac_mobility.h"
25 : #include "bgp/extended-community/router_mac.h"
26 : #include "bgp/extended-community/site_of_origin.h"
27 : #include "bgp/extended-community/source_as.h"
28 : #include "bgp/extended-community/tag.h"
29 : #include "bgp/extended-community/vrf_route_import.h"
30 : #include "bgp/origin-vn/origin_vn.h"
31 : #include "bgp/routing-instance/routepath_replicator.h"
32 : #include "bgp/routing-instance/routing_instance.h"
33 : #include "bgp/rtarget/rtarget_address.h"
34 : #include "bgp/security_group/security_group.h"
35 : #include "bgp/tunnel_encap/tunnel_encap.h"
36 : #include "net/community_type.h"
37 :
38 :
39 : using contrail::regex;
40 : using contrail::regex_match;
41 : using contrail::regex_search;
42 : using std::includes;
43 : using std::map;
44 : using std::ostringstream;
45 : using std::sort;
46 : using std::string;
47 : using std::unique;
48 : using std::vector;
49 : using std::find;
50 :
51 351 : MatchCommunity::MatchCommunity(const vector<string> &communities,
52 351 : bool match_all) : match_all_(match_all) {
53 : // Assume that the each community string that doesn't correspond to a
54 : // community name or value is a regex string.
55 1327 : BOOST_FOREACH(const string &community, communities) {
56 488 : uint32_t value = CommunityType::CommunityFromString(community);
57 488 : if (value) {
58 370 : to_match_.insert(value);
59 : } else {
60 118 : to_match_regex_strings_.push_back(community);
61 : }
62 : }
63 :
64 : // Sort and uniquify the vector of regex strings.
65 351 : sort(to_match_regex_strings_.begin(), to_match_regex_strings_.end());
66 : vector<string>::iterator it =
67 351 : unique(to_match_regex_strings_.begin(), to_match_regex_strings_.end());
68 351 : to_match_regex_strings_.erase(it, to_match_regex_strings_.end());
69 :
70 : // Build a vector of regexs corresponding to the regex strings.
71 575 : BOOST_FOREACH(string regex_str, regex_strings()) {
72 112 : to_match_regexs_.push_back(regex(regex_str));
73 112 : }
74 351 : }
75 :
76 839 : MatchCommunity::~MatchCommunity() {
77 839 : }
78 :
79 : //
80 : // Return true if all community strings (normal or regex) are matched by the
81 : // community values in the BgpAttr.
82 : //
83 72 : bool MatchCommunity::MatchAll(const BgpAttr *attr) const {
84 : // Bail if there's no community values in the BgpAttr.
85 72 : const Community *comm = attr->community();
86 72 : if (!comm)
87 0 : return false;
88 :
89 : // Make sure that all non-regex communities in this MatchCommunity are
90 : // present in the BgpAttr.
91 72 : vector<uint32_t> list = comm->communities();
92 72 : sort(list.begin(), list.end());
93 144 : if (!includes(list.begin(), list.end(),
94 144 : communities().begin(), communities().end())) {
95 20 : return false;
96 : }
97 :
98 : // Make sure that each regex in this MatchCommunity is matched by one
99 : // of the communities in the BgpAttr.
100 172 : BOOST_FOREACH(const regex &match_expr, regexs()) {
101 77 : bool matched = false;
102 383 : BOOST_FOREACH(uint32_t community, comm->communities()) {
103 183 : string community_str = CommunityType::CommunityToString(community);
104 183 : if (regex_match(community_str, match_expr)) {
105 60 : matched = true;
106 60 : break;
107 : }
108 183 : }
109 77 : if (!matched)
110 17 : return false;
111 : }
112 :
113 35 : return true;
114 72 : }
115 :
116 : //
117 : // Return true if any community strings (normal or regex) is matched by the
118 : // community values in the BgpAttr.
119 : //
120 383 : bool MatchCommunity::MatchAny(const BgpAttr *attr) const {
121 : // Bail if there's no community values in the BgpAttr.
122 383 : const Community *comm = attr->community();
123 383 : if (!comm)
124 254 : return false;
125 :
126 : // Check if any of the community values in the BgpAttr matches one of
127 : // the normal community strings.
128 315 : BOOST_FOREACH(uint32_t community, comm->communities()) {
129 174 : if (communities().find(community) != communities().end())
130 81 : return true;
131 : }
132 :
133 : // Check if any of the community values in the BgpAttr matches one of
134 : // the community regexs.
135 150 : BOOST_FOREACH(uint32_t community, comm->communities()) {
136 64 : string community_str = CommunityType::CommunityToString(community);
137 168 : BOOST_FOREACH(const regex &match_expr, regexs()) {
138 65 : if (regex_match(community_str, match_expr))
139 13 : return true;
140 : }
141 64 : }
142 :
143 35 : return false;
144 : }
145 :
146 : //
147 : // Return true if the BgpPath matches this MatchCommunity.
148 : //
149 455 : bool MatchCommunity::Match(const BgpRoute *route, const BgpPath *path,
150 : const BgpAttr *attr) const {
151 455 : return (match_all_ ? MatchAll(attr) : MatchAny(attr));
152 : }
153 :
154 : //
155 : // Return string representation of this MatchCommunity.
156 : //
157 19 : string MatchCommunity::ToString() const {
158 19 : ostringstream oss;
159 19 : if (match_all_) {
160 4 : oss << "community (all) [ ";
161 : } else {
162 15 : oss << "community (any) [ ";
163 : }
164 53 : BOOST_FOREACH(uint32_t community, communities()) {
165 17 : string name = CommunityType::CommunityToString(community);
166 17 : oss << name << ",";
167 17 : }
168 43 : BOOST_FOREACH(string regex_str, regex_strings()) {
169 12 : oss << regex_str << ",";
170 12 : }
171 19 : oss.seekp(-1, oss.cur);
172 19 : oss << " ]";
173 38 : return oss.str();
174 19 : }
175 :
176 : //
177 : // Return true if this MatchCommunity is equal to the one supplied.
178 : //
179 204 : bool MatchCommunity::IsEqual(const RoutingPolicyMatch &community) const {
180 : const MatchCommunity in_community =
181 204 : static_cast<const MatchCommunity &>(community);
182 204 : if (match_all() != in_community.match_all())
183 8 : return false;
184 196 : if (communities() != in_community.communities())
185 14 : return false;
186 182 : if (regex_strings() != in_community.regex_strings())
187 12 : return false;
188 170 : return true;
189 204 : }
190 :
191 81 : MatchExtCommunity::MatchExtCommunity(const vector<string> &communities,
192 81 : bool match_all) : match_all_(match_all) {
193 : // Assume that the each community string that doesn't correspond to a
194 : // community name or value is a regex string.
195 465 : BOOST_FOREACH(const string &community, communities) {
196 : const ExtCommunity::ExtCommunityList list =
197 192 : ExtCommunity::ExtCommunityFromString(community);
198 192 : if (list.size()) {
199 92 : if(!Find(list[0]))
200 88 : to_match_.push_back(list[0]);
201 : } else {
202 100 : to_match_regex_strings_.push_back(community);
203 : }
204 192 : }
205 :
206 : // Sort and uniquify the vector of regex strings.
207 81 : sort(to_match_.begin(), to_match_.end());
208 81 : sort(to_match_regex_strings_.begin(), to_match_regex_strings_.end());
209 : vector<string>::iterator it =
210 81 : unique(to_match_regex_strings_.begin(), to_match_regex_strings_.end());
211 81 : to_match_regex_strings_.erase(it, to_match_regex_strings_.end());
212 :
213 : // Build a vector of regexs corresponding to the regex strings.
214 269 : BOOST_FOREACH(string regex_str, regex_strings()) {
215 94 : to_match_regexs_.push_back(regex(regex_str));
216 94 : }
217 81 : }
218 :
219 139 : MatchExtCommunity::~MatchExtCommunity() {
220 139 : }
221 :
222 : //
223 : // Return true if all community strings (normal or regex) are matched by the
224 : // community values in the BgpAttr.
225 : //
226 51 : bool MatchExtCommunity::MatchAll(const BgpAttr *attr) const {
227 : // Bail if there's no community values in the BgpAttr.
228 51 : const ExtCommunity *comm = attr->ext_community();
229 51 : if (!comm)
230 0 : return false;
231 :
232 : // Make sure that all non-regex communities in this MatchExtCommunity are
233 : // present in the BgpAttr.
234 51 : ExtCommunity::ExtCommunityList list = comm->communities();
235 51 : sort(list.begin(), list.end());
236 102 : if (!includes(list.begin(), list.end(),
237 102 : communities().begin(), communities().end())) {
238 15 : return false;
239 : }
240 :
241 : // Make sure that each regex in this MatchExtCommunity is matched by one
242 : // of the communities in the BgpAttr.
243 120 : BOOST_FOREACH(const regex &match_expr, regexs()) {
244 54 : bool matched = false;
245 260 : BOOST_FOREACH(ExtCommunity::ExtCommunityValue community,
246 : comm->communities()) {
247 124 : string community_str = ExtCommunity::ToString(community);
248 124 : if (regex_match(community_str, match_expr)) {
249 42 : matched = true;
250 42 : break;
251 : }
252 82 : community_str = ExtCommunity::ToHexString(community);
253 82 : if (regex_match(community_str, match_expr)) {
254 0 : matched = true;
255 0 : break;
256 : }
257 124 : }
258 54 : if (!matched)
259 12 : return false;
260 : }
261 :
262 24 : return true;
263 51 : }
264 :
265 151 : bool MatchExtCommunity::Find(const ExtCommunity::ExtCommunityValue &community)
266 : const {
267 151 : return (std::find(communities().begin(), communities().end(), community) !=
268 302 : communities().end());
269 : }
270 :
271 : //
272 : // Return true if any community strings (normal or regex) is matched by the
273 : // community values in the BgpAttr.
274 : //
275 25 : bool MatchExtCommunity::MatchAny(const BgpAttr *attr) const {
276 : // Bail if there's no community values in the BgpAttr.
277 25 : const ExtCommunity *comm = attr->ext_community();
278 25 : if (!comm)
279 0 : return false;
280 :
281 : // Check if any of the community values in the BgpAttr matches one of
282 : // the normal community strings.
283 97 : BOOST_FOREACH(ExtCommunity::ExtCommunityValue community,
284 : comm->communities()) {
285 43 : if (Find(community))
286 7 : return true;
287 : }
288 :
289 : // Check if any of the community values in the BgpAttr matches one of
290 : // the community regexs.
291 58 : BOOST_FOREACH(ExtCommunity::ExtCommunityValue community,
292 : comm->communities()) {
293 27 : string community_str = ExtCommunity::ToString(community);
294 91 : BOOST_FOREACH(const regex &match_expr, regexs()) {
295 38 : if (regex_match(community_str, match_expr))
296 6 : return true;
297 : }
298 21 : community_str = ExtCommunity::ToHexString(community);
299 77 : BOOST_FOREACH(const regex &match_expr, regexs()) {
300 29 : if (regex_match(community_str, match_expr))
301 1 : return true;
302 : }
303 27 : }
304 :
305 11 : return false;
306 : }
307 :
308 : //
309 : // Return true if the BgpPath matches this MatchExtCommunity.
310 : //
311 76 : bool MatchExtCommunity::Match(const BgpRoute *route, const BgpPath *path,
312 : const BgpAttr *attr) const {
313 76 : return (match_all_ ? MatchAll(attr) : MatchAny(attr));
314 : }
315 :
316 : //
317 : // Return string representation of this MatchExtCommunity.
318 : //
319 8 : string MatchExtCommunity::ToString() const {
320 8 : ostringstream oss;
321 8 : if (match_all_) {
322 4 : oss << "Extcommunity (all) [ ";
323 : } else {
324 4 : oss << "Extcommunity (any) [ ";
325 : }
326 20 : BOOST_FOREACH(ExtCommunity::ExtCommunityValue community, communities()) {
327 6 : string name = ExtCommunity::ToString(community);
328 6 : oss << name << ",";
329 6 : }
330 32 : BOOST_FOREACH(string regex_str, regex_strings()) {
331 12 : oss << regex_str << ",";
332 12 : }
333 8 : oss.seekp(-1, oss.cur);
334 8 : oss << " ]";
335 16 : return oss.str();
336 8 : }
337 :
338 : //
339 : // Return true if this MatchExtCommunity is equal to the one supplied.
340 : //
341 46 : bool MatchExtCommunity::IsEqual(const RoutingPolicyMatch &community) const {
342 : const MatchExtCommunity in_community =
343 46 : static_cast<const MatchExtCommunity &>(community);
344 46 : if (match_all() != in_community.match_all())
345 8 : return false;
346 38 : if (communities() != in_community.communities())
347 12 : return false;
348 26 : if (regex_strings() != in_community.regex_strings())
349 12 : return false;
350 14 : return true;
351 46 : }
352 :
353 : template <typename T>
354 298 : typename MatchPrefix<T>::MatchType MatchPrefix<T>::GetMatchType(
355 : const string &match_type_str) {
356 298 : MatchType match_type = EXACT;
357 298 : if (match_type_str == "exact") {
358 180 : match_type = EXACT;
359 118 : } else if (match_type_str == "longer") {
360 36 : match_type = LONGER;
361 82 : } else if (match_type_str == "orlonger") {
362 62 : match_type = ORLONGER;
363 : }
364 298 : return match_type;
365 : }
366 :
367 : template <typename T>
368 200 : MatchPrefix<T>::MatchPrefix(const PrefixMatchConfigList &match_config_list) {
369 760 : BOOST_FOREACH(const PrefixMatchConfig &match_config, match_config_list) {
370 280 : boost::system::error_code ec;
371 280 : PrefixT prefix = PrefixT::FromString(match_config.prefix_to_match, &ec);
372 : MatchType match_type =
373 280 : MatchPrefix<T>::GetMatchType(match_config.prefix_match_type);
374 280 : match_list_.push_back(PrefixMatch(prefix, match_type));
375 : }
376 :
377 : // Sort and uniquify the vector of PrefixMatch elements.
378 200 : sort(match_list_.begin(), match_list_.end());
379 : typename PrefixMatchList::iterator it =
380 200 : unique(match_list_.begin(), match_list_.end());
381 200 : match_list_.erase(it, match_list_.end());
382 200 : }
383 :
384 : template <typename T>
385 478 : MatchPrefix<T>::~MatchPrefix() {
386 478 : }
387 :
388 : template <typename T>
389 596 : bool MatchPrefix<T>::Match(const BgpRoute *route, const BgpPath *path,
390 : const BgpAttr *attr) const {
391 596 : const RouteT *in_route = dynamic_cast<const RouteT *>(route);
392 596 : if (in_route == NULL)
393 3 : return false;
394 593 : const PrefixT &prefix = in_route->GetPrefix();
395 2198 : BOOST_FOREACH(const PrefixMatch &prefix_match, match_list_) {
396 870 : if (prefix_match.match_type == EXACT) {
397 564 : if (prefix == prefix_match.prefix)
398 67 : return true;
399 306 : } else if (prefix_match.match_type == LONGER) {
400 272 : if (prefix == prefix_match.prefix)
401 3 : continue;
402 269 : if (prefix.IsMoreSpecific(prefix_match.prefix))
403 7 : return true;
404 34 : } else if (prefix_match.match_type == ORLONGER) {
405 34 : if (prefix.IsMoreSpecific(prefix_match.prefix))
406 26 : return true;
407 : }
408 : }
409 523 : return false;
410 : }
411 :
412 : template <typename T>
413 106 : bool MatchPrefix<T>::IsEqual(const RoutingPolicyMatch &prefix) const {
414 106 : const MatchPrefix in_prefix = static_cast<const MatchPrefix&>(prefix);
415 212 : return (in_prefix.match_list_ == match_list_);
416 106 : }
417 :
418 : template <typename T>
419 16 : string MatchPrefix<T>::ToString() const {
420 16 : ostringstream oss;
421 16 : oss << "prefix [";
422 72 : BOOST_FOREACH(const PrefixMatch &prefix_match, match_list_) {
423 28 : oss << " " << prefix_match.prefix.ToString();
424 28 : if (prefix_match.match_type == LONGER) {
425 6 : oss << " longer";
426 22 : } else if (prefix_match.match_type == ORLONGER) {
427 6 : oss << " orlonger";
428 : }
429 28 : oss << ",";
430 : }
431 16 : oss.seekp(-1, oss.cur);
432 16 : oss << " ]";
433 32 : return oss.str();
434 16 : }
435 :
436 : template class MatchPrefix<PrefixMatchInet>;
437 : template class MatchPrefix<PrefixMatchInet6>;
438 :
439 : static const map<string, MatchProtocol::MatchProtocolType> fromString
440 : = boost::assign::map_list_of
441 : ("bgp", MatchProtocol::BGP)
442 : ("xmpp", MatchProtocol::XMPP)
443 : ("static", MatchProtocol::StaticRoute)
444 : ("service-chain", MatchProtocol::ServiceChainRoute)
445 : ("aggregate", MatchProtocol::AggregateRoute)
446 : ("interface", MatchProtocol::Interface)
447 : ("interface-static", MatchProtocol::InterfaceStatic)
448 : ("service-interface", MatchProtocol::ServiceInterface)
449 : ("bgpaas", MatchProtocol::BGPaaS);
450 :
451 : static const map<MatchProtocol::MatchProtocolType, string> toString
452 : = boost::assign::map_list_of
453 : (MatchProtocol::BGP, "bgp")
454 : (MatchProtocol::XMPP, "xmpp")
455 : (MatchProtocol::StaticRoute, "static")
456 : (MatchProtocol::ServiceChainRoute, "service-chain")
457 : (MatchProtocol::AggregateRoute, "aggregate")
458 : (MatchProtocol::Interface, "interface")
459 : (MatchProtocol::InterfaceStatic, "interface-static")
460 : (MatchProtocol::ServiceInterface, "service-interface")
461 : (MatchProtocol::BGPaaS, "bgpaas");
462 :
463 : static const map<MatchProtocol::MatchProtocolType, BgpPath::PathSource>
464 : pathSourceMap = boost::assign::map_list_of
465 : (MatchProtocol::BGP, BgpPath::BGP_XMPP)
466 : (MatchProtocol::XMPP, BgpPath::BGP_XMPP)
467 : (MatchProtocol::StaticRoute, BgpPath::StaticRoute)
468 : (MatchProtocol::ServiceChainRoute, BgpPath::ServiceChain)
469 : (MatchProtocol::AggregateRoute, BgpPath::Aggregate)
470 : (MatchProtocol::Interface, BgpPath::BGP_XMPP)
471 : (MatchProtocol::InterfaceStatic, BgpPath::BGP_XMPP)
472 : (MatchProtocol::ServiceInterface, BgpPath::BGP_XMPP)
473 : (MatchProtocol::BGPaaS, BgpPath::BGP_XMPP);
474 :
475 : static const vector<MatchProtocol::MatchProtocolType>
476 : isSubprotocol = boost::assign::list_of(MatchProtocol::Interface)
477 : (MatchProtocol::InterfaceStatic)
478 : (MatchProtocol::ServiceInterface)
479 : (MatchProtocol::StaticRoute);
480 :
481 78 : static bool IsSubprotocol(MatchProtocol::MatchProtocolType protocol) {
482 78 : return (find(isSubprotocol.begin(), isSubprotocol.end(), protocol) !=
483 156 : isSubprotocol.end());
484 : }
485 :
486 2092 : const string MatchProtocolToString(MatchProtocol::MatchProtocolType protocol) {
487 : map<MatchProtocol::MatchProtocolType, string>::const_iterator it =
488 2092 : toString.find(protocol);
489 2092 : if (it != toString.end()) {
490 2092 : return it->second;
491 : }
492 0 : return "unspecified";
493 : }
494 :
495 107 : static MatchProtocol::MatchProtocolType MatchProtocolFromString(
496 : const string &protocol) {
497 : map<string, MatchProtocol::MatchProtocolType>::const_iterator it =
498 107 : fromString.find(protocol);
499 107 : if (it != fromString.end()) {
500 106 : return it->second;
501 : }
502 1 : return MatchProtocol::Unspecified;
503 : }
504 :
505 55 : static BgpPath::PathSource PathSourceFromMatchProtocol(
506 : MatchProtocol::MatchProtocolType src) {
507 : map<MatchProtocol::MatchProtocolType, BgpPath::PathSource>::const_iterator
508 55 : it = pathSourceMap.find(src);
509 55 : if (it != pathSourceMap.end()) {
510 55 : return it->second;
511 : }
512 0 : return BgpPath::None;
513 : }
514 :
515 41 : MatchProtocol::MatchProtocol(const vector<string> &protocols) {
516 255 : BOOST_FOREACH(const string &protocol, protocols) {
517 107 : MatchProtocolType value = MatchProtocolFromString(protocol);
518 : // Ignore invalid protocol values.
519 107 : if (value == Unspecified)
520 1 : continue;
521 106 : to_match_.push_back(value);
522 : }
523 :
524 : // Sort and uniquify the vector match protocols.
525 41 : sort(to_match_.begin(), to_match_.end());
526 : vector<MatchProtocolType>::iterator it =
527 41 : unique(to_match_.begin(), to_match_.end());
528 41 : to_match_.erase(it, to_match_.end());
529 41 : }
530 :
531 76 : MatchProtocol::~MatchProtocol() {
532 76 : }
533 :
534 43 : bool MatchProtocol::Match(const BgpRoute *route, const BgpPath *path,
535 : const BgpAttr *attr) const {
536 43 : BgpPath::PathSource path_src = path->GetSource();
537 43 : bool is_xmpp = path->GetPeer() ? path->GetPeer()->IsXmppPeer() : false;
538 43 : bool bgpaas = path->GetPeer() ? path->GetPeer()->IsRouterTypeBGPaaS() : false;
539 145 : BOOST_FOREACH(MatchProtocolType protocol, protocols()) {
540 78 : if (IsSubprotocol(protocol)) {
541 : // Check only if matching protocol is subprotocol
542 23 : if (attr && !attr->sub_protocol().empty()) {
543 14 : std::string matchps = MatchProtocolToString(protocol);
544 14 : if (matchps.compare(attr->sub_protocol()) == 0)
545 11 : return true;
546 14 : }
547 : } else {
548 : BgpPath::PathSource mapped_src =
549 55 : PathSourceFromMatchProtocol(protocol);
550 55 : if (mapped_src != BgpPath::None) {
551 55 : if (mapped_src == path_src) {
552 25 : if (protocol == XMPP && !is_xmpp)
553 3 : continue;
554 22 : if (protocol == BGP && (bgpaas || is_xmpp))
555 4 : continue;
556 18 : if (protocol == BGPaaS && (!bgpaas || is_xmpp))
557 2 : continue;
558 16 : return true;
559 : }
560 : }
561 : }
562 : }
563 16 : return false;
564 : }
565 :
566 6 : string MatchProtocol::ToString() const {
567 6 : ostringstream oss;
568 6 : oss << "protocol [ ";
569 40 : BOOST_FOREACH(MatchProtocolType protocol, protocols()) {
570 17 : string name = MatchProtocolToString(protocol);
571 17 : oss << name << ",";
572 17 : }
573 6 : oss.seekp(-1, oss.cur);
574 6 : oss << " ]";
575 12 : return oss.str();
576 6 : }
577 :
578 19 : bool MatchProtocol::IsEqual(const RoutingPolicyMatch &protocol) const {
579 : const MatchProtocol in_protocol =
580 19 : static_cast<const MatchProtocol&>(protocol);
581 38 : return (protocols() == in_protocol.protocols());
582 19 : }
|