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/bgp_path.h"
7 :
8 : #include <boost/foreach.hpp>
9 :
10 : #include "bgp/bgp_peer.h"
11 : #include "bgp/bgp_route.h"
12 : #include "bgp/bgp_server.h"
13 : #include "bgp/extended-community/sub_cluster.h"
14 : #include "net/community_type.h"
15 :
16 : using std::string;
17 : using std::vector;
18 :
19 1278568 : string BgpPath::PathIdString(uint32_t path_id) {
20 1278568 : Ip4Address addr(path_id);
21 2557089 : return addr.to_string();
22 : }
23 :
24 918916 : BgpPath::BgpPath(const IPeer *peer, uint32_t path_id, PathSource src,
25 : const BgpAttrPtr ptr, uint32_t flags, uint32_t label,
26 918916 : uint32_t l3_label)
27 918892 : : peer_(peer), path_id_(path_id), source_(src), attr_(ptr),
28 918916 : original_attr_(ptr), flags_(flags), label_(label), l3_label_(l3_label) {
29 918954 : }
30 :
31 889 : BgpPath::BgpPath(const IPeer *peer, PathSource src, const BgpAttrPtr ptr,
32 889 : uint32_t flags, uint32_t label, uint32_t l3_label)
33 889 : : peer_(peer), path_id_(0), source_(src), attr_(ptr), original_attr_(ptr),
34 889 : flags_(flags), label_(label), l3_label_(l3_label) {
35 889 : }
36 :
37 46635 : BgpPath::BgpPath(uint32_t path_id, PathSource src, const BgpAttrPtr ptr,
38 46635 : uint32_t flags, uint32_t label, uint32_t l3_label)
39 46635 : : peer_(NULL), path_id_(path_id), source_(src), attr_(ptr),
40 46635 : original_attr_(ptr), flags_(flags), label_(label), l3_label_(l3_label) {
41 46635 : }
42 :
43 193 : BgpPath::BgpPath(PathSource src, const BgpAttrPtr ptr,
44 193 : uint32_t flags, uint32_t label, uint32_t l3_label)
45 193 : : peer_(NULL), path_id_(0), source_(src), attr_(ptr), original_attr_(ptr),
46 193 : flags_(flags), label_(label), l3_label_(l3_label) {
47 193 : }
48 :
49 : // True is better
50 : #define BOOL_COMPARE(CondA, CondB) \
51 : do { \
52 : if (CondA) { \
53 : if (!(CondB)) return -1; \
54 : } else { \
55 : if (CondB) return 1; \
56 : } \
57 : } while (0)
58 :
59 2374882 : int BgpPath::PathCompare(const BgpPath &rhs, bool allow_ecmp) const {
60 2374882 : const BgpAttr *rattr = rhs.GetAttr();
61 :
62 : // Feasible Path first
63 2374875 : KEY_COMPARE(rhs.IsFeasible(), IsFeasible());
64 :
65 : // Compare local_pref in reverse order as larger is better.
66 2359643 : KEY_COMPARE(rattr->local_pref(), attr_->local_pref());
67 :
68 : // ETree Root path first [compare in reverse order]
69 2357492 : BOOL_COMPARE(rattr->etree_leaf(), attr_->etree_leaf());
70 :
71 : // Sticky paths first
72 2357436 : BOOL_COMPARE(rattr->evpn_sticky_mac(), attr_->evpn_sticky_mac());
73 :
74 : // Compare sequence_number in reverse order as larger is better.
75 2357427 : KEY_COMPARE(rattr->sequence_number(), attr_->sequence_number());
76 :
77 : // Route without LLGR_STALE community is always preferred over one with.
78 2357469 : bool llgr_stale = attr_->community() && attr_->community()->ContainsValue(
79 2357471 : CommunityType::LlgrStale);
80 2357471 : llgr_stale |= IsLlgrStale();
81 :
82 2357472 : bool rllgr_stale = rattr->community() && rattr->community()->ContainsValue(
83 2357469 : CommunityType::LlgrStale);
84 2357469 : rllgr_stale |= rhs.IsLlgrStale();
85 :
86 2357469 : KEY_COMPARE(llgr_stale, rllgr_stale);
87 :
88 : // Do not compare as path length for service chain paths at this point.
89 : // We want to treat service chain paths as ECMP irrespective of as path
90 : // length.
91 2356839 : const BgpServer *server = attr_->attr_db()->server();
92 4748199 : if (!server->ignore_aspath() &&
93 2391367 : (!attr_->origin_vn_path() || !rattr->origin_vn_path())) {
94 2323614 : KEY_COMPARE(attr_->max_as_path_count(), rattr->max_as_path_count());
95 : }
96 :
97 2353630 : KEY_COMPARE(attr_->origin(), rattr->origin());
98 :
99 : // Compare med if always compare med knob is enabled or if both paths are
100 : // learnt from the same neighbor as.
101 4707143 : if (server->global_config()->always_compare_med() ||
102 2353570 : (attr_->neighbor_as() &&
103 148507 : attr_->neighbor_as() == rattr->neighbor_as())) {
104 147482 : KEY_COMPARE(attr_->med(), rattr->med());
105 : }
106 :
107 : // For ECMP paths, above checks should suffice.
108 2353543 : if (allow_ecmp)
109 556630 : return 0;
110 :
111 : // Prefer non-aliased paths.
112 1796913 : BOOL_COMPARE(rhs.IsAliased(), IsAliased());
113 :
114 : // Compare as path length for service chain paths since we bypassed the
115 : // check previously.
116 1796860 : if (attr_->origin_vn_path() && rattr->origin_vn_path())
117 11690 : KEY_COMPARE(attr_->max_as_path_count(), rattr->max_as_path_count());
118 :
119 : // Prefer locally generated routes over bgp and xmpp routes.
120 1796858 : BOOL_COMPARE(peer_ == NULL, rhs.peer_ == NULL);
121 :
122 : // Compare the source and the path id.
123 1790878 : KEY_COMPARE(rhs.GetSource(), GetSource());
124 :
125 : // Bail if both paths are local since all subsequent checks are
126 : // based on IPeer properties.
127 1789335 : if (peer_ == NULL && rhs.peer_ == NULL) {
128 1575712 : KEY_COMPARE(path_id_, rhs.path_id_);
129 1561800 : return 0;
130 : }
131 :
132 : // Prefer xmpp routes over bgp routes.
133 213623 : BOOL_COMPARE(peer_->IsXmppPeer(), rhs.peer_->IsXmppPeer());
134 :
135 : // Path received from EBGP is better than the one received from IBGP
136 198779 : KEY_COMPARE(peer_->PeerType() == BgpProto::IBGP,
137 : rhs.peer_->PeerType() == BgpProto::IBGP);
138 :
139 198755 : KEY_COMPARE(path_id_, rhs.path_id_);
140 :
141 : // Lower router id is better. Substitute originator id for router id
142 : // if the path has an originator id.
143 191141 : uint32_t orig_id = attr_->originator_id().to_ulong();
144 191141 : uint32_t rorig_id = rattr->originator_id().to_ulong();
145 191141 : uint32_t id = orig_id ? orig_id : peer_->bgp_identifier();
146 191141 : uint32_t rid = rorig_id ? rorig_id : rhs.peer_->bgp_identifier();
147 191141 : KEY_COMPARE(id, rid);
148 :
149 80092 : KEY_COMPARE(attr_->cluster_list_length(), rattr->cluster_list_length());
150 :
151 80088 : const BgpPeer *lpeer = dynamic_cast<const BgpPeer *>(peer_);
152 80088 : const BgpPeer *rpeer = dynamic_cast<const BgpPeer *>(rhs.peer_);
153 80088 : if (lpeer != NULL && rpeer != NULL) {
154 890 : KEY_COMPARE(lpeer->peer_key(), rpeer->peer_key());
155 : }
156 :
157 80032 : return 0;
158 : }
159 :
160 178 : bool BgpPath::PathSameNeighborAs(const BgpPath &rhs) const {
161 178 : const BgpAttr *rattr = rhs.GetAttr();
162 178 : if (!peer_ || peer_->PeerType() != BgpProto::EBGP)
163 2 : return false;
164 176 : if (!rhs.peer_ || rhs.peer_->PeerType() != BgpProto::EBGP)
165 2 : return false;
166 174 : return (attr_->neighbor_as() == rattr->neighbor_as());
167 : }
168 :
169 1932571 : void BgpPath::UpdatePeerRefCount(int count, Address::Family family) const {
170 1932571 : if (!peer_)
171 642968 : return;
172 1289603 : peer_->UpdateTotalPathCount(count);
173 1289866 : if (source_ != BGP_XMPP || IsReplicated() || IsResolved() || IsAliased())
174 804060 : return;
175 485773 : peer_->UpdatePrimaryPathCount(count, family);
176 : }
177 :
178 827580 : string BgpPath::ToString() const {
179 827580 : return peer_ ? peer_->ToString() : "Nil";
180 : }
181 :
182 6144 : RouteDistinguisher BgpPath::GetSourceRouteDistinguisher() const {
183 6144 : if (!attr_->source_rd().IsZero())
184 6139 : return attr_->source_rd();
185 3 : if (!IsReplicated())
186 1 : return RouteDistinguisher::kZeroRd;
187 :
188 2 : const BgpSecondaryPath *path = static_cast<const BgpSecondaryPath *>(this);
189 2 : return path->GetPrimaryRouteDistinguisher();
190 : }
191 :
192 5606 : vector<string> BgpPath::GetFlagsStringList() const {
193 5606 : vector<string> flag_names;
194 5604 : if (flags_ == 0) {
195 5599 : flag_names.push_back("None");
196 5588 : return flag_names;
197 : }
198 :
199 : // First we form a list of enums and then iterate over it to get their
200 : // string forms using switch. This lets compiler tell us when ever we add a
201 : // new enumeration to PathFlag.
202 5 : vector<PathFlag> flags;
203 5 : if (flags_ & AsPathLooped)
204 1 : flags.push_back(AsPathLooped);
205 5 : if (flags_ & NoNeighborAs)
206 1 : flags.push_back(NoNeighborAs);
207 5 : if (flags_ & Stale)
208 1 : flags.push_back(Stale);
209 5 : if (flags_ & NoTunnelEncap)
210 1 : flags.push_back(NoTunnelEncap);
211 5 : if (flags_ & OriginatorIdLooped)
212 1 : flags.push_back(OriginatorIdLooped);
213 5 : if (flags_ & ResolveNexthop)
214 5 : flags.push_back(ResolveNexthop);
215 5 : if (flags_ & ResolvedPath)
216 1 : flags.push_back(ResolvedPath);
217 5 : if (flags_ & RoutingPolicyReject)
218 1 : flags.push_back(RoutingPolicyReject);
219 5 : if (flags_ & LlgrStale)
220 1 : flags.push_back(LlgrStale);
221 5 : if (flags_ & ClusterListLooped)
222 1 : flags.push_back(ClusterListLooped);
223 5 : if (flags_ & AliasedPath)
224 1 : flags.push_back(AliasedPath);
225 5 : if (flags_ & CheckGlobalErmVpnRoute)
226 1 : flags.push_back(CheckGlobalErmVpnRoute);
227 :
228 21 : for (auto flag : flags) {
229 16 : switch (flag) {
230 1 : case AsPathLooped:
231 1 : flag_names.push_back("AsPathLooped");
232 1 : break;
233 1 : case NoNeighborAs:
234 1 : flag_names.push_back("NoNeighborAs");
235 1 : break;
236 1 : case Stale:
237 1 : flag_names.push_back("Stale");
238 1 : break;
239 1 : case NoTunnelEncap:
240 1 : flag_names.push_back("NoTunnelEncap");
241 1 : break;
242 1 : case OriginatorIdLooped:
243 1 : flag_names.push_back("OriginatorIdLooped");
244 1 : break;
245 5 : case ResolveNexthop:
246 5 : flag_names.push_back("ResolveNexthop");
247 5 : break;
248 1 : case ResolvedPath:
249 1 : flag_names.push_back("ResolvedPath");
250 1 : break;
251 1 : case RoutingPolicyReject:
252 1 : flag_names.push_back("RoutingPolicyReject");
253 1 : break;
254 1 : case LlgrStale:
255 1 : flag_names.push_back("LlgrStale");
256 1 : break;
257 1 : case ClusterListLooped:
258 1 : flag_names.push_back("ClusterListLooped");
259 1 : break;
260 1 : case AliasedPath:
261 1 : flag_names.push_back("AliasedPath");
262 1 : break;
263 1 : case CheckGlobalErmVpnRoute:
264 1 : flag_names.push_back("CheckGlobalErmVpnRoute");
265 1 : break;
266 : }
267 : }
268 5 : return flag_names;
269 5 : }
270 :
271 7241 : string BgpPath::GetSourceString(bool combine_bgp_and_xmpp) const {
272 7241 : switch (source_) {
273 2 : case None:
274 2 : return "None";
275 6472 : case BGP_XMPP:
276 6472 : if (combine_bgp_and_xmpp) {
277 321 : return "BGP_XMPP";
278 6151 : } else if (peer_) {
279 6004 : return(peer_->IsXmppPeer() ? "XMPP" : "BGP");
280 : } else {
281 147 : return "None";
282 : }
283 482 : case ServiceChain:
284 482 : return "ServiceChain";
285 34 : case StaticRoute:
286 34 : return "StaticRoute";
287 190 : case Aggregate:
288 190 : return "Aggregate";
289 61 : case Local:
290 61 : return "Local";
291 : }
292 0 : return "None";
293 : }
294 :
295 579475 : BgpSecondaryPath::BgpSecondaryPath(const IPeer *peer, uint32_t path_id,
296 : PathSource src, const BgpAttrPtr ptr, uint32_t flags, uint32_t label,
297 579475 : uint32_t l3_label)
298 579475 : : BgpPath(peer, path_id, src, ptr, flags, label, l3_label) {
299 579472 : }
300 :
301 2 : RouteDistinguisher BgpSecondaryPath::GetPrimaryRouteDistinguisher() const {
302 2 : return src_entry_->GetRouteDistinguisher();
303 : }
304 :
305 0 : void BgpPath::AddExtCommunitySubCluster(uint32_t subcluster_id) {
306 0 : BgpAttr *attr = new BgpAttr(*(GetOriginalAttr()));
307 0 : BgpServer *server = attr->attr_db()->server();
308 0 : ExtCommunityPtr ext_community = attr->ext_community();
309 :
310 0 : SubCluster sc(server->autonomous_system(), subcluster_id);
311 : ext_community = server->extcomm_db()->
312 0 : ReplaceSubClusterAndLocate(ext_community.get(),
313 0 : sc.GetExtCommunity());
314 : BgpAttrPtr modified_attr = server->attr_db()->
315 0 : ReplaceExtCommunityAndLocate(attr, ext_community);
316 : // Since routing policies are applied only to original attribute hence
317 : // we are updating original_attr with subcluster extended community.
318 : // Also we need to set modified_attr in attr as well as orignal_attr,
319 : // because there may or may not be a policy but we still need to add this
320 : // community.
321 : // Modifying original attr should be done judiciously and only if required.
322 0 : if (modified_attr) {
323 0 : SetAttr(modified_attr, modified_attr);
324 : }
325 0 : }
|