blob: 508c2f1266b83230322a8eb41016887813bee38f [file] [log] [blame]
Jonathan Hartbfc5c482016-04-05 18:57:00 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2016-present Open Networking Laboratory
Jonathan Hartbfc5c482016-04-05 18:57:00 -07003 *
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 */
16
17package org.onosproject.incubator.store.routing.impl;
18
Jonathan Hartfd176612016-04-11 10:42:10 -070019import com.googlecode.concurrenttrees.common.KeyValuePair;
Jonathan Hartbfc5c482016-04-05 18:57:00 -070020import com.googlecode.concurrenttrees.radix.node.concrete.DefaultByteArrayNodeFactory;
21import com.googlecode.concurrenttrees.radixinverted.ConcurrentInvertedRadixTree;
22import com.googlecode.concurrenttrees.radixinverted.InvertedRadixTree;
Jonathan Hartbfc5c482016-04-05 18:57:00 -070023import org.onlab.packet.IpAddress;
24import org.onlab.packet.IpPrefix;
Jonathan Hart96c146b2017-02-24 16:32:00 -080025import org.onosproject.incubator.net.routing.InternalRouteEvent;
Charles Chan8fe9f4c2016-10-24 16:46:25 -070026import org.onosproject.incubator.net.routing.NextHopData;
Jonathan Hartbfc5c482016-04-05 18:57:00 -070027import org.onosproject.incubator.net.routing.Route;
Jonathan Hart96c146b2017-02-24 16:32:00 -080028import org.onosproject.incubator.net.routing.RouteSet;
Jonathan Hartbfc5c482016-04-05 18:57:00 -070029import org.onosproject.incubator.net.routing.RouteStore;
30import org.onosproject.incubator.net.routing.RouteStoreDelegate;
31import org.onosproject.incubator.net.routing.RouteTableId;
32import org.onosproject.store.AbstractStore;
Jonathan Hartfd176612016-04-11 10:42:10 -070033import org.slf4j.Logger;
34import org.slf4j.LoggerFactory;
Jonathan Hartbfc5c482016-04-05 18:57:00 -070035
36import java.util.Collection;
37import java.util.Collections;
38import java.util.Iterator;
Jonathan Hartfd176612016-04-11 10:42:10 -070039import java.util.LinkedList;
40import java.util.List;
Jonathan Hartbfc5c482016-04-05 18:57:00 -070041import java.util.Map;
42import java.util.Set;
43import java.util.concurrent.ConcurrentHashMap;
Jonathan Hart96c146b2017-02-24 16:32:00 -080044import java.util.stream.Collectors;
Jonathan Hartbfc5c482016-04-05 18:57:00 -070045
Charles Chanb21d69a2016-11-11 17:46:14 -080046import static com.google.common.base.Preconditions.checkNotNull;
Jonathan Hartc4c2d622017-02-10 14:13:57 -080047import static org.onosproject.incubator.net.routing.RouteTools.createBinaryString;
Charles Chanb21d69a2016-11-11 17:46:14 -080048
Jonathan Hartbfc5c482016-04-05 18:57:00 -070049/**
50 * Route store based on in-memory storage.
51 */
Jonathan Hart96c146b2017-02-24 16:32:00 -080052public class LocalRouteStore extends AbstractStore<InternalRouteEvent, RouteStoreDelegate>
Jonathan Hartbfc5c482016-04-05 18:57:00 -070053 implements RouteStore {
54
Jonathan Hartfd176612016-04-11 10:42:10 -070055 private Logger log = LoggerFactory.getLogger(getClass());
56
Jonathan Hartbfc5c482016-04-05 18:57:00 -070057 private Map<RouteTableId, RouteTable> routeTables;
58 private static final RouteTableId IPV4 = new RouteTableId("ipv4");
59 private static final RouteTableId IPV6 = new RouteTableId("ipv6");
60
Charles Chan0214ded2016-11-18 17:48:37 -080061 /**
62 * Sets up local route store.
63 */
Jonathan Hart6c2e7962016-04-11 13:54:09 -070064 public void activate() {
Jonathan Hartbfc5c482016-04-05 18:57:00 -070065 routeTables = new ConcurrentHashMap<>();
66
Jonathan Hart96c146b2017-02-24 16:32:00 -080067 routeTables.put(IPV4, new RouteTable(IPV4));
68 routeTables.put(IPV6, new RouteTable(IPV6));
Charles Chan0214ded2016-11-18 17:48:37 -080069
70 log.info("Started");
71 }
72
73 /**
Jonathan Hart96c146b2017-02-24 16:32:00 -080074 * Cleans up local route store.
Charles Chan0214ded2016-11-18 17:48:37 -080075 */
76 public void deactivate() {
77 log.info("Stopped");
Jonathan Hartbfc5c482016-04-05 18:57:00 -070078 }
79
80 @Override
81 public void updateRoute(Route route) {
82 getDefaultRouteTable(route).update(route);
83 }
84
85 @Override
86 public void removeRoute(Route route) {
Jonathan Hart96c146b2017-02-24 16:32:00 -080087 getDefaultRouteTable(route).remove(route);
Jonathan Hartbfc5c482016-04-05 18:57:00 -070088 }
89
90 @Override
91 public Set<RouteTableId> getRouteTables() {
92 return routeTables.keySet();
93 }
94
95 @Override
Jonathan Hart96c146b2017-02-24 16:32:00 -080096 public Collection<RouteSet> getRoutes(RouteTableId table) {
Jonathan Hartbfc5c482016-04-05 18:57:00 -070097 RouteTable routeTable = routeTables.get(table);
Jonathan Hart96c146b2017-02-24 16:32:00 -080098 if (routeTable != null) {
99 return routeTable.getRouteSets();
Jonathan Hartbfc5c482016-04-05 18:57:00 -0700100 }
Jonathan Hart96c146b2017-02-24 16:32:00 -0800101 return null;
Jonathan Hartbfc5c482016-04-05 18:57:00 -0700102 }
103
104 @Override
105 public Route longestPrefixMatch(IpAddress ip) {
106 return getDefaultRouteTable(ip).longestPrefixMatch(ip);
107 }
108
109 @Override
Jonathan Hartfd176612016-04-11 10:42:10 -0700110 public Collection<Route> getRoutesForNextHop(IpAddress ip) {
111 return getDefaultRouteTable(ip).getRoutesForNextHop(ip);
112 }
113
114 @Override
Jonathan Hart96c146b2017-02-24 16:32:00 -0800115 public RouteSet getRoutes(IpPrefix prefix) {
116 return getDefaultRouteTable(prefix.address()).getRoutes(prefix);
117 }
118
119 @Override
Charles Chan8fe9f4c2016-10-24 16:46:25 -0700120 public void updateNextHop(IpAddress ip, NextHopData nextHopData) {
Jonathan Hart96c146b2017-02-24 16:32:00 -0800121 // No longer needed
Jonathan Hartbfc5c482016-04-05 18:57:00 -0700122 }
123
124 @Override
Charles Chan8fe9f4c2016-10-24 16:46:25 -0700125 public void removeNextHop(IpAddress ip, NextHopData nextHopData) {
Jonathan Hart96c146b2017-02-24 16:32:00 -0800126 // No longer needed
Jonathan Hartbfc5c482016-04-05 18:57:00 -0700127 }
128
129 @Override
Charles Chan8fe9f4c2016-10-24 16:46:25 -0700130 public NextHopData getNextHop(IpAddress ip) {
Jonathan Hart96c146b2017-02-24 16:32:00 -0800131 // No longer needed
132 return null;
Jonathan Hartbfc5c482016-04-05 18:57:00 -0700133 }
134
Jonathan Hartfd176612016-04-11 10:42:10 -0700135 @Override
Charles Chan8fe9f4c2016-10-24 16:46:25 -0700136 public Map<IpAddress, NextHopData> getNextHops() {
Jonathan Hart96c146b2017-02-24 16:32:00 -0800137 // No longer needed
138 return Collections.emptyMap();
Jonathan Hartfd176612016-04-11 10:42:10 -0700139 }
140
Jonathan Hartbfc5c482016-04-05 18:57:00 -0700141 private RouteTable getDefaultRouteTable(Route route) {
142 return getDefaultRouteTable(route.prefix().address());
143 }
144
145 private RouteTable getDefaultRouteTable(IpAddress ip) {
146 RouteTableId routeTableId = (ip.isIp4()) ? IPV4 : IPV6;
147 return routeTables.get(routeTableId);
148 }
149
Jonathan Hartbfc5c482016-04-05 18:57:00 -0700150 /**
151 * Route table into which routes can be placed.
152 */
153 private class RouteTable {
154 private final InvertedRadixTree<Route> routeTable;
Jonathan Hartbfc5c482016-04-05 18:57:00 -0700155 private final Map<IpPrefix, Route> routes = new ConcurrentHashMap<>();
Jonathan Hart96c146b2017-02-24 16:32:00 -0800156 private final RouteTableId id;
Jonathan Hartbfc5c482016-04-05 18:57:00 -0700157
158 /**
159 * Creates a new route table.
160 */
Jonathan Hart96c146b2017-02-24 16:32:00 -0800161 public RouteTable(RouteTableId id) {
162 this.id = checkNotNull(id);
Jonathan Hartbfc5c482016-04-05 18:57:00 -0700163 routeTable = new ConcurrentInvertedRadixTree<>(
164 new DefaultByteArrayNodeFactory());
165 }
166
167 /**
168 * Adds or updates the route in the route table.
169 *
170 * @param route route to update
171 */
172 public void update(Route route) {
173 synchronized (this) {
174 Route oldRoute = routes.put(route.prefix(), route);
Charles Chanb21d69a2016-11-11 17:46:14 -0800175
176 // No need to proceed if the new route is the same
177 if (route.equals(oldRoute)) {
178 return;
179 }
180
Jonathan Hartbfc5c482016-04-05 18:57:00 -0700181 routeTable.put(createBinaryString(route.prefix()), route);
182
Jonathan Hart96c146b2017-02-24 16:32:00 -0800183 notifyDelegate(new InternalRouteEvent(
184 InternalRouteEvent.Type.ROUTE_ADDED, singletonRouteSet(route)));
Jonathan Hartbfc5c482016-04-05 18:57:00 -0700185 }
186 }
187
188 /**
189 * Removes the route from the route table.
190 *
191 * @param route route to remove
192 */
193 public void remove(Route route) {
194 synchronized (this) {
195 Route removed = routes.remove(route.prefix());
196 routeTable.remove(createBinaryString(route.prefix()));
Jonathan Hartbfc5c482016-04-05 18:57:00 -0700197
198 if (removed != null) {
Jonathan Hart96c146b2017-02-24 16:32:00 -0800199 notifyDelegate(new InternalRouteEvent(
200 InternalRouteEvent.Type.ROUTE_REMOVED, emptyRouteSet(route.prefix())));
Jonathan Hartbfc5c482016-04-05 18:57:00 -0700201 }
202 }
203 }
204
205 /**
206 * Returns the routes pointing to a particular next hop.
207 *
208 * @param ip next hop IP address
209 * @return routes for the next hop
210 */
211 public Collection<Route> getRoutesForNextHop(IpAddress ip) {
Jonathan Hart96c146b2017-02-24 16:32:00 -0800212 return routes.values()
213 .stream()
214 .filter(route -> route.nextHop().equals(ip))
215 .collect(Collectors.toSet());
216 }
217
218 public RouteSet getRoutes(IpPrefix prefix) {
219 Route route = routes.get(prefix);
220 if (route != null) {
221 return singletonRouteSet(route);
222 }
223 return null;
224 }
225
226 public Collection<RouteSet> getRouteSets() {
227 return routes.values().stream()
228 .map(this::singletonRouteSet)
229 .collect(Collectors.toSet());
Jonathan Hartbfc5c482016-04-05 18:57:00 -0700230 }
231
232 /**
233 * Returns all routes in the route table.
234 *
235 * @return all routes
236 */
237 public Collection<Route> getRoutes() {
Jonathan Hartfd176612016-04-11 10:42:10 -0700238 Iterator<KeyValuePair<Route>> it =
239 routeTable.getKeyValuePairsForKeysStartingWith("").iterator();
240
241 List<Route> routes = new LinkedList<>();
242
243 while (it.hasNext()) {
244 KeyValuePair<Route> entry = it.next();
245 routes.add(entry.getValue());
246 }
247
248 return routes;
Jonathan Hartbfc5c482016-04-05 18:57:00 -0700249 }
250
251 /**
252 * Performs a longest prefix match with the given IP in the route table.
253 *
254 * @param ip IP address to look up
255 * @return most specific prefix containing the given
256 */
257 public Route longestPrefixMatch(IpAddress ip) {
258 Iterable<Route> prefixes =
259 routeTable.getValuesForKeysPrefixing(createBinaryString(ip.toIpPrefix()));
260
261 Iterator<Route> it = prefixes.iterator();
262
263 Route route = null;
264 while (it.hasNext()) {
265 route = it.next();
266 }
267
268 return route;
269 }
Jonathan Hart96c146b2017-02-24 16:32:00 -0800270
271 private RouteSet singletonRouteSet(Route route) {
272 return new RouteSet(id, route.prefix(), Collections.singleton(route));
273 }
274
275 private RouteSet emptyRouteSet(IpPrefix prefix) {
276 return new RouteSet(id, prefix, Collections.emptySet());
277 }
Jonathan Hartbfc5c482016-04-05 18:57:00 -0700278 }
279
280}