blob: 01d0f41eee278378e2b20f7fb097c017f4c68cf2 [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 Hart2da1e602015-02-18 19:09:24 -080019import org.onosproject.routing.RouteUpdate;
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 *
48 * @param bgpSession the BGP session the route entry updates were
49 * received on
50 * @param addedBgpRouteEntries the added/updated route entries to process
51 * @param deletedBgpRouteEntries the deleted route entries to process
52 */
53 synchronized void routeUpdates(BgpSession bgpSession,
54 Collection<BgpRouteEntry> addedBgpRouteEntries,
55 Collection<BgpRouteEntry> deletedBgpRouteEntries) {
56 Collection<RouteUpdate> routeUpdates = new LinkedList<>();
57 RouteUpdate routeUpdate;
58
59 if (bgpSessionManager.isShutdown()) {
60 return; // Ignore any leftover updates if shutdown
61 }
62 // Process the deleted route entries
63 for (BgpRouteEntry bgpRouteEntry : deletedBgpRouteEntries) {
64 routeUpdate = processDeletedRoute(bgpSession, bgpRouteEntry);
65 if (routeUpdate != null) {
66 routeUpdates.add(routeUpdate);
67 }
68 }
69
70 // Process the added/updated route entries
71 for (BgpRouteEntry bgpRouteEntry : addedBgpRouteEntries) {
72 routeUpdate = processAddedRoute(bgpSession, bgpRouteEntry);
73 if (routeUpdate != null) {
74 routeUpdates.add(routeUpdate);
75 }
76 }
77 bgpSessionManager.getRouteListener().update(routeUpdates);
78 }
79
80 /**
81 * Processes an added/updated route entry.
82 *
83 * @param bgpSession the BGP session the route entry update was received on
84 * @param bgpRouteEntry the added/updated route entry
85 * @return the result route update that should be forwarded to the
86 * Route Listener, or null if no route update should be forwarded
87 */
88 private RouteUpdate processAddedRoute(BgpSession bgpSession,
89 BgpRouteEntry bgpRouteEntry) {
90 RouteUpdate routeUpdate;
91 BgpRouteEntry bestBgpRouteEntry =
92 bgpSessionManager.findBgpRoute(bgpRouteEntry.prefix());
93
94 //
95 // Install the new route entry if it is better than the
96 // current best route.
97 //
98 if ((bestBgpRouteEntry == null) ||
99 bgpRouteEntry.isBetterThan(bestBgpRouteEntry)) {
100 bgpSessionManager.addBgpRoute(bgpRouteEntry);
101 routeUpdate =
102 new RouteUpdate(RouteUpdate.Type.UPDATE, bgpRouteEntry);
103 return routeUpdate;
104 }
105
106 //
107 // If the route entry arrived on the same BGP Session as
108 // the current best route, then elect the next best route
109 // and install it.
110 //
111 if (bestBgpRouteEntry.getBgpSession() !=
112 bgpRouteEntry.getBgpSession()) {
113 return null; // Nothing to do
114 }
115
116 // Find the next best route
117 bestBgpRouteEntry = findBestBgpRoute(bgpRouteEntry.prefix());
118 if (bestBgpRouteEntry == null) {
119 //
120 // TODO: Shouldn't happen. Install the new route as a
121 // pre-caution.
122 //
123 log.debug("BGP next best route for prefix {} is missing. " +
124 "Adding the route that is currently processed.",
125 bgpRouteEntry.prefix());
126 bestBgpRouteEntry = bgpRouteEntry;
127 }
128
129 // Install the next best route
130 bgpSessionManager.addBgpRoute(bestBgpRouteEntry);
131 routeUpdate = new RouteUpdate(RouteUpdate.Type.UPDATE,
132 bestBgpRouteEntry);
133 return routeUpdate;
134 }
135
136 /**
137 * Processes a deleted route entry.
138 *
139 * @param bgpSession the BGP session the route entry update was received on
140 * @param bgpRouteEntry the deleted route entry
141 * @return the result route update that should be forwarded to the
142 * Route Listener, or null if no route update should be forwarded
143 */
144 private RouteUpdate processDeletedRoute(BgpSession bgpSession,
145 BgpRouteEntry bgpRouteEntry) {
146 RouteUpdate routeUpdate;
147 BgpRouteEntry bestBgpRouteEntry =
148 bgpSessionManager.findBgpRoute(bgpRouteEntry.prefix());
149
150 //
151 // Remove the route entry only if it was the best one.
152 // Install the the next best route if it exists.
153 //
154 // NOTE: We intentionally use "==" instead of method equals(),
155 // because we need to check whether this is same object.
156 //
157 if (bgpRouteEntry != bestBgpRouteEntry) {
158 return null; // Nothing to do
159 }
160
161 //
162 // Find the next best route
163 //
164 bestBgpRouteEntry = findBestBgpRoute(bgpRouteEntry.prefix());
165 if (bestBgpRouteEntry != null) {
166 // Install the next best route
167 bgpSessionManager.addBgpRoute(bestBgpRouteEntry);
168 routeUpdate = new RouteUpdate(RouteUpdate.Type.UPDATE,
169 bestBgpRouteEntry);
170 return routeUpdate;
171 }
172
173 //
174 // No route found. Remove the route entry
175 //
176 bgpSessionManager.removeBgpRoute(bgpRouteEntry.prefix());
177 routeUpdate = new RouteUpdate(RouteUpdate.Type.DELETE, bgpRouteEntry);
178 return routeUpdate;
179 }
180
181 /**
182 * Finds the best route entry among all BGP Sessions.
183 *
184 * @param prefix the prefix of the route
185 * @return the best route if found, otherwise null
186 */
187 private BgpRouteEntry findBestBgpRoute(IpPrefix prefix) {
188 BgpRouteEntry bestRoute = null;
189
190 // Iterate across all BGP Sessions and select the best route
191 for (BgpSession bgpSession : bgpSessionManager.getBgpSessions()) {
192 BgpRouteEntry route = bgpSession.findBgpRoute(prefix);
193 if (route == null) {
194 continue;
195 }
196 if ((bestRoute == null) || route.isBetterThan(bestRoute)) {
197 bestRoute = route;
198 }
199 }
200 return bestRoute;
201 }
202}