blob: efdb79268efafa241d790a4001f83b855251a946 [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;
Charles Chan0214ded2016-11-18 17:48:37 -080020import org.onlab.packet.IpAddress;
21import org.onlab.packet.IpPrefix;
22import org.onlab.util.KryoNamespace;
Ray Milkey69ec8712017-08-08 13:00:43 -070023import org.onosproject.routeservice.InternalRouteEvent;
24import org.onosproject.routeservice.Route;
25import org.onosproject.routeservice.RouteSet;
26import org.onosproject.routeservice.RouteStore;
27import org.onosproject.routeservice.RouteStoreDelegate;
28import org.onosproject.routeservice.RouteTableId;
Charles Chan0214ded2016-11-18 17:48:37 -080029import org.onosproject.store.AbstractStore;
Jonathan Hart96c146b2017-02-24 16:32:00 -080030import org.onosproject.store.service.DistributedSet;
Charles Chan0214ded2016-11-18 17:48:37 -080031import org.onosproject.store.service.Serializer;
Jonathan Hart96c146b2017-02-24 16:32:00 -080032import org.onosproject.store.service.SetEvent;
33import org.onosproject.store.service.SetEventListener;
Charles Chan0214ded2016-11-18 17:48:37 -080034import org.onosproject.store.service.StorageService;
Charles Chan0214ded2016-11-18 17:48:37 -080035import org.slf4j.Logger;
36import org.slf4j.LoggerFactory;
37
38import java.util.Collection;
39import java.util.Collections;
Charles Chan0214ded2016-11-18 17:48:37 -080040import java.util.Map;
41import java.util.Set;
Jonathan Hart96c146b2017-02-24 16:32:00 -080042import java.util.concurrent.ConcurrentHashMap;
43import java.util.concurrent.ExecutorService;
Charles Chan0214ded2016-11-18 17:48:37 -080044import java.util.concurrent.Executors;
Charles Chan0214ded2016-11-18 17:48:37 -080045
Jonathan Hart1f67d282017-05-25 14:23:01 -070046import static org.onlab.util.Tools.groupedThreads;
47
Charles Chan0214ded2016-11-18 17:48:37 -080048/**
49 * Route store based on distributed storage.
50 */
Jonathan Hart96c146b2017-02-24 16:32:00 -080051public class DistributedRouteStore extends AbstractStore<InternalRouteEvent, RouteStoreDelegate>
Charles Chan0214ded2016-11-18 17:48:37 -080052 implements RouteStore {
Jonathan Hart96c146b2017-02-24 16:32:00 -080053
54 protected StorageService storageService;
Charles Chan0214ded2016-11-18 17:48:37 -080055
56 private static final RouteTableId IPV4 = new RouteTableId("ipv4");
57 private static final RouteTableId IPV6 = new RouteTableId("ipv6");
58 private static final Logger log = LoggerFactory.getLogger(DistributedRouteStore.class);
Jonathan Hart96c146b2017-02-24 16:32:00 -080059 private final SetEventListener<RouteTableId> masterRouteTableListener =
60 new MasterRouteTableListener();
61 private final RouteStoreDelegate ourDelegate = new InternalRouteStoreDelegate();
Charles Chan0214ded2016-11-18 17:48:37 -080062
Jonathan Hart96c146b2017-02-24 16:32:00 -080063 // Stores the route tables that have been created
64 private DistributedSet<RouteTableId> masterRouteTable;
65 // Local memory map to store route table object
66 private Map<RouteTableId, RouteTable> routeTables;
Charles Chan0214ded2016-11-18 17:48:37 -080067
Jonathan Hart96c146b2017-02-24 16:32:00 -080068 private ExecutorService executor;
69
Charles Chan0214ded2016-11-18 17:48:37 -080070 public DistributedRouteStore(StorageService storageService) {
71 this.storageService = storageService;
72 }
73
74 /**
75 * Sets up distributed route store.
76 */
77 public void activate() {
Jonathan Hart96c146b2017-02-24 16:32:00 -080078 routeTables = new ConcurrentHashMap<>();
Jonathan Hart1f67d282017-05-25 14:23:01 -070079 executor = Executors.newSingleThreadExecutor(groupedThreads("onos/route", "store", log));
Charles Chan0214ded2016-11-18 17:48:37 -080080
Jonathan Hart96c146b2017-02-24 16:32:00 -080081 KryoNamespace masterRouteTableSerializer = KryoNamespace.newBuilder()
82 .register(RouteTableId.class)
83 .build();
84
85 masterRouteTable = storageService.<RouteTableId>setBuilder()
86 .withName("onos-master-route-table")
87 .withSerializer(Serializer.using(masterRouteTableSerializer))
88 .build()
89 .asDistributedSet();
90
Jonathan Hart96c146b2017-02-24 16:32:00 -080091 masterRouteTable.addListener(masterRouteTableListener);
92
93 // Add default tables (add is idempotent)
94 masterRouteTable.add(IPV4);
95 masterRouteTable.add(IPV6);
Charles Chan0214ded2016-11-18 17:48:37 -080096
Yi Tseng46654c32017-08-08 19:09:19 -070097 masterRouteTable.forEach(this::createRouteTable);
98
Charles Chan0214ded2016-11-18 17:48:37 -080099 log.info("Started");
100 }
101
102 /**
103 * Cleans up distributed route store.
104 */
105 public void deactivate() {
Jonathan Hart96c146b2017-02-24 16:32:00 -0800106 masterRouteTable.removeListener(masterRouteTableListener);
Charles Chan0214ded2016-11-18 17:48:37 -0800107
Jonathan Hart96c146b2017-02-24 16:32:00 -0800108 routeTables.values().forEach(RouteTable::shutdown);
Charles Chan0214ded2016-11-18 17:48:37 -0800109
110 log.info("Stopped");
111 }
112
113 @Override
114 public void updateRoute(Route route) {
Jonathan Hart96c146b2017-02-24 16:32:00 -0800115 getDefaultRouteTable(route).update(route);
Charles Chan0214ded2016-11-18 17:48:37 -0800116 }
117
118 @Override
119 public void removeRoute(Route route) {
Jonathan Hart96c146b2017-02-24 16:32:00 -0800120 getDefaultRouteTable(route).remove(route);
Charles Chan0214ded2016-11-18 17:48:37 -0800121 }
122
123 @Override
Daniel Ginsburg83b76452018-06-09 01:43:59 +0300124 public void replaceRoute(Route route) {
125 getDefaultRouteTable(route).replace(route);
126 }
127
128 @Override
Charles Chan0214ded2016-11-18 17:48:37 -0800129 public Set<RouteTableId> getRouteTables() {
Jonathan Hart96c146b2017-02-24 16:32:00 -0800130 return ImmutableSet.copyOf(masterRouteTable);
Charles Chan0214ded2016-11-18 17:48:37 -0800131 }
132
133 @Override
Jonathan Hart96c146b2017-02-24 16:32:00 -0800134 public Collection<RouteSet> getRoutes(RouteTableId table) {
135 RouteTable routeTable = routeTables.get(table);
136 if (routeTable == null) {
137 return Collections.emptySet();
138 } else {
139 return ImmutableSet.copyOf(routeTable.getRoutes());
140 }
Charles Chan0214ded2016-11-18 17:48:37 -0800141 }
142
143 @Override
Charles Chan0214ded2016-11-18 17:48:37 -0800144 public Collection<Route> getRoutesForNextHop(IpAddress ip) {
Jonathan Hart96c146b2017-02-24 16:32:00 -0800145 return getDefaultRouteTable(ip).getRoutesForNextHop(ip);
146 }
147
148 @Override
149 public RouteSet getRoutes(IpPrefix prefix) {
150 return getDefaultRouteTable(prefix.address()).getRoutes(prefix);
Charles Chan0214ded2016-11-18 17:48:37 -0800151 }
152
Jonathan Hart96c146b2017-02-24 16:32:00 -0800153 private void createRouteTable(RouteTableId tableId) {
Jonathan Hart1f67d282017-05-25 14:23:01 -0700154 routeTables.computeIfAbsent(tableId, id -> new DefaultRouteTable(id, ourDelegate, storageService, executor));
Charles Chan0214ded2016-11-18 17:48:37 -0800155 }
156
Jonathan Hart96c146b2017-02-24 16:32:00 -0800157 private void destroyRouteTable(RouteTableId tableId) {
158 RouteTable table = routeTables.remove(tableId);
159 if (table != null) {
160 table.destroy();
161 }
Charles Chan0214ded2016-11-18 17:48:37 -0800162 }
163
Jonathan Hart96c146b2017-02-24 16:32:00 -0800164 private RouteTable getDefaultRouteTable(Route route) {
Charles Chan0214ded2016-11-18 17:48:37 -0800165 return getDefaultRouteTable(route.prefix().address());
166 }
167
Jonathan Hart96c146b2017-02-24 16:32:00 -0800168 private RouteTable getDefaultRouteTable(IpAddress ip) {
Charles Chan0214ded2016-11-18 17:48:37 -0800169 RouteTableId routeTableId = (ip.isIp4()) ? IPV4 : IPV6;
Jonathan Hart96c146b2017-02-24 16:32:00 -0800170 return routeTables.getOrDefault(routeTableId, EmptyRouteTable.instance());
Charles Chan0214ded2016-11-18 17:48:37 -0800171 }
172
Jonathan Hart96c146b2017-02-24 16:32:00 -0800173 private class InternalRouteStoreDelegate implements RouteStoreDelegate {
Charles Chan0214ded2016-11-18 17:48:37 -0800174 @Override
Jonathan Hart96c146b2017-02-24 16:32:00 -0800175 public void notify(InternalRouteEvent event) {
176 executor.execute(() -> DistributedRouteStore.this.notifyDelegate(event));
Charles Chan0214ded2016-11-18 17:48:37 -0800177 }
178 }
179
Jonathan Hart96c146b2017-02-24 16:32:00 -0800180 private class MasterRouteTableListener implements SetEventListener<RouteTableId> {
Charles Chan0214ded2016-11-18 17:48:37 -0800181 @Override
Jonathan Hart96c146b2017-02-24 16:32:00 -0800182 public void event(SetEvent<RouteTableId> event) {
Charles Chan0214ded2016-11-18 17:48:37 -0800183 switch (event.type()) {
Jonathan Hart96c146b2017-02-24 16:32:00 -0800184 case ADD:
185 executor.execute(() -> createRouteTable(event.entry()));
186 break;
187 case REMOVE:
188 executor.execute(() -> destroyRouteTable(event.entry()));
189 break;
190 default:
191 break;
Charles Chan0214ded2016-11-18 17:48:37 -0800192 }
193 }
194 }
195}