blob: 36b4b6efc3a89e01a4c2decba0522aa9bfda6ce2 [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 Hart41349e92015-02-09 14:14:02 -080020import org.slf4j.Logger;
21import org.slf4j.LoggerFactory;
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -080022
23import java.util.Collection;
24import java.util.LinkedList;
25
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -080026/**
27 * Class to receive and process the BGP routes from each BGP Session/Peer.
28 */
29class BgpRouteSelector {
30 private static final Logger log =
31 LoggerFactory.getLogger(BgpRouteSelector.class);
32
33 private BgpSessionManager bgpSessionManager;
34
35 /**
36 * Constructor.
37 *
38 * @param bgpSessionManager the BGP Session Manager to use
39 */
40 BgpRouteSelector(BgpSessionManager bgpSessionManager) {
41 this.bgpSessionManager = bgpSessionManager;
42 }
43
44 /**
45 * Processes route entry updates: added/updated and deleted route
46 * entries.
47 *
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -080048 * @param addedBgpRouteEntries the added/updated route entries to process
49 * @param deletedBgpRouteEntries the deleted route entries to process
50 */
Jonathan Hart1ad75f22016-04-13 21:24:13 -070051 synchronized void routeUpdates(
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -080052 Collection<BgpRouteEntry> addedBgpRouteEntries,
53 Collection<BgpRouteEntry> deletedBgpRouteEntries) {
Jonathan Hart1ad75f22016-04-13 21:24:13 -070054
55 Collection<Route> updates = new LinkedList<>();
56 Collection<Route> withdraws = new LinkedList<>();
57
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -080058 RouteUpdate routeUpdate;
59
60 if (bgpSessionManager.isShutdown()) {
61 return; // Ignore any leftover updates if shutdown
62 }
63 // Process the deleted route entries
64 for (BgpRouteEntry bgpRouteEntry : deletedBgpRouteEntries) {
Jonathan Hart1ad75f22016-04-13 21:24:13 -070065 routeUpdate = processDeletedRoute(bgpRouteEntry);
66 convertRouteUpdateToRoute(routeUpdate, updates, withdraws);
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -080067 }
68
69 // Process the added/updated route entries
70 for (BgpRouteEntry bgpRouteEntry : addedBgpRouteEntries) {
Jonathan Hart1ad75f22016-04-13 21:24:13 -070071 routeUpdate = processAddedRoute(bgpRouteEntry);
72 convertRouteUpdateToRoute(routeUpdate, updates, withdraws);
73 }
74
75 bgpSessionManager.withdraw(withdraws);
76 bgpSessionManager.update(updates);
77 }
78
79 private void convertRouteUpdateToRoute(RouteUpdate routeUpdate,
80 Collection<Route> updates,
81 Collection<Route> withdraws) {
82 if (routeUpdate != null) {
83 Route route = new Route(Route.Source.BGP, routeUpdate.routeEntry().prefix(),
84 routeUpdate.routeEntry().nextHop());
85 if (routeUpdate.type().equals(RouteUpdate.Type.UPDATE)) {
86 updates.add(route);
87 } else if (routeUpdate.type().equals(RouteUpdate.Type.DELETE)) {
88 withdraws.add(route);
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -080089 }
90 }
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -080091 }
92
93 /**
94 * Processes an added/updated route entry.
95 *
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -080096 * @param bgpRouteEntry the added/updated route entry
97 * @return the result route update that should be forwarded to the
98 * Route Listener, or null if no route update should be forwarded
99 */
Jonathan Hart1ad75f22016-04-13 21:24:13 -0700100 private RouteUpdate processAddedRoute(BgpRouteEntry bgpRouteEntry) {
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800101 RouteUpdate routeUpdate;
102 BgpRouteEntry bestBgpRouteEntry =
103 bgpSessionManager.findBgpRoute(bgpRouteEntry.prefix());
104
105 //
106 // Install the new route entry if it is better than the
107 // current best route.
108 //
109 if ((bestBgpRouteEntry == null) ||
110 bgpRouteEntry.isBetterThan(bestBgpRouteEntry)) {
111 bgpSessionManager.addBgpRoute(bgpRouteEntry);
112 routeUpdate =
113 new RouteUpdate(RouteUpdate.Type.UPDATE, bgpRouteEntry);
114 return routeUpdate;
115 }
116
117 //
118 // If the route entry arrived on the same BGP Session as
119 // the current best route, then elect the next best route
120 // and install it.
121 //
122 if (bestBgpRouteEntry.getBgpSession() !=
123 bgpRouteEntry.getBgpSession()) {
124 return null; // Nothing to do
125 }
126
127 // Find the next best route
128 bestBgpRouteEntry = findBestBgpRoute(bgpRouteEntry.prefix());
129 if (bestBgpRouteEntry == null) {
130 //
131 // TODO: Shouldn't happen. Install the new route as a
132 // pre-caution.
133 //
134 log.debug("BGP next best route for prefix {} is missing. " +
135 "Adding the route that is currently processed.",
136 bgpRouteEntry.prefix());
137 bestBgpRouteEntry = bgpRouteEntry;
138 }
139
140 // Install the next best route
141 bgpSessionManager.addBgpRoute(bestBgpRouteEntry);
142 routeUpdate = new RouteUpdate(RouteUpdate.Type.UPDATE,
143 bestBgpRouteEntry);
144 return routeUpdate;
145 }
146
147 /**
148 * Processes a deleted route entry.
149 *
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800150 * @param bgpRouteEntry the deleted route entry
151 * @return the result route update that should be forwarded to the
152 * Route Listener, or null if no route update should be forwarded
153 */
Jonathan Hart1ad75f22016-04-13 21:24:13 -0700154 private RouteUpdate processDeletedRoute(BgpRouteEntry bgpRouteEntry) {
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800155 RouteUpdate routeUpdate;
156 BgpRouteEntry bestBgpRouteEntry =
157 bgpSessionManager.findBgpRoute(bgpRouteEntry.prefix());
158
159 //
160 // Remove the route entry only if it was the best one.
161 // Install the the next best route if it exists.
162 //
163 // NOTE: We intentionally use "==" instead of method equals(),
164 // because we need to check whether this is same object.
165 //
166 if (bgpRouteEntry != bestBgpRouteEntry) {
167 return null; // Nothing to do
168 }
169
170 //
171 // Find the next best route
172 //
173 bestBgpRouteEntry = findBestBgpRoute(bgpRouteEntry.prefix());
174 if (bestBgpRouteEntry != null) {
175 // Install the next best route
176 bgpSessionManager.addBgpRoute(bestBgpRouteEntry);
177 routeUpdate = new RouteUpdate(RouteUpdate.Type.UPDATE,
178 bestBgpRouteEntry);
179 return routeUpdate;
180 }
181
182 //
183 // No route found. Remove the route entry
184 //
185 bgpSessionManager.removeBgpRoute(bgpRouteEntry.prefix());
186 routeUpdate = new RouteUpdate(RouteUpdate.Type.DELETE, bgpRouteEntry);
187 return routeUpdate;
188 }
189
190 /**
191 * Finds the best route entry among all BGP Sessions.
192 *
193 * @param prefix the prefix of the route
194 * @return the best route if found, otherwise null
195 */
196 private BgpRouteEntry findBestBgpRoute(IpPrefix prefix) {
197 BgpRouteEntry bestRoute = null;
198
199 // Iterate across all BGP Sessions and select the best route
200 for (BgpSession bgpSession : bgpSessionManager.getBgpSessions()) {
201 BgpRouteEntry route = bgpSession.findBgpRoute(prefix);
202 if (route == null) {
203 continue;
204 }
205 if ((bestRoute == null) || route.isBetterThan(bestRoute)) {
206 bestRoute = route;
207 }
208 }
209 return bestRoute;
210 }
211}