blob: 89173257334691dffb404827df4abcbdd4e9f17a [file] [log] [blame]
Mohammad Shahidaa7c1232017-08-09 11:13:15 +05301/*
2 * Copyright 2017-present Open Networking Foundation
3 *
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 Milkeya95193c2017-08-10 15:35:36 -070017package org.onosproject.evpnrouteservice.store;
Mohammad Shahidaa7c1232017-08-09 11:13:15 +053018
19import com.google.common.collect.ImmutableSet;
Mohammad Shahidaa7c1232017-08-09 11:13:15 +053020import org.onlab.packet.IpAddress;
21import org.onlab.util.KryoNamespace;
Ray Milkeya95193c2017-08-10 15:35:36 -070022import org.onosproject.evpnrouteservice.EvpnInternalRouteEvent;
23import org.onosproject.evpnrouteservice.EvpnRoute;
24import org.onosproject.evpnrouteservice.EvpnRouteSet;
25import org.onosproject.evpnrouteservice.EvpnRouteStore;
26import org.onosproject.evpnrouteservice.EvpnRouteStoreDelegate;
27import org.onosproject.evpnrouteservice.EvpnRouteTableId;
28import org.onosproject.evpnrouteservice.EvpnTable;
Mohammad Shahidaa7c1232017-08-09 11:13:15 +053029import org.onosproject.store.AbstractStore;
30import org.onosproject.store.service.DistributedSet;
31import org.onosproject.store.service.Serializer;
32import org.onosproject.store.service.SetEvent;
33import org.onosproject.store.service.SetEventListener;
34import org.onosproject.store.service.StorageService;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070035import org.osgi.service.component.annotations.Activate;
36import org.osgi.service.component.annotations.Component;
37import org.osgi.service.component.annotations.Deactivate;
38import org.osgi.service.component.annotations.Reference;
39import org.osgi.service.component.annotations.ReferenceCardinality;
Mohammad Shahidaa7c1232017-08-09 11:13:15 +053040import org.slf4j.Logger;
41import org.slf4j.LoggerFactory;
42
43import java.util.Collection;
44import java.util.Collections;
45import java.util.Map;
46import java.util.Set;
47import java.util.concurrent.ConcurrentHashMap;
48import java.util.concurrent.ExecutorService;
49import java.util.concurrent.Executors;
50
51import static org.onlab.util.Tools.groupedThreads;
52
53/**
54 * Route store based on distributed storage.
55 */
Ray Milkeyd84f89b2018-08-17 14:54:17 -070056@Component(service = EvpnRouteStore.class)
Mohammad Shahidaa7c1232017-08-09 11:13:15 +053057public class DistributedEvpnRouteStore extends
58 AbstractStore<EvpnInternalRouteEvent,
59 EvpnRouteStoreDelegate>
60 implements EvpnRouteStore {
61
62 private static final Logger log = LoggerFactory
63 .getLogger(DistributedEvpnRouteStore.class);
64
Ray Milkeyd84f89b2018-08-17 14:54:17 -070065 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Mohammad Shahidaa7c1232017-08-09 11:13:15 +053066 public StorageService storageService;
67
Jonathan Harte9c0c6e2017-08-09 16:44:13 -070068 private static final EvpnRouteTableId EVPN_IPV4 = new EvpnRouteTableId("evpn_ipv4");
69 private static final EvpnRouteTableId EVPN_IPV6 = new EvpnRouteTableId("evpn_ipv6");
Mohammad Shahidaa7c1232017-08-09 11:13:15 +053070
Jonathan Harte9c0c6e2017-08-09 16:44:13 -070071 private final SetEventListener<EvpnRouteTableId> masterRouteTableListener =
Mohammad Shahidaa7c1232017-08-09 11:13:15 +053072 new MasterRouteTableListener();
73 private final EvpnRouteStoreDelegate ourDelegate = new
74 InternalEvpnRouteStoreDelegate();
75
76 // Stores the route tables that have been created
Jonathan Harte9c0c6e2017-08-09 16:44:13 -070077 public DistributedSet<EvpnRouteTableId> masterRouteTable;
Mohammad Shahidaa7c1232017-08-09 11:13:15 +053078 // Local memory map to store route table object
Jonathan Harte9c0c6e2017-08-09 16:44:13 -070079 public Map<EvpnRouteTableId, EvpnTable> routeTables;
Mohammad Shahidaa7c1232017-08-09 11:13:15 +053080
81 private ExecutorService executor;
82
83
84 /**
85 * Sets up distributed route store.
86 */
87 @Activate
88 public void activate() {
89 routeTables = new ConcurrentHashMap<>();
90 executor = Executors.newSingleThreadExecutor(groupedThreads("onos/route", "store", log));
91
92 KryoNamespace masterRouteTableSerializer = KryoNamespace.newBuilder()
Jonathan Harte9c0c6e2017-08-09 16:44:13 -070093 .register(EvpnRouteTableId.class)
Mohammad Shahidaa7c1232017-08-09 11:13:15 +053094 .build();
95
Jonathan Harte9c0c6e2017-08-09 16:44:13 -070096 masterRouteTable = storageService.<EvpnRouteTableId>setBuilder()
Mohammad Shahidaa7c1232017-08-09 11:13:15 +053097 .withName("onos-master-route-table")
98 .withSerializer(Serializer.using(masterRouteTableSerializer))
99 .build()
100 .asDistributedSet();
101
102 masterRouteTable.forEach(this::createRouteTable);
103
104 masterRouteTable.addListener(masterRouteTableListener);
105
106 // Add default tables (add is idempotent)
107 masterRouteTable.add(EVPN_IPV4);
108 masterRouteTable.add(EVPN_IPV6);
109
110 log.info("Started");
111 }
112
113 /**
114 * Cleans up distributed route store.
115 */
116 @Deactivate
117 public void deactivate() {
118 masterRouteTable.removeListener(masterRouteTableListener);
119
120 routeTables.values().forEach(EvpnTable::shutdown);
121
122 log.info("Stopped");
123 }
124
125 @Override
126 public void updateRoute(EvpnRoute route) {
127 getDefaultRouteTable(route).update(route);
128 }
129
130 @Override
131 public void removeRoute(EvpnRoute route) {
132 getDefaultRouteTable(route).remove(route);
133 }
134
135 @Override
Jonathan Harte9c0c6e2017-08-09 16:44:13 -0700136 public Set<EvpnRouteTableId> getRouteTables() {
Mohammad Shahidaa7c1232017-08-09 11:13:15 +0530137 return ImmutableSet.copyOf(masterRouteTable);
138 }
139
140 @Override
Jonathan Harte9c0c6e2017-08-09 16:44:13 -0700141 public Collection<EvpnRouteSet> getRoutes(EvpnRouteTableId table) {
Mohammad Shahidaa7c1232017-08-09 11:13:15 +0530142 EvpnTable routeTable = routeTables.get(table);
143 if (routeTable == null) {
144 return Collections.emptySet();
145 } else {
146 return ImmutableSet.copyOf(routeTable.getRoutes());
147 }
148 }
149
150 @Override
151 public Collection<EvpnRoute> getRoutesForNextHop(IpAddress ip) {
152 return getDefaultRouteTable(ip).getRoutesForNextHop(ip);
153 }
154
Jonathan Harte9c0c6e2017-08-09 16:44:13 -0700155 private void createRouteTable(EvpnRouteTableId tableId) {
Mohammad Shahidaa7c1232017-08-09 11:13:15 +0530156 routeTables.computeIfAbsent(tableId, id -> new EvpnRouteTable(id,
157 ourDelegate, storageService, executor));
158 }
159
Jonathan Harte9c0c6e2017-08-09 16:44:13 -0700160 private void destroyRouteTable(EvpnRouteTableId tableId) {
Mohammad Shahidaa7c1232017-08-09 11:13:15 +0530161 EvpnTable table = routeTables.remove(tableId);
162 if (table != null) {
163 table.destroy();
164 }
165 }
166
167 private EvpnTable getDefaultRouteTable(EvpnRoute route) {
168 return getDefaultRouteTable(route.prefixIp().address());
169 }
170
171 private EvpnTable getDefaultRouteTable(IpAddress ip) {
Jonathan Harte9c0c6e2017-08-09 16:44:13 -0700172 EvpnRouteTableId routeTableId = (ip.isIp4()) ? EVPN_IPV4 : EVPN_IPV6;
Mohammad Shahidaa7c1232017-08-09 11:13:15 +0530173 return routeTables.getOrDefault(routeTableId, EmptyEvpnRouteTable
174 .instance());
175 }
176
177 private class InternalEvpnRouteStoreDelegate implements
178 EvpnRouteStoreDelegate {
179 @Override
180 public void notify(EvpnInternalRouteEvent event) {
181 executor.execute(() -> DistributedEvpnRouteStore
182 .this.notifyDelegate(event));
183 }
184 }
185
Jonathan Harte9c0c6e2017-08-09 16:44:13 -0700186 private class MasterRouteTableListener implements SetEventListener<EvpnRouteTableId> {
Mohammad Shahidaa7c1232017-08-09 11:13:15 +0530187 @Override
Jonathan Harte9c0c6e2017-08-09 16:44:13 -0700188 public void event(SetEvent<EvpnRouteTableId> event) {
Mohammad Shahidaa7c1232017-08-09 11:13:15 +0530189 switch (event.type()) {
190 case ADD:
191 executor.execute(() -> createRouteTable(event.entry()));
192 break;
193 case REMOVE:
194 executor.execute(() -> destroyRouteTable(event.entry()));
195 break;
196 default:
197 break;
198 }
199 }
200 }
201}