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