blob: 49356b63c5603bba67ea8226c943b98b25287e07 [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;
33import org.onosproject.incubator.net.routing.EvpnTable;
34import org.onosproject.incubator.net.routing.RouteTableId;
35import 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
70 private static final RouteTableId EVPN_IPV4 = new RouteTableId("evpn_ipv4");
71 private static final RouteTableId EVPN_IPV6 = new RouteTableId("evpn_ipv6");
72
73 private final SetEventListener<RouteTableId> masterRouteTableListener =
74 new MasterRouteTableListener();
75 private final EvpnRouteStoreDelegate ourDelegate = new
76 InternalEvpnRouteStoreDelegate();
77
78 // Stores the route tables that have been created
79 public DistributedSet<RouteTableId> masterRouteTable;
80 // Local memory map to store route table object
81 public Map<RouteTableId, EvpnTable> routeTables;
82
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()
95 .register(RouteTableId.class)
96 .build();
97
98 masterRouteTable = storageService.<RouteTableId>setBuilder()
99 .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
138 public Set<RouteTableId> getRouteTables() {
139 return ImmutableSet.copyOf(masterRouteTable);
140 }
141
142 @Override
143 public Collection<EvpnRouteSet> getRoutes(RouteTableId table) {
144 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
157 private void createRouteTable(RouteTableId tableId) {
158 routeTables.computeIfAbsent(tableId, id -> new EvpnRouteTable(id,
159 ourDelegate, storageService, executor));
160 }
161
162 private void destroyRouteTable(RouteTableId tableId) {
163 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) {
174 RouteTableId routeTableId = (ip.isIp4()) ? EVPN_IPV4 : EVPN_IPV6;
175 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
188 private class MasterRouteTableListener implements SetEventListener<RouteTableId> {
189 @Override
190 public void event(SetEvent<RouteTableId> event) {
191 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}