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 0 : string BgpPath::PathIdString(uint32_t path_id) {
19 0 : Ip4Address addr(path_id);
20 0 : return addr.to_string();
21 : }
22 :
23 80 : BgpPath::BgpPath(const IPeer *peer, uint32_t path_id, PathSource src,
24 : const BgpAttrPtr ptr, uint32_t flags, uint32_t label,
25 80 : uint32_t l3_label)
26 80 : : peer_(peer), path_id_(path_id), source_(src), attr_(ptr),
27 80 : original_attr_(ptr), flags_(flags), label_(label), l3_label_(l3_label) {
28 80 : }
29 :
30 0 : BgpPath::BgpPath(const IPeer *peer, PathSource src, const BgpAttrPtr ptr,
31 0 : uint32_t flags, uint32_t label, uint32_t l3_label)
32 0 : : peer_(peer), path_id_(0), source_(src), attr_(ptr), original_attr_(ptr),
33 0 : flags_(flags), label_(label), l3_label_(l3_label) {
34 0 : }
35 :
36 270 : BgpPath::BgpPath(uint32_t path_id, PathSource src, const BgpAttrPtr ptr,
37 270 : uint32_t flags, uint32_t label, uint32_t l3_label)
38 270 : : peer_(NULL), path_id_(path_id), source_(src), attr_(ptr),
39 270 : original_attr_(ptr), flags_(flags), label_(label), l3_label_(l3_label) {
40 270 : }
41 :
42 0 : BgpPath::BgpPath(PathSource src, const BgpAttrPtr ptr,
43 0 : uint32_t flags, uint32_t label, uint32_t l3_label)
44 0 : : peer_(NULL), path_id_(0), source_(src), attr_(ptr), original_attr_(ptr),
45 0 : flags_(flags), label_(label), l3_label_(l3_label) {
46 0 : }
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 16 : int BgpPath::PathCompare(const BgpPath &rhs, bool allow_ecmp) const {
59 16 : const BgpAttr *rattr = rhs.GetAttr();
60 :
61 : // Feasible Path first
62 16 : KEY_COMPARE(rhs.IsFeasible(), IsFeasible());
63 :
64 : // Compare local_pref in reverse order as larger is better.
65 16 : KEY_COMPARE(rattr->local_pref(), attr_->local_pref());
66 :
67 : // ETree Root path first [compare in reverse order]
68 16 : BOOL_COMPARE(rattr->etree_leaf(), attr_->etree_leaf());
69 :
70 : // Sticky paths first
71 16 : BOOL_COMPARE(rattr->evpn_sticky_mac(), attr_->evpn_sticky_mac());
72 :
73 : // Compare sequence_number in reverse order as larger is better.
74 16 : KEY_COMPARE(rattr->sequence_number(), attr_->sequence_number());
75 :
76 : // Route without LLGR_STALE community is always preferred over one with.
77 16 : bool llgr_stale = attr_->community() && attr_->community()->ContainsValue(
78 16 : CommunityType::LlgrStale);
79 16 : llgr_stale |= IsLlgrStale();
80 :
81 16 : bool rllgr_stale = rattr->community() && rattr->community()->ContainsValue(
82 16 : CommunityType::LlgrStale);
83 16 : rllgr_stale |= rhs.IsLlgrStale();
84 :
85 16 : 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 16 : const BgpServer *server = attr_->attr_db()->server();
91 32 : if (!server->ignore_aspath() &&
92 16 : (!attr_->origin_vn_path() || !rattr->origin_vn_path())) {
93 16 : KEY_COMPARE(attr_->max_as_path_count(), rattr->max_as_path_count());
94 : }
95 :
96 16 : 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 32 : if (server->global_config()->always_compare_med() ||
101 16 : (attr_->neighbor_as() &&
102 0 : attr_->neighbor_as() == rattr->neighbor_as())) {
103 0 : KEY_COMPARE(attr_->med(), rattr->med());
104 : }
105 :
106 : // For ECMP paths, above checks should suffice.
107 16 : if (allow_ecmp)
108 16 : return 0;
109 :
110 : // Prefer non-aliased paths.
111 0 : BOOL_COMPARE(rhs.IsAliased(), IsAliased());
112 :
113 : // Compare as path length for service chain paths since we bypassed the
114 : // check previously.
115 0 : if (attr_->origin_vn_path() && rattr->origin_vn_path())
116 0 : KEY_COMPARE(attr_->max_as_path_count(), rattr->max_as_path_count());
117 :
118 : // Prefer locally generated routes over bgp and xmpp routes.
119 0 : BOOL_COMPARE(peer_ == NULL, rhs.peer_ == NULL);
120 :
121 : // Compare the source and the path id.
122 0 : KEY_COMPARE(rhs.GetSource(), GetSource());
123 :
124 : // Bail if both paths are local since all subsequent checks are
125 : // based on IPeer properties.
126 0 : if (peer_ == NULL && rhs.peer_ == NULL) {
127 0 : KEY_COMPARE(path_id_, rhs.path_id_);
128 0 : return 0;
129 : }
130 :
131 : // Prefer xmpp routes over bgp routes.
132 0 : BOOL_COMPARE(peer_->IsXmppPeer(), rhs.peer_->IsXmppPeer());
133 :
134 : // Path received from EBGP is better than the one received from IBGP
135 0 : KEY_COMPARE(peer_->PeerType() == BgpProto::IBGP,
136 : rhs.peer_->PeerType() == BgpProto::IBGP);
137 :
138 0 : 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 0 : uint32_t orig_id = attr_->originator_id().to_ulong();
143 0 : uint32_t rorig_id = rattr->originator_id().to_ulong();
144 0 : uint32_t id = orig_id ? orig_id : peer_->bgp_identifier();
145 0 : uint32_t rid = rorig_id ? rorig_id : rhs.peer_->bgp_identifier();
146 0 : KEY_COMPARE(id, rid);
147 :
148 0 : KEY_COMPARE(attr_->cluster_list_length(), rattr->cluster_list_length());
149 :
150 0 : const BgpPeer *lpeer = dynamic_cast<const BgpPeer *>(peer_);
151 0 : const BgpPeer *rpeer = dynamic_cast<const BgpPeer *>(rhs.peer_);
152 0 : if (lpeer != NULL && rpeer != NULL) {
153 0 : KEY_COMPARE(lpeer->peer_key(), rpeer->peer_key());
154 : }
155 :
156 0 : return 0;
157 : }
158 :
159 0 : bool BgpPath::PathSameNeighborAs(const BgpPath &rhs) const {
160 0 : const BgpAttr *rattr = rhs.GetAttr();
161 0 : if (!peer_ || peer_->PeerType() != BgpProto::EBGP)
162 0 : return false;
163 0 : if (!rhs.peer_ || rhs.peer_->PeerType() != BgpProto::EBGP)
164 0 : return false;
165 0 : return (attr_->neighbor_as() == rattr->neighbor_as());
166 : }
167 :
168 700 : void BgpPath::UpdatePeerRefCount(int count, Address::Family family) const {
169 700 : if (!peer_)
170 604 : return;
171 96 : peer_->UpdateTotalPathCount(count);
172 96 : if (source_ != BGP_XMPP || IsReplicated() || IsResolved() || IsAliased())
173 0 : return;
174 96 : peer_->UpdatePrimaryPathCount(count, family);
175 : }
176 :
177 0 : string BgpPath::ToString() const {
178 0 : return peer_ ? peer_->ToString() : "Nil";
179 : }
180 :
181 0 : RouteDistinguisher BgpPath::GetSourceRouteDistinguisher() const {
182 0 : if (!attr_->source_rd().IsZero())
183 0 : return attr_->source_rd();
184 0 : if (!IsReplicated())
185 0 : return RouteDistinguisher::kZeroRd;
186 :
187 0 : const BgpSecondaryPath *path = static_cast<const BgpSecondaryPath *>(this);
188 0 : return path->GetPrimaryRouteDistinguisher();
189 : }
190 :
191 0 : vector<string> BgpPath::GetFlagsStringList() const {
192 0 : vector<string> flag_names;
193 0 : if (flags_ == 0) {
194 0 : flag_names.push_back("None");
195 0 : 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 0 : vector<PathFlag> flags;
202 0 : if (flags_ & AsPathLooped)
203 0 : flags.push_back(AsPathLooped);
204 0 : if (flags_ & NoNeighborAs)
205 0 : flags.push_back(NoNeighborAs);
206 0 : if (flags_ & Stale)
207 0 : flags.push_back(Stale);
208 0 : if (flags_ & NoTunnelEncap)
209 0 : flags.push_back(NoTunnelEncap);
210 0 : if (flags_ & OriginatorIdLooped)
211 0 : flags.push_back(OriginatorIdLooped);
212 0 : if (flags_ & ResolveNexthop)
213 0 : flags.push_back(ResolveNexthop);
214 0 : if (flags_ & ResolvedPath)
215 0 : flags.push_back(ResolvedPath);
216 0 : if (flags_ & RoutingPolicyReject)
217 0 : flags.push_back(RoutingPolicyReject);
218 0 : if (flags_ & LlgrStale)
219 0 : flags.push_back(LlgrStale);
220 0 : if (flags_ & ClusterListLooped)
221 0 : flags.push_back(ClusterListLooped);
222 0 : if (flags_ & AliasedPath)
223 0 : flags.push_back(AliasedPath);
224 0 : if (flags_ & CheckGlobalErmVpnRoute)
225 0 : flags.push_back(CheckGlobalErmVpnRoute);
226 :
227 0 : for (auto flag : flags) {
228 0 : switch (flag) {
229 0 : case AsPathLooped:
230 0 : flag_names.push_back("AsPathLooped");
231 0 : break;
232 0 : case NoNeighborAs:
233 0 : flag_names.push_back("NoNeighborAs");
234 0 : break;
235 0 : case Stale:
236 0 : flag_names.push_back("Stale");
237 0 : break;
238 0 : case NoTunnelEncap:
239 0 : flag_names.push_back("NoTunnelEncap");
240 0 : break;
241 0 : case OriginatorIdLooped:
242 0 : flag_names.push_back("OriginatorIdLooped");
243 0 : break;
244 0 : case ResolveNexthop:
245 0 : flag_names.push_back("ResolveNexthop");
246 0 : break;
247 0 : case ResolvedPath:
248 0 : flag_names.push_back("ResolvedPath");
249 0 : break;
250 0 : case RoutingPolicyReject:
251 0 : flag_names.push_back("RoutingPolicyReject");
252 0 : break;
253 0 : case LlgrStale:
254 0 : flag_names.push_back("LlgrStale");
255 0 : break;
256 0 : case ClusterListLooped:
257 0 : flag_names.push_back("ClusterListLooped");
258 0 : break;
259 0 : case AliasedPath:
260 0 : flag_names.push_back("AliasedPath");
261 0 : break;
262 0 : case CheckGlobalErmVpnRoute:
263 0 : flag_names.push_back("CheckGlobalErmVpnRoute");
264 0 : break;
265 : }
266 : }
267 0 : return flag_names;
268 0 : }
269 :
270 0 : string BgpPath::GetSourceString(bool combine_bgp_and_xmpp) const {
271 0 : switch (source_) {
272 0 : case None:
273 0 : return "None";
274 0 : case BGP_XMPP:
275 0 : if (combine_bgp_and_xmpp) {
276 0 : return "BGP_XMPP";
277 0 : } else if (peer_) {
278 0 : return(peer_->IsXmppPeer() ? "XMPP" : "BGP");
279 : } else {
280 0 : return "None";
281 : }
282 0 : case ServiceChain:
283 0 : return "ServiceChain";
284 0 : case StaticRoute:
285 0 : return "StaticRoute";
286 0 : case Aggregate:
287 0 : return "Aggregate";
288 0 : case Local:
289 0 : return "Local";
290 : }
291 0 : return "None";
292 : }
293 :
294 0 : BgpSecondaryPath::BgpSecondaryPath(const IPeer *peer, uint32_t path_id,
295 : PathSource src, const BgpAttrPtr ptr, uint32_t flags, uint32_t label,
296 0 : uint32_t l3_label)
297 0 : : BgpPath(peer, path_id, src, ptr, flags, label, l3_label) {
298 0 : }
299 :
300 0 : RouteDistinguisher BgpSecondaryPath::GetPrimaryRouteDistinguisher() const {
301 0 : 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 : }
|