blob: 6b1051231def6d9286b5b5aa2518fcaeda38c2c1 [file] [log] [blame]
Hyunsun Moon44aac662017-02-18 02:07:01 +09001/*
2 * Copyright 2017-present Open Networking Laboratory
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 */
16package org.onosproject.openstacknetworking.impl;
17
18import com.google.common.base.Strings;
19import com.google.common.collect.ImmutableSet;
20import org.apache.felix.scr.annotations.Component;
21import org.apache.felix.scr.annotations.Deactivate;
22import org.apache.felix.scr.annotations.Reference;
23import org.apache.felix.scr.annotations.ReferenceCardinality;
24import org.apache.felix.scr.annotations.Service;
25import org.onlab.util.KryoNamespace;
26import org.onosproject.core.ApplicationId;
27import org.onosproject.core.CoreService;
28import org.onosproject.openstacknetworking.api.OpenstackRouterEvent;
29import org.onosproject.openstacknetworking.api.OpenstackRouterStore;
30import org.onosproject.openstacknetworking.api.OpenstackRouterStoreDelegate;
31import org.onosproject.store.AbstractStore;
32import org.onosproject.store.serializers.KryoNamespaces;
33import org.onosproject.store.service.ConsistentMap;
34import org.onosproject.store.service.MapEvent;
35import org.onosproject.store.service.MapEventListener;
36import org.onosproject.store.service.Serializer;
37import org.onosproject.store.service.StorageService;
38import org.onosproject.store.service.Versioned;
39import org.openstack4j.model.network.ExternalGateway;
40import org.openstack4j.model.network.NetFloatingIP;
41import org.openstack4j.model.network.Router;
42import org.openstack4j.model.network.RouterInterface;
43import org.openstack4j.model.network.State;
44import org.openstack4j.openstack.networking.domain.NeutronExternalGateway;
45import org.openstack4j.openstack.networking.domain.NeutronFloatingIP;
46import org.openstack4j.openstack.networking.domain.NeutronHostRoute;
47import org.openstack4j.openstack.networking.domain.NeutronRouter;
48import org.openstack4j.openstack.networking.domain.NeutronRouterInterface;
49import org.osgi.service.component.annotations.Activate;
50import org.slf4j.Logger;
51
52import java.util.Set;
53import java.util.concurrent.ExecutorService;
54import java.util.stream.Collectors;
55
56import static com.google.common.base.Preconditions.checkArgument;
57import static java.util.concurrent.Executors.newSingleThreadExecutor;
58import static org.onlab.util.Tools.groupedThreads;
59import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
60import static org.onosproject.openstacknetworking.api.OpenstackRouterEvent.Type.*;
61import static org.slf4j.LoggerFactory.getLogger;
62
63/**
64 * Manages the inventory of OpenStack router and floating IP using a {@code ConsistentMap}.
65 */
66@Service
67@Component(immediate = true)
68public class DistributedOpenstackRouterStore
69 extends AbstractStore<OpenstackRouterEvent, OpenstackRouterStoreDelegate>
70 implements OpenstackRouterStore {
71
72 protected final Logger log = getLogger(getClass());
73
74 private static final String ERR_NOT_FOUND = " does not exist";
75 private static final String ERR_DUPLICATE = " already exists";
76
77 private static final KryoNamespace SERIALIZER_NEUTRON_L3 = KryoNamespace.newBuilder()
78 .register(KryoNamespaces.API)
79 .register(Router.class)
80 .register(NeutronRouter.class)
81 .register(State.class)
82 .register(NeutronHostRoute.class)
83 .register(ExternalGateway.class)
84 .register(NeutronExternalGateway.class)
85 .register(RouterInterface.class)
86 .register(NeutronRouterInterface.class)
87 .register(NetFloatingIP.class)
88 .register(NeutronFloatingIP.class)
89 .build();
90
91 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
92 protected CoreService coreService;
93
94 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
95 protected StorageService storageService;
96
97 private final ExecutorService eventExecutor = newSingleThreadExecutor(
98 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
99 private final MapEventListener<String, Router> routerMapListener = new OpenstackRouterMapListener();
100 private final MapEventListener<String, RouterInterface> routerInterfaceMapListener =
101 new OpenstackRouterInterfaceMapListener();
102 private final MapEventListener<String, NetFloatingIP> floatingIpMapListener =
103 new OpenstackFloatingIpMapListener();
104
105 private ConsistentMap<String, Router> osRouterStore;
106 private ConsistentMap<String, RouterInterface> osRouterInterfaceStore;
107 private ConsistentMap<String, NetFloatingIP> osFloatingIpStore;
108
109 @Activate
110 protected void activate() {
111 ApplicationId appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
112
113 osRouterStore = storageService.<String, Router>consistentMapBuilder()
114 .withSerializer(Serializer.using(SERIALIZER_NEUTRON_L3))
115 .withName("openstack-routerstore")
116 .withApplicationId(appId)
117 .build();
118 osRouterStore.addListener(routerMapListener);
119
120 osRouterInterfaceStore = storageService.<String, RouterInterface>consistentMapBuilder()
121 .withSerializer(Serializer.using(SERIALIZER_NEUTRON_L3))
122 .withName("openstack-routerifacestore")
123 .withApplicationId(appId)
124 .build();
125 osRouterInterfaceStore.addListener(routerInterfaceMapListener);
126
127 osFloatingIpStore = storageService.<String, NetFloatingIP>consistentMapBuilder()
128 .withSerializer(Serializer.using(SERIALIZER_NEUTRON_L3))
129 .withName("openstack-floatingipstore")
130 .withApplicationId(appId)
131 .build();
132 osFloatingIpStore.addListener(floatingIpMapListener);
133
134 log.info("Started");
135 }
136
137 @Deactivate
138 protected void deactivate() {
139 osRouterStore.removeListener(routerMapListener);
140 osRouterInterfaceStore.removeListener(routerInterfaceMapListener);
141 osFloatingIpStore.removeListener(floatingIpMapListener);
142 eventExecutor.shutdown();
143
144 log.info("Stopped");
145 }
146
147 @Override
148 public void createRouter(Router osRouter) {
149 osRouterStore.compute(osRouter.getId(), (id, existing) -> {
150 final String error = osRouter.getName() + ERR_DUPLICATE;
151 checkArgument(existing == null, error);
152 return osRouter;
153 });
154 }
155
156 @Override
157 public void updateRouter(Router osRouter) {
158 osRouterStore.compute(osRouter.getId(), (id, existing) -> {
159 final String error = osRouter.getName() + ERR_NOT_FOUND;
160 checkArgument(existing != null, error);
161 return osRouter;
162 });
163 }
164
165 @Override
166 public Router removeRouter(String routerId) {
167 Versioned<Router> osRouter = osRouterStore.remove(routerId);
168 return osRouter == null ? null : osRouter.value();
169 }
170
171 @Override
172 public Router router(String routerId) {
173 Versioned<Router> versioned = osRouterStore.get(routerId);
174 return versioned == null ? null : versioned.value();
175 }
176
177 @Override
178 public Set<Router> routers() {
179 Set<Router> osRouters = osRouterStore.values().stream()
180 .map(Versioned::value)
181 .collect(Collectors.toSet());
182 return ImmutableSet.copyOf(osRouters);
183 }
184
185 @Override
186 public void addRouterInterface(RouterInterface osRouterIface) {
187 osRouterInterfaceStore.compute(osRouterIface.getPortId(), (id, existing) -> {
188 final String error = osRouterIface.getPortId() + ERR_DUPLICATE;
189 checkArgument(existing == null, error);
190 return osRouterIface;
191 });
192 }
193
194 @Override
195 public void updateRouterInterface(RouterInterface osRouterIface) {
196 osRouterInterfaceStore.compute(osRouterIface.getPortId(), (id, existing) -> {
197 final String error = osRouterIface.getPortId() + ERR_NOT_FOUND;
198 checkArgument(existing != null, error);
199 return osRouterIface;
200 });
201 }
202
203 @Override
204 public RouterInterface removeRouterInterface(String routerIfaceId) {
205 Versioned<RouterInterface> osRouterIface = osRouterInterfaceStore.remove(routerIfaceId);
206 return osRouterIface == null ? null : osRouterIface.value();
207 }
208
209 @Override
210 public RouterInterface routerInterface(String routerIfaceId) {
211 Versioned<RouterInterface> osRouterIface = osRouterInterfaceStore.get(routerIfaceId);
212 return osRouterIface == null ? null : osRouterIface.value();
213 }
214
215 @Override
216 public Set<RouterInterface> routerInterfaces() {
217 Set<RouterInterface> osRouterIfaces = osRouterInterfaceStore.values().stream()
218 .map(Versioned::value)
219 .collect(Collectors.toSet());
220 return ImmutableSet.copyOf(osRouterIfaces);
221 }
222
223 @Override
224 public void createFloatingIp(NetFloatingIP osFloatingIp) {
225 osFloatingIpStore.compute(osFloatingIp.getId(), (id, existing) -> {
226 final String error = osFloatingIp.getId() + ERR_DUPLICATE;
227 checkArgument(existing == null, error);
228 return osFloatingIp;
229 });
230 }
231
232 @Override
233 public void updateFloatingIp(NetFloatingIP osFloatingIp) {
234 osFloatingIpStore.compute(osFloatingIp.getId(), (id, existing) -> {
235 final String error = osFloatingIp.getId() + ERR_NOT_FOUND;
236 checkArgument(existing != null, error);
237 return osFloatingIp;
238 });
239 }
240
241 @Override
242 public NetFloatingIP removeFloatingIp(String floatingIpId) {
243 Versioned<NetFloatingIP> osFloatingIp = osFloatingIpStore.remove(floatingIpId);
244 return osFloatingIp == null ? null : osFloatingIp.value();
245 }
246
247 @Override
248 public NetFloatingIP floatingIp(String floatingIpId) {
249 Versioned<NetFloatingIP> osFloatingIp = osFloatingIpStore.get(floatingIpId);
250 return osFloatingIp == null ? null : osFloatingIp.value();
251 }
252
253 @Override
254 public Set<NetFloatingIP> floatingIps() {
255 Set<NetFloatingIP> osFloatingIps = osFloatingIpStore.values().stream()
256 .map(Versioned::value)
257 .collect(Collectors.toSet());
258 return ImmutableSet.copyOf(osFloatingIps);
259 }
260
261 private class OpenstackRouterMapListener implements MapEventListener<String, Router> {
262
263 @Override
264 public void event(MapEvent<String, Router> event) {
265 switch (event.type()) {
266 case UPDATE:
267 log.debug("OpenStack router updated {}", event.newValue());
268 eventExecutor.execute(() -> {
269 notifyDelegate(new OpenstackRouterEvent(
270 OPENSTACK_ROUTER_UPDATED,
271 event.newValue().value()));
272 processGatewayUpdate(event);
273 });
274 break;
275 case INSERT:
276 log.debug("OpenStack router created {}", event.newValue());
277 eventExecutor.execute(() -> {
278 notifyDelegate(new OpenstackRouterEvent(
279 OPENSTACK_ROUTER_CREATED,
280 event.newValue().value()));
281 });
282 break;
283 case REMOVE:
284 log.debug("OpenStack router removed {}", event.oldValue());
285 eventExecutor.execute(() -> {
286 notifyDelegate(new OpenstackRouterEvent(
287 OPENSTACK_ROUTER_REMOVED,
288 event.oldValue().value()));
289 });
290 break;
291 default:
292 log.error("Unsupported event type");
293 break;
294 }
295 }
296
297 private void processGatewayUpdate(MapEvent<String, Router> event) {
298 ExternalGateway oldGateway = event.oldValue().value().getExternalGatewayInfo();
299 ExternalGateway newGateway = event.newValue().value().getExternalGatewayInfo();
300
301 if (oldGateway == null && newGateway != null) {
302 notifyDelegate(new OpenstackRouterEvent(
303 OPENSTACK_ROUTER_GATEWAY_ADDED,
304 event.newValue().value(), newGateway));
305 }
306 if (oldGateway != null && newGateway == null) {
307 notifyDelegate(new OpenstackRouterEvent(
308 OPENSTACK_ROUTER_GATEWAY_ADDED,
309 event.newValue().value(), oldGateway));
310 }
311 }
312 }
313
314 private class OpenstackRouterInterfaceMapListener implements MapEventListener<String, RouterInterface> {
315
316 @Override
317 public void event(MapEvent<String, RouterInterface> event) {
318 switch (event.type()) {
319 case UPDATE:
320 log.debug("OpenStack router interface updated {}", event.newValue());
321 eventExecutor.execute(() -> {
322 notifyDelegate(new OpenstackRouterEvent(
323 OPENSTACK_ROUTER_INTERFACE_UPDATED,
324 router(event.newValue().value().getId()),
325 event.newValue().value()));
326 });
327 break;
328 case INSERT:
329 log.debug("OpenStack router interface created {}", event.newValue());
330 eventExecutor.execute(() -> {
331 notifyDelegate(new OpenstackRouterEvent(
332 OPENSTACK_ROUTER_INTERFACE_ADDED,
333 router(event.newValue().value().getId()),
334 event.newValue().value()));
335 });
336 break;
337 case REMOVE:
338 log.debug("OpenStack router interface removed {}", event.oldValue());
339 eventExecutor.execute(() -> {
340 notifyDelegate(new OpenstackRouterEvent(
341 OPENSTACK_ROUTER_INTERFACE_REMOVED,
342 router(event.oldValue().value().getId()),
343 event.oldValue().value()));
344 });
345 break;
346 default:
347 log.error("Unsupported event type");
348 break;
349 }
350 }
351 }
352
353 private class OpenstackFloatingIpMapListener implements MapEventListener<String, NetFloatingIP> {
354
355 @Override
356 public void event(MapEvent<String, NetFloatingIP> event) {
357 switch (event.type()) {
358 case UPDATE:
359 log.debug("OpenStack floating IP updated {}", event.newValue());
360 eventExecutor.execute(() -> {
361 Router osRouter = Strings.isNullOrEmpty(
362 event.newValue().value().getRouterId()) ?
363 null :
364 router(event.newValue().value().getRouterId());
365 notifyDelegate(new OpenstackRouterEvent(
366 OPENSTACK_FLOATING_IP_UPDATED,
367 osRouter,
368 event.newValue().value()));
369 processFloatingIpUpdate(event, osRouter);
370 });
371 break;
372 case INSERT:
373 log.debug("OpenStack floating IP created {}", event.newValue());
374 eventExecutor.execute(() -> {
375 Router osRouter = Strings.isNullOrEmpty(
376 event.newValue().value().getRouterId()) ?
377 null :
378 router(event.newValue().value().getRouterId());
379 notifyDelegate(new OpenstackRouterEvent(
380 OPENSTACK_FLOATING_IP_CREATED,
381 osRouter,
382 event.newValue().value()));
383 });
384 break;
385 case REMOVE:
386 log.debug("OpenStack floating IP removed {}", event.oldValue());
387 eventExecutor.execute(() -> {
388 Router osRouter = Strings.isNullOrEmpty(
389 event.oldValue().value().getRouterId()) ?
390 null :
391 router(event.oldValue().value().getRouterId());
392 notifyDelegate(new OpenstackRouterEvent(
393 OPENSTACK_FLOATING_IP_REMOVED,
394 osRouter,
395 event.oldValue().value()));
396 });
397 break;
398 default:
399 log.error("Unsupported event type");
400 break;
401 }
402 }
403
404 private void processFloatingIpUpdate(MapEvent<String, NetFloatingIP> event,
405 Router osRouter) {
406 String oldPortId = event.oldValue().value().getPortId();
407 String newPortId = event.newValue().value().getPortId();
408
409 if (Strings.isNullOrEmpty(oldPortId) && !Strings.isNullOrEmpty(newPortId)) {
410 notifyDelegate(new OpenstackRouterEvent(
411 OPENSTACK_FLOATING_IP_ASSOCIATED,
412 osRouter,
413 event.newValue().value(), newPortId));
414 }
415 if (!Strings.isNullOrEmpty(oldPortId) && Strings.isNullOrEmpty(newPortId)) {
416 notifyDelegate(new OpenstackRouterEvent(
417 OPENSTACK_FLOATING_IP_DISASSOCIATED,
418 osRouter,
419 event.newValue().value(), oldPortId));
420 }
421 }
422 }
423}