blob: b4526e2bd3c16831aa20732eedad31448a58b384 [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
17package org.onosproject.incubator.store.routing.impl;
18
19import com.google.common.collect.ImmutableSet;
20import org.apache.felix.scr.annotations.Activate;
21import org.apache.felix.scr.annotations.Component;
22import org.apache.felix.scr.annotations.Deactivate;
23import org.apache.felix.scr.annotations.Reference;
24import org.apache.felix.scr.annotations.ReferenceCardinality;
25import org.apache.felix.scr.annotations.Service;
26import org.onlab.packet.IpAddress;
27import org.onlab.util.KryoNamespace;
28import org.onosproject.incubator.net.routing.EvpnInternalRouteEvent;
29import org.onosproject.incubator.net.routing.EvpnRoute;
30import org.onosproject.incubator.net.routing.EvpnRouteSet;
31import org.onosproject.incubator.net.routing.EvpnRouteStore;
32import org.onosproject.incubator.net.routing.EvpnRouteStoreDelegate;
Jonathan Harte9c0c6e2017-08-09 16:44:13 -070033import org.onosproject.incubator.net.routing.EvpnRouteTableId;
Mohammad Shahidaa7c1232017-08-09 11:13:15 +053034import org.onosproject.incubator.net.routing.EvpnTable;
Mohammad Shahidaa7c1232017-08-09 11:13:15 +053035import org.onosproject.store.AbstractStore;
36import org.onosproject.store.service.DistributedSet;
37import org.onosproject.store.service.Serializer;
38import org.onosproject.store.service.SetEvent;
39import org.onosproject.store.service.SetEventListener;
40import org.onosproject.store.service.StorageService;
41import org.slf4j.Logger;
42import org.slf4j.LoggerFactory;
43
44import java.util.Collection;
45import java.util.Collections;
46import java.util.Map;
47import java.util.Set;
48import java.util.concurrent.ConcurrentHashMap;
49import java.util.concurrent.ExecutorService;
50import java.util.concurrent.Executors;
51
52import static org.onlab.util.Tools.groupedThreads;
53
54/**
55 * Route store based on distributed storage.
56 */
57@Service
58@Component
59public class DistributedEvpnRouteStore extends
60 AbstractStore<EvpnInternalRouteEvent,
61 EvpnRouteStoreDelegate>
62 implements EvpnRouteStore {
63
64 private static final Logger log = LoggerFactory
65 .getLogger(DistributedEvpnRouteStore.class);
66
67 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
68 public StorageService storageService;
69
Jonathan Harte9c0c6e2017-08-09 16:44:13 -070070 private static final EvpnRouteTableId EVPN_IPV4 = new EvpnRouteTableId("evpn_ipv4");
71 private static final EvpnRouteTableId EVPN_IPV6 = new EvpnRouteTableId("evpn_ipv6");
Mohammad Shahidaa7c1232017-08-09 11:13:15 +053072
Jonathan Harte9c0c6e2017-08-09 16:44:13 -070073 private final SetEventListener<EvpnRouteTableId> masterRouteTableListener =
Mohammad Shahidaa7c1232017-08-09 11:13:15 +053074 new MasterRouteTableListener();
75 private final EvpnRouteStoreDelegate ourDelegate = new
76 InternalEvpnRouteStoreDelegate();
77
78 // Stores the route tables that have been created
Jonathan Harte9c0c6e2017-08-09 16:44:13 -070079 public DistributedSet<EvpnRouteTableId> masterRouteTable;
Mohammad Shahidaa7c1232017-08-09 11:13:15 +053080 // Local memory map to store route table object
Jonathan Harte9c0c6e2017-08-09 16:44:13 -070081 public Map<EvpnRouteTableId, EvpnTable> routeTables;
Mohammad Shahidaa7c1232017-08-09 11:13:15 +053082
83 private ExecutorService executor;
84
85
86 /**
87 * Sets up distributed route store.
88 */
89 @Activate
90 public void activate() {
91 routeTables = new ConcurrentHashMap<>();
92 executor = Executors.newSingleThreadExecutor(groupedThreads("onos/route", "store", log));
93
94 KryoNamespace masterRouteTableSerializer = KryoNamespace.newBuilder()
Jonathan Harte9c0c6e2017-08-09 16:44:13 -070095 .register(EvpnRouteTableId.class)
Mohammad Shahidaa7c1232017-08-09 11:13:15 +053096 .build();
97
Jonathan Harte9c0c6e2017-08-09 16:44:13 -070098 masterRouteTable = storageService.<EvpnRouteTableId>setBuilder()
Mohammad Shahidaa7c1232017-08-09 11:13:15 +053099 .withName("onos-master-route-table")
100 .withSerializer(Serializer.using(masterRouteTableSerializer))
101 .build()
102 .asDistributedSet();
103
104 masterRouteTable.forEach(this::createRouteTable);
105
106 masterRouteTable.addListener(masterRouteTableListener);
107
108 // Add default tables (add is idempotent)
109 masterRouteTable.add(EVPN_IPV4);
110 masterRouteTable.add(EVPN_IPV6);
111
112 log.info("Started");
113 }
114
115 /**
116 * Cleans up distributed route store.
117 */
118 @Deactivate
119 public void deactivate() {
120 masterRouteTable.removeListener(masterRouteTableListener);
121
122 routeTables.values().forEach(EvpnTable::shutdown);
123
124 log.info("Stopped");
125 }
126
127 @Override
128 public void updateRoute(EvpnRoute route) {
129 getDefaultRouteTable(route).update(route);
130 }
131
132 @Override
133 public void removeRoute(EvpnRoute route) {
134 getDefaultRouteTable(route).remove(route);
135 }
136
137 @Override
Jonathan Harte9c0c6e2017-08-09 16:44:13 -0700138 public Set<EvpnRouteTableId> getRouteTables() {
Mohammad Shahidaa7c1232017-08-09 11:13:15 +0530139 return ImmutableSet.copyOf(masterRouteTable);
140 }
141
142 @Override
Jonathan Harte9c0c6e2017-08-09 16:44:13 -0700143 public Collection<EvpnRouteSet> getRoutes(EvpnRouteTableId table) {
Mohammad Shahidaa7c1232017-08-09 11:13:15 +0530144 EvpnTable routeTable = routeTables.get(table);
145 if (routeTable == null) {
146 return Collections.emptySet();
147 } else {
148 return ImmutableSet.copyOf(routeTable.getRoutes());
149 }
150 }
151
152 @Override
153 public Collection<EvpnRoute> getRoutesForNextHop(IpAddress ip) {
154 return getDefaultRouteTable(ip).getRoutesForNextHop(ip);
155 }
156
Jonathan Harte9c0c6e2017-08-09 16:44:13 -0700157 private void createRouteTable(EvpnRouteTableId tableId) {
Mohammad Shahidaa7c1232017-08-09 11:13:15 +0530158 routeTables.computeIfAbsent(tableId, id -> new EvpnRouteTable(id,
159 ourDelegate, storageService, executor));
160 }
161
Jonathan Harte9c0c6e2017-08-09 16:44:13 -0700162 private void destroyRouteTable(EvpnRouteTableId tableId) {
Mohammad Shahidaa7c1232017-08-09 11:13:15 +0530163 EvpnTable table = routeTables.remove(tableId);
164 if (table != null) {
165 table.destroy();
166 }
167 }
168
169 private EvpnTable getDefaultRouteTable(EvpnRoute route) {
170 return getDefaultRouteTable(route.prefixIp().address());
171 }
172
173 private EvpnTable getDefaultRouteTable(IpAddress ip) {
Jonathan Harte9c0c6e2017-08-09 16:44:13 -0700174 EvpnRouteTableId routeTableId = (ip.isIp4()) ? EVPN_IPV4 : EVPN_IPV6;
Mohammad Shahidaa7c1232017-08-09 11:13:15 +0530175 return routeTables.getOrDefault(routeTableId, EmptyEvpnRouteTable
176 .instance());
177 }
178
179 private class InternalEvpnRouteStoreDelegate implements
180 EvpnRouteStoreDelegate {
181 @Override
182 public void notify(EvpnInternalRouteEvent event) {
183 executor.execute(() -> DistributedEvpnRouteStore
184 .this.notifyDelegate(event));
185 }
186 }
187
Jonathan Harte9c0c6e2017-08-09 16:44:13 -0700188 private class MasterRouteTableListener implements SetEventListener<EvpnRouteTableId> {
Mohammad Shahidaa7c1232017-08-09 11:13:15 +0530189 @Override
Jonathan Harte9c0c6e2017-08-09 16:44:13 -0700190 public void event(SetEvent<EvpnRouteTableId> event) {
Mohammad Shahidaa7c1232017-08-09 11:13:15 +0530191 switch (event.type()) {
192 case ADD:
193 executor.execute(() -> createRouteTable(event.entry()));
194 break;
195 case REMOVE:
196 executor.execute(() -> destroyRouteTable(event.entry()));
197 break;
198 default:
199 break;
200 }
201 }
202 }
203}