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