blob: 259ae3cff896340b0dfe659dafbbd95073427c16 [file] [log] [blame]
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -08001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2017-present Open Networking Foundation
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -08003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Jonathan Hartf4bd0482017-01-27 15:11:18 -080016
Jonathan Hart41349e92015-02-09 14:14:02 -080017package org.onosproject.routing.bgp;
18
19import org.onlab.packet.IpPrefix;
Jonathan Hart10dbafd2017-05-18 15:53:03 -070020import org.onosproject.cluster.ClusterService;
Ray Milkey69ec8712017-08-08 13:00:43 -070021import org.onosproject.routeservice.Route;
Jonathan Hart41349e92015-02-09 14:14:02 -080022import org.slf4j.Logger;
23import org.slf4j.LoggerFactory;
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -080024
25import java.util.Collection;
26import java.util.LinkedList;
27
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -080028/**
29 * Class to receive and process the BGP routes from each BGP Session/Peer.
30 */
31class BgpRouteSelector {
32 private static final Logger log =
33 LoggerFactory.getLogger(BgpRouteSelector.class);
34
35 private BgpSessionManager bgpSessionManager;
Jonathan Hart10dbafd2017-05-18 15:53:03 -070036 private ClusterService clusterService;
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -080037
38 /**
39 * Constructor.
40 *
41 * @param bgpSessionManager the BGP Session Manager to use
Jonathan Hart10dbafd2017-05-18 15:53:03 -070042 * @param clusterService the cluster service
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -080043 */
Jonathan Hart10dbafd2017-05-18 15:53:03 -070044 BgpRouteSelector(BgpSessionManager bgpSessionManager, ClusterService clusterService) {
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -080045 this.bgpSessionManager = bgpSessionManager;
Jonathan Hart10dbafd2017-05-18 15:53:03 -070046 this.clusterService = clusterService;
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -080047 }
48
49 /**
50 * Processes route entry updates: added/updated and deleted route
51 * entries.
52 *
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -080053 * @param addedBgpRouteEntries the added/updated route entries to process
54 * @param deletedBgpRouteEntries the deleted route entries to process
55 */
Jonathan Hart1ad75f22016-04-13 21:24:13 -070056 synchronized void routeUpdates(
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -080057 Collection<BgpRouteEntry> addedBgpRouteEntries,
58 Collection<BgpRouteEntry> deletedBgpRouteEntries) {
Jonathan Hart1ad75f22016-04-13 21:24:13 -070059
60 Collection<Route> updates = new LinkedList<>();
61 Collection<Route> withdraws = new LinkedList<>();
62
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -080063 RouteUpdate routeUpdate;
64
65 if (bgpSessionManager.isShutdown()) {
66 return; // Ignore any leftover updates if shutdown
67 }
68 // Process the deleted route entries
69 for (BgpRouteEntry bgpRouteEntry : deletedBgpRouteEntries) {
Jonathan Hart1ad75f22016-04-13 21:24:13 -070070 routeUpdate = processDeletedRoute(bgpRouteEntry);
71 convertRouteUpdateToRoute(routeUpdate, updates, withdraws);
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -080072 }
73
74 // Process the added/updated route entries
75 for (BgpRouteEntry bgpRouteEntry : addedBgpRouteEntries) {
Jonathan Hart1ad75f22016-04-13 21:24:13 -070076 routeUpdate = processAddedRoute(bgpRouteEntry);
77 convertRouteUpdateToRoute(routeUpdate, updates, withdraws);
78 }
79
80 bgpSessionManager.withdraw(withdraws);
81 bgpSessionManager.update(updates);
82 }
83
84 private void convertRouteUpdateToRoute(RouteUpdate routeUpdate,
85 Collection<Route> updates,
86 Collection<Route> withdraws) {
87 if (routeUpdate != null) {
88 Route route = new Route(Route.Source.BGP, routeUpdate.routeEntry().prefix(),
Jonathan Hart10dbafd2017-05-18 15:53:03 -070089 routeUpdate.routeEntry().nextHop(), clusterService.getLocalNode().id());
Jonathan Hart1ad75f22016-04-13 21:24:13 -070090 if (routeUpdate.type().equals(RouteUpdate.Type.UPDATE)) {
91 updates.add(route);
92 } else if (routeUpdate.type().equals(RouteUpdate.Type.DELETE)) {
93 withdraws.add(route);
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -080094 }
95 }
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -080096 }
97
98 /**
99 * Processes an added/updated route entry.
100 *
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800101 * @param bgpRouteEntry the added/updated route entry
102 * @return the result route update that should be forwarded to the
103 * Route Listener, or null if no route update should be forwarded
104 */
Jonathan Hart1ad75f22016-04-13 21:24:13 -0700105 private RouteUpdate processAddedRoute(BgpRouteEntry bgpRouteEntry) {
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800106 RouteUpdate routeUpdate;
107 BgpRouteEntry bestBgpRouteEntry =
108 bgpSessionManager.findBgpRoute(bgpRouteEntry.prefix());
109
110 //
111 // Install the new route entry if it is better than the
112 // current best route.
113 //
114 if ((bestBgpRouteEntry == null) ||
115 bgpRouteEntry.isBetterThan(bestBgpRouteEntry)) {
116 bgpSessionManager.addBgpRoute(bgpRouteEntry);
117 routeUpdate =
118 new RouteUpdate(RouteUpdate.Type.UPDATE, bgpRouteEntry);
119 return routeUpdate;
120 }
121
122 //
123 // If the route entry arrived on the same BGP Session as
124 // the current best route, then elect the next best route
125 // and install it.
126 //
127 if (bestBgpRouteEntry.getBgpSession() !=
128 bgpRouteEntry.getBgpSession()) {
129 return null; // Nothing to do
130 }
131
132 // Find the next best route
133 bestBgpRouteEntry = findBestBgpRoute(bgpRouteEntry.prefix());
134 if (bestBgpRouteEntry == null) {
135 //
136 // TODO: Shouldn't happen. Install the new route as a
137 // pre-caution.
138 //
139 log.debug("BGP next best route for prefix {} is missing. " +
140 "Adding the route that is currently processed.",
141 bgpRouteEntry.prefix());
142 bestBgpRouteEntry = bgpRouteEntry;
143 }
144
145 // Install the next best route
146 bgpSessionManager.addBgpRoute(bestBgpRouteEntry);
147 routeUpdate = new RouteUpdate(RouteUpdate.Type.UPDATE,
148 bestBgpRouteEntry);
149 return routeUpdate;
150 }
151
152 /**
153 * Processes a deleted route entry.
154 *
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800155 * @param bgpRouteEntry the deleted route entry
156 * @return the result route update that should be forwarded to the
157 * Route Listener, or null if no route update should be forwarded
158 */
Jonathan Hart1ad75f22016-04-13 21:24:13 -0700159 private RouteUpdate processDeletedRoute(BgpRouteEntry bgpRouteEntry) {
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800160 RouteUpdate routeUpdate;
161 BgpRouteEntry bestBgpRouteEntry =
162 bgpSessionManager.findBgpRoute(bgpRouteEntry.prefix());
163
164 //
165 // Remove the route entry only if it was the best one.
166 // Install the the next best route if it exists.
167 //
168 // NOTE: We intentionally use "==" instead of method equals(),
169 // because we need to check whether this is same object.
170 //
171 if (bgpRouteEntry != bestBgpRouteEntry) {
172 return null; // Nothing to do
173 }
174
175 //
176 // Find the next best route
177 //
178 bestBgpRouteEntry = findBestBgpRoute(bgpRouteEntry.prefix());
179 if (bestBgpRouteEntry != null) {
180 // Install the next best route
181 bgpSessionManager.addBgpRoute(bestBgpRouteEntry);
182 routeUpdate = new RouteUpdate(RouteUpdate.Type.UPDATE,
183 bestBgpRouteEntry);
184 return routeUpdate;
185 }
186
187 //
188 // No route found. Remove the route entry
189 //
190 bgpSessionManager.removeBgpRoute(bgpRouteEntry.prefix());
191 routeUpdate = new RouteUpdate(RouteUpdate.Type.DELETE, bgpRouteEntry);
192 return routeUpdate;
193 }
194
195 /**
196 * Finds the best route entry among all BGP Sessions.
197 *
198 * @param prefix the prefix of the route
199 * @return the best route if found, otherwise null
200 */
201 private BgpRouteEntry findBestBgpRoute(IpPrefix prefix) {
202 BgpRouteEntry bestRoute = null;
203
204 // Iterate across all BGP Sessions and select the best route
205 for (BgpSession bgpSession : bgpSessionManager.getBgpSessions()) {
206 BgpRouteEntry route = bgpSession.findBgpRoute(prefix);
207 if (route == null) {
208 continue;
209 }
210 if ((bestRoute == null) || route.isBetterThan(bestRoute)) {
211 bestRoute = route;
212 }
213 }
214 return bestRoute;
215 }
216}