blob: 92c4e7dab93c0a67b26389e4194948c36c5b2d7b [file] [log] [blame]
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -08001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
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 Hart41349e92015-02-09 14:14:02 -080016package org.onosproject.routing.bgp;
17
18import org.onlab.packet.IpPrefix;
Jonathan Hart1ad75f22016-04-13 21:24:13 -070019import org.onosproject.incubator.net.routing.Route;
Jonathan Hart2da1e602015-02-18 19:09:24 -080020import org.onosproject.routing.RouteUpdate;
Jonathan Hart41349e92015-02-09 14:14:02 -080021import org.slf4j.Logger;
22import org.slf4j.LoggerFactory;
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -080023
24import java.util.Collection;
25import java.util.LinkedList;
26
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -080027/**
28 * Class to receive and process the BGP routes from each BGP Session/Peer.
29 */
30class BgpRouteSelector {
31 private static final Logger log =
32 LoggerFactory.getLogger(BgpRouteSelector.class);
33
34 private BgpSessionManager bgpSessionManager;
35
36 /**
37 * Constructor.
38 *
39 * @param bgpSessionManager the BGP Session Manager to use
40 */
41 BgpRouteSelector(BgpSessionManager bgpSessionManager) {
42 this.bgpSessionManager = bgpSessionManager;
43 }
44
45 /**
46 * Processes route entry updates: added/updated and deleted route
47 * entries.
48 *
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -080049 * @param addedBgpRouteEntries the added/updated route entries to process
50 * @param deletedBgpRouteEntries the deleted route entries to process
51 */
Jonathan Hart1ad75f22016-04-13 21:24:13 -070052 synchronized void routeUpdates(
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -080053 Collection<BgpRouteEntry> addedBgpRouteEntries,
54 Collection<BgpRouteEntry> deletedBgpRouteEntries) {
Jonathan Hart1ad75f22016-04-13 21:24:13 -070055
56 Collection<Route> updates = new LinkedList<>();
57 Collection<Route> withdraws = new LinkedList<>();
58
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -080059 RouteUpdate routeUpdate;
60
61 if (bgpSessionManager.isShutdown()) {
62 return; // Ignore any leftover updates if shutdown
63 }
64 // Process the deleted route entries
65 for (BgpRouteEntry bgpRouteEntry : deletedBgpRouteEntries) {
Jonathan Hart1ad75f22016-04-13 21:24:13 -070066 routeUpdate = processDeletedRoute(bgpRouteEntry);
67 convertRouteUpdateToRoute(routeUpdate, updates, withdraws);
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -080068 }
69
70 // Process the added/updated route entries
71 for (BgpRouteEntry bgpRouteEntry : addedBgpRouteEntries) {
Jonathan Hart1ad75f22016-04-13 21:24:13 -070072 routeUpdate = processAddedRoute(bgpRouteEntry);
73 convertRouteUpdateToRoute(routeUpdate, updates, withdraws);
74 }
75
76 bgpSessionManager.withdraw(withdraws);
77 bgpSessionManager.update(updates);
78 }
79
80 private void convertRouteUpdateToRoute(RouteUpdate routeUpdate,
81 Collection<Route> updates,
82 Collection<Route> withdraws) {
83 if (routeUpdate != null) {
84 Route route = new Route(Route.Source.BGP, routeUpdate.routeEntry().prefix(),
85 routeUpdate.routeEntry().nextHop());
86 if (routeUpdate.type().equals(RouteUpdate.Type.UPDATE)) {
87 updates.add(route);
88 } else if (routeUpdate.type().equals(RouteUpdate.Type.DELETE)) {
89 withdraws.add(route);
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -080090 }
91 }
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -080092 }
93
94 /**
95 * Processes an added/updated route entry.
96 *
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -080097 * @param bgpRouteEntry the added/updated route entry
98 * @return the result route update that should be forwarded to the
99 * Route Listener, or null if no route update should be forwarded
100 */
Jonathan Hart1ad75f22016-04-13 21:24:13 -0700101 private RouteUpdate processAddedRoute(BgpRouteEntry bgpRouteEntry) {
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800102 RouteUpdate routeUpdate;
103 BgpRouteEntry bestBgpRouteEntry =
104 bgpSessionManager.findBgpRoute(bgpRouteEntry.prefix());
105
106 //
107 // Install the new route entry if it is better than the
108 // current best route.
109 //
110 if ((bestBgpRouteEntry == null) ||
111 bgpRouteEntry.isBetterThan(bestBgpRouteEntry)) {
112 bgpSessionManager.addBgpRoute(bgpRouteEntry);
113 routeUpdate =
114 new RouteUpdate(RouteUpdate.Type.UPDATE, bgpRouteEntry);
115 return routeUpdate;
116 }
117
118 //
119 // If the route entry arrived on the same BGP Session as
120 // the current best route, then elect the next best route
121 // and install it.
122 //
123 if (bestBgpRouteEntry.getBgpSession() !=
124 bgpRouteEntry.getBgpSession()) {
125 return null; // Nothing to do
126 }
127
128 // Find the next best route
129 bestBgpRouteEntry = findBestBgpRoute(bgpRouteEntry.prefix());
130 if (bestBgpRouteEntry == null) {
131 //
132 // TODO: Shouldn't happen. Install the new route as a
133 // pre-caution.
134 //
135 log.debug("BGP next best route for prefix {} is missing. " +
136 "Adding the route that is currently processed.",
137 bgpRouteEntry.prefix());
138 bestBgpRouteEntry = bgpRouteEntry;
139 }
140
141 // Install the next best route
142 bgpSessionManager.addBgpRoute(bestBgpRouteEntry);
143 routeUpdate = new RouteUpdate(RouteUpdate.Type.UPDATE,
144 bestBgpRouteEntry);
145 return routeUpdate;
146 }
147
148 /**
149 * Processes a deleted route entry.
150 *
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800151 * @param bgpRouteEntry the deleted route entry
152 * @return the result route update that should be forwarded to the
153 * Route Listener, or null if no route update should be forwarded
154 */
Jonathan Hart1ad75f22016-04-13 21:24:13 -0700155 private RouteUpdate processDeletedRoute(BgpRouteEntry bgpRouteEntry) {
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800156 RouteUpdate routeUpdate;
157 BgpRouteEntry bestBgpRouteEntry =
158 bgpSessionManager.findBgpRoute(bgpRouteEntry.prefix());
159
160 //
161 // Remove the route entry only if it was the best one.
162 // Install the the next best route if it exists.
163 //
164 // NOTE: We intentionally use "==" instead of method equals(),
165 // because we need to check whether this is same object.
166 //
167 if (bgpRouteEntry != bestBgpRouteEntry) {
168 return null; // Nothing to do
169 }
170
171 //
172 // Find the next best route
173 //
174 bestBgpRouteEntry = findBestBgpRoute(bgpRouteEntry.prefix());
175 if (bestBgpRouteEntry != null) {
176 // Install the next best route
177 bgpSessionManager.addBgpRoute(bestBgpRouteEntry);
178 routeUpdate = new RouteUpdate(RouteUpdate.Type.UPDATE,
179 bestBgpRouteEntry);
180 return routeUpdate;
181 }
182
183 //
184 // No route found. Remove the route entry
185 //
186 bgpSessionManager.removeBgpRoute(bgpRouteEntry.prefix());
187 routeUpdate = new RouteUpdate(RouteUpdate.Type.DELETE, bgpRouteEntry);
188 return routeUpdate;
189 }
190
191 /**
192 * Finds the best route entry among all BGP Sessions.
193 *
194 * @param prefix the prefix of the route
195 * @return the best route if found, otherwise null
196 */
197 private BgpRouteEntry findBestBgpRoute(IpPrefix prefix) {
198 BgpRouteEntry bestRoute = null;
199
200 // Iterate across all BGP Sessions and select the best route
201 for (BgpSession bgpSession : bgpSessionManager.getBgpSessions()) {
202 BgpRouteEntry route = bgpSession.findBgpRoute(prefix);
203 if (route == null) {
204 continue;
205 }
206 if ((bestRoute == null) || route.isBetterThan(bestRoute)) {
207 bestRoute = route;
208 }
209 }
210 return bestRoute;
211 }
212}