blob: f2661a104090b32d2100e748c459ba48e655a47d [file] [log] [blame]
Charles Chan0214ded2016-11-18 17:48:37 -08001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Charles Chan0214ded2016-11-18 17:48: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 */
16
Ray Milkey69ec8712017-08-08 13:00:43 -070017package org.onosproject.routeservice.store;
Charles Chan0214ded2016-11-18 17:48:37 -080018
Jonathan Hart96c146b2017-02-24 16:32:00 -080019import com.google.common.collect.ImmutableSet;
pier8a86db22019-10-16 16:58:20 +020020import com.google.common.collect.Sets;
Charles Chan0214ded2016-11-18 17:48:37 -080021import org.onlab.packet.IpAddress;
22import org.onlab.packet.IpPrefix;
23import org.onlab.util.KryoNamespace;
Ray Milkey69ec8712017-08-08 13:00:43 -070024import org.onosproject.routeservice.InternalRouteEvent;
25import org.onosproject.routeservice.Route;
26import org.onosproject.routeservice.RouteSet;
27import org.onosproject.routeservice.RouteStore;
28import org.onosproject.routeservice.RouteStoreDelegate;
29import org.onosproject.routeservice.RouteTableId;
Charles Chan0214ded2016-11-18 17:48:37 -080030import org.onosproject.store.AbstractStore;
Jonathan Hart96c146b2017-02-24 16:32:00 -080031import org.onosproject.store.service.DistributedSet;
Charles Chan0214ded2016-11-18 17:48:37 -080032import org.onosproject.store.service.Serializer;
Jonathan Hart96c146b2017-02-24 16:32:00 -080033import org.onosproject.store.service.SetEvent;
34import org.onosproject.store.service.SetEventListener;
Charles Chan0214ded2016-11-18 17:48:37 -080035import org.onosproject.store.service.StorageService;
Charles Chan0214ded2016-11-18 17:48:37 -080036import org.slf4j.Logger;
37import org.slf4j.LoggerFactory;
38
39import java.util.Collection;
40import java.util.Collections;
pier8a86db22019-10-16 16:58:20 +020041import java.util.HashMap;
Charles Chan0214ded2016-11-18 17:48:37 -080042import java.util.Map;
43import java.util.Set;
Jonathan Hart96c146b2017-02-24 16:32:00 -080044import java.util.concurrent.ConcurrentHashMap;
45import java.util.concurrent.ExecutorService;
Charles Chan0214ded2016-11-18 17:48:37 -080046import java.util.concurrent.Executors;
pier8a86db22019-10-16 16:58:20 +020047import java.util.stream.Collectors;
Charles Chan0214ded2016-11-18 17:48:37 -080048
Jonathan Hart1f67d282017-05-25 14:23:01 -070049import static org.onlab.util.Tools.groupedThreads;
50
Charles Chan0214ded2016-11-18 17:48:37 -080051/**
52 * Route store based on distributed storage.
53 */
Jonathan Hart96c146b2017-02-24 16:32:00 -080054public class DistributedRouteStore extends AbstractStore<InternalRouteEvent, RouteStoreDelegate>
Charles Chan0214ded2016-11-18 17:48:37 -080055 implements RouteStore {
Jonathan Hart96c146b2017-02-24 16:32:00 -080056
57 protected StorageService storageService;
Charles Chan0214ded2016-11-18 17:48:37 -080058
59 private static final RouteTableId IPV4 = new RouteTableId("ipv4");
60 private static final RouteTableId IPV6 = new RouteTableId("ipv6");
61 private static final Logger log = LoggerFactory.getLogger(DistributedRouteStore.class);
Jonathan Hart96c146b2017-02-24 16:32:00 -080062 private final SetEventListener<RouteTableId> masterRouteTableListener =
63 new MasterRouteTableListener();
64 private final RouteStoreDelegate ourDelegate = new InternalRouteStoreDelegate();
Charles Chan0214ded2016-11-18 17:48:37 -080065
Jonathan Hart96c146b2017-02-24 16:32:00 -080066 // Stores the route tables that have been created
67 private DistributedSet<RouteTableId> masterRouteTable;
68 // Local memory map to store route table object
69 private Map<RouteTableId, RouteTable> routeTables;
Charles Chan0214ded2016-11-18 17:48:37 -080070
Jonathan Hart96c146b2017-02-24 16:32:00 -080071 private ExecutorService executor;
72
Charles Chan0214ded2016-11-18 17:48:37 -080073 public DistributedRouteStore(StorageService storageService) {
74 this.storageService = storageService;
75 }
76
77 /**
78 * Sets up distributed route store.
79 */
80 public void activate() {
Jonathan Hart96c146b2017-02-24 16:32:00 -080081 routeTables = new ConcurrentHashMap<>();
Jonathan Hart1f67d282017-05-25 14:23:01 -070082 executor = Executors.newSingleThreadExecutor(groupedThreads("onos/route", "store", log));
Charles Chan0214ded2016-11-18 17:48:37 -080083
Jonathan Hart96c146b2017-02-24 16:32:00 -080084 KryoNamespace masterRouteTableSerializer = KryoNamespace.newBuilder()
85 .register(RouteTableId.class)
86 .build();
87
88 masterRouteTable = storageService.<RouteTableId>setBuilder()
89 .withName("onos-master-route-table")
90 .withSerializer(Serializer.using(masterRouteTableSerializer))
91 .build()
92 .asDistributedSet();
93
Jonathan Hart96c146b2017-02-24 16:32:00 -080094 masterRouteTable.addListener(masterRouteTableListener);
95
96 // Add default tables (add is idempotent)
97 masterRouteTable.add(IPV4);
98 masterRouteTable.add(IPV6);
Charles Chan0214ded2016-11-18 17:48:37 -080099
Yi Tseng46654c32017-08-08 19:09:19 -0700100 masterRouteTable.forEach(this::createRouteTable);
101
Charles Chan0214ded2016-11-18 17:48:37 -0800102 log.info("Started");
103 }
104
105 /**
106 * Cleans up distributed route store.
107 */
108 public void deactivate() {
Jonathan Hart96c146b2017-02-24 16:32:00 -0800109 masterRouteTable.removeListener(masterRouteTableListener);
Charles Chan0214ded2016-11-18 17:48:37 -0800110
Jonathan Hart96c146b2017-02-24 16:32:00 -0800111 routeTables.values().forEach(RouteTable::shutdown);
Charles Chan0214ded2016-11-18 17:48:37 -0800112
113 log.info("Stopped");
114 }
115
116 @Override
117 public void updateRoute(Route route) {
Jonathan Hart96c146b2017-02-24 16:32:00 -0800118 getDefaultRouteTable(route).update(route);
Charles Chan0214ded2016-11-18 17:48:37 -0800119 }
120
121 @Override
pier8a86db22019-10-16 16:58:20 +0200122 public void updateRoutes(Collection<Route> routes) {
123 Map<RouteTableId, Set<Route>> computedTables = computeRouteTablesFromRoutes(routes);
124 computedTables.forEach(
125 ((routeTableId, routesToAdd) -> getDefaultRouteTable(routeTableId).update(routesToAdd))
126 );
127 }
128
129 @Override
Charles Chan0214ded2016-11-18 17:48:37 -0800130 public void removeRoute(Route route) {
Jonathan Hart96c146b2017-02-24 16:32:00 -0800131 getDefaultRouteTable(route).remove(route);
Charles Chan0214ded2016-11-18 17:48:37 -0800132 }
133
134 @Override
pier8a86db22019-10-16 16:58:20 +0200135 public void removeRoutes(Collection<Route> routes) {
136 Map<RouteTableId, Set<Route>> computedTables = computeRouteTablesFromRoutes(routes);
137 computedTables.forEach(
138 ((routeTableId, routesToRemove) -> getDefaultRouteTable(routeTableId).remove(routesToRemove))
139 );
140 }
141
142 @Override
Daniel Ginsburg83b76452018-06-09 01:43:59 +0300143 public void replaceRoute(Route route) {
144 getDefaultRouteTable(route).replace(route);
145 }
146
147 @Override
Charles Chan0214ded2016-11-18 17:48:37 -0800148 public Set<RouteTableId> getRouteTables() {
Jonathan Hart96c146b2017-02-24 16:32:00 -0800149 return ImmutableSet.copyOf(masterRouteTable);
Charles Chan0214ded2016-11-18 17:48:37 -0800150 }
151
152 @Override
Jonathan Hart96c146b2017-02-24 16:32:00 -0800153 public Collection<RouteSet> getRoutes(RouteTableId table) {
154 RouteTable routeTable = routeTables.get(table);
155 if (routeTable == null) {
156 return Collections.emptySet();
157 } else {
158 return ImmutableSet.copyOf(routeTable.getRoutes());
159 }
Charles Chan0214ded2016-11-18 17:48:37 -0800160 }
161
162 @Override
Charles Chan0214ded2016-11-18 17:48:37 -0800163 public Collection<Route> getRoutesForNextHop(IpAddress ip) {
Jonathan Hart96c146b2017-02-24 16:32:00 -0800164 return getDefaultRouteTable(ip).getRoutesForNextHop(ip);
165 }
166
167 @Override
pier8a86db22019-10-16 16:58:20 +0200168 public Collection<RouteSet> getRoutesForNextHops(Collection<IpAddress> nextHops) {
169 Map<RouteTableId, Set<IpAddress>> computedTables = computeRouteTablesFromIps(nextHops);
170 return computedTables.entrySet().stream()
171 .map(entry -> getDefaultRouteTable(entry.getKey()).getRoutesForNextHops(entry.getValue()))
172 .flatMap(Collection::stream)
173 .collect(Collectors.toList());
174 }
175
176 @Override
Jonathan Hart96c146b2017-02-24 16:32:00 -0800177 public RouteSet getRoutes(IpPrefix prefix) {
178 return getDefaultRouteTable(prefix.address()).getRoutes(prefix);
Charles Chan0214ded2016-11-18 17:48:37 -0800179 }
180
Jonathan Hart96c146b2017-02-24 16:32:00 -0800181 private void createRouteTable(RouteTableId tableId) {
Jonathan Hart1f67d282017-05-25 14:23:01 -0700182 routeTables.computeIfAbsent(tableId, id -> new DefaultRouteTable(id, ourDelegate, storageService, executor));
Charles Chan0214ded2016-11-18 17:48:37 -0800183 }
184
Jonathan Hart96c146b2017-02-24 16:32:00 -0800185 private void destroyRouteTable(RouteTableId tableId) {
186 RouteTable table = routeTables.remove(tableId);
187 if (table != null) {
188 table.destroy();
189 }
Charles Chan0214ded2016-11-18 17:48:37 -0800190 }
191
Jonathan Hart96c146b2017-02-24 16:32:00 -0800192 private RouteTable getDefaultRouteTable(Route route) {
Charles Chan0214ded2016-11-18 17:48:37 -0800193 return getDefaultRouteTable(route.prefix().address());
194 }
195
Jonathan Hart96c146b2017-02-24 16:32:00 -0800196 private RouteTable getDefaultRouteTable(IpAddress ip) {
Charles Chan0214ded2016-11-18 17:48:37 -0800197 RouteTableId routeTableId = (ip.isIp4()) ? IPV4 : IPV6;
Jonathan Hart96c146b2017-02-24 16:32:00 -0800198 return routeTables.getOrDefault(routeTableId, EmptyRouteTable.instance());
Charles Chan0214ded2016-11-18 17:48:37 -0800199 }
200
pier8a86db22019-10-16 16:58:20 +0200201 private RouteTable getDefaultRouteTable(RouteTableId routeTableId) {
202 return routeTables.getOrDefault(routeTableId, EmptyRouteTable.instance());
203 }
204
205 private Map<RouteTableId, Set<Route>> computeRouteTablesFromRoutes(Collection<Route> routes) {
206 Map<RouteTableId, Set<Route>> computedTables = new HashMap<>();
207 routes.forEach(route -> {
208 RouteTableId routeTableId = (route.prefix().address().isIp4()) ? IPV4 : IPV6;
209 Set<Route> tempRoutes = computedTables.computeIfAbsent(routeTableId, k -> Sets.newHashSet());
210 tempRoutes.add(route);
211 });
212 return computedTables;
213 }
214
215 private Map<RouteTableId, Set<IpAddress>> computeRouteTablesFromIps(Collection<IpAddress> ipAddresses) {
216 Map<RouteTableId, Set<IpAddress>> computedTables = new HashMap<>();
217 ipAddresses.forEach(ipAddress -> {
218 RouteTableId routeTableId = (ipAddress.isIp4()) ? IPV4 : IPV6;
219 Set<IpAddress> tempIpAddresses = computedTables.computeIfAbsent(routeTableId, k -> Sets.newHashSet());
220 tempIpAddresses.add(ipAddress);
221 });
222 return computedTables;
223 }
224
Jonathan Hart96c146b2017-02-24 16:32:00 -0800225 private class InternalRouteStoreDelegate implements RouteStoreDelegate {
Charles Chan0214ded2016-11-18 17:48:37 -0800226 @Override
Jonathan Hart96c146b2017-02-24 16:32:00 -0800227 public void notify(InternalRouteEvent event) {
228 executor.execute(() -> DistributedRouteStore.this.notifyDelegate(event));
Charles Chan0214ded2016-11-18 17:48:37 -0800229 }
230 }
231
Jonathan Hart96c146b2017-02-24 16:32:00 -0800232 private class MasterRouteTableListener implements SetEventListener<RouteTableId> {
Charles Chan0214ded2016-11-18 17:48:37 -0800233 @Override
Jonathan Hart96c146b2017-02-24 16:32:00 -0800234 public void event(SetEvent<RouteTableId> event) {
Charles Chan0214ded2016-11-18 17:48:37 -0800235 switch (event.type()) {
Jonathan Hart96c146b2017-02-24 16:32:00 -0800236 case ADD:
237 executor.execute(() -> createRouteTable(event.entry()));
238 break;
239 case REMOVE:
240 executor.execute(() -> destroyRouteTable(event.entry()));
241 break;
242 default:
243 break;
Charles Chan0214ded2016-11-18 17:48:37 -0800244 }
245 }
246 }
247}