blob: bea2a006b4bf39948066221735f442ec3519578f [file] [log] [blame]
Hyunsun Moon44aac662017-02-18 02:07:01 +09001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2017-present Open Networking Foundation
Hyunsun Moon44aac662017-02-18 02:07:01 +09003 *
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;
daniel parkb5817102018-02-15 00:18:51 +090028import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090029import org.onosproject.openstacknetworking.api.OpenstackRouterEvent;
30import org.onosproject.openstacknetworking.api.OpenstackRouterStore;
31import org.onosproject.openstacknetworking.api.OpenstackRouterStoreDelegate;
32import org.onosproject.store.AbstractStore;
33import org.onosproject.store.serializers.KryoNamespaces;
34import org.onosproject.store.service.ConsistentMap;
35import org.onosproject.store.service.MapEvent;
36import org.onosproject.store.service.MapEventListener;
37import org.onosproject.store.service.Serializer;
38import org.onosproject.store.service.StorageService;
39import org.onosproject.store.service.Versioned;
40import org.openstack4j.model.network.ExternalGateway;
41import org.openstack4j.model.network.NetFloatingIP;
42import org.openstack4j.model.network.Router;
43import org.openstack4j.model.network.RouterInterface;
44import org.openstack4j.model.network.State;
45import org.openstack4j.openstack.networking.domain.NeutronExternalGateway;
46import org.openstack4j.openstack.networking.domain.NeutronFloatingIP;
47import org.openstack4j.openstack.networking.domain.NeutronHostRoute;
48import org.openstack4j.openstack.networking.domain.NeutronRouter;
49import org.openstack4j.openstack.networking.domain.NeutronRouterInterface;
50import org.osgi.service.component.annotations.Activate;
51import org.slf4j.Logger;
52
53import java.util.Set;
54import java.util.concurrent.ExecutorService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090055
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;
Jian Li78885a22018-03-02 11:33:02 +090060import static org.onosproject.openstacknetworking.api.OpenstackRouterEvent.Type.OPENSTACK_FLOATING_IP_ASSOCIATED;
61import static org.onosproject.openstacknetworking.api.OpenstackRouterEvent.Type.OPENSTACK_FLOATING_IP_CREATED;
62import static org.onosproject.openstacknetworking.api.OpenstackRouterEvent.Type.OPENSTACK_FLOATING_IP_DISASSOCIATED;
63import static org.onosproject.openstacknetworking.api.OpenstackRouterEvent.Type.OPENSTACK_FLOATING_IP_REMOVED;
64import static org.onosproject.openstacknetworking.api.OpenstackRouterEvent.Type.OPENSTACK_FLOATING_IP_UPDATED;
65import static org.onosproject.openstacknetworking.api.OpenstackRouterEvent.Type.OPENSTACK_ROUTER_CREATED;
66import static org.onosproject.openstacknetworking.api.OpenstackRouterEvent.Type.OPENSTACK_ROUTER_GATEWAY_ADDED;
67import static org.onosproject.openstacknetworking.api.OpenstackRouterEvent.Type.OPENSTACK_ROUTER_GATEWAY_REMOVED;
68import static org.onosproject.openstacknetworking.api.OpenstackRouterEvent.Type.OPENSTACK_ROUTER_INTERFACE_ADDED;
69import static org.onosproject.openstacknetworking.api.OpenstackRouterEvent.Type.OPENSTACK_ROUTER_INTERFACE_REMOVED;
70import static org.onosproject.openstacknetworking.api.OpenstackRouterEvent.Type.OPENSTACK_ROUTER_INTERFACE_UPDATED;
71import static org.onosproject.openstacknetworking.api.OpenstackRouterEvent.Type.OPENSTACK_ROUTER_REMOVED;
72import static org.onosproject.openstacknetworking.api.OpenstackRouterEvent.Type.OPENSTACK_ROUTER_UPDATED;
Hyunsun Moon44aac662017-02-18 02:07:01 +090073import static org.slf4j.LoggerFactory.getLogger;
74
75/**
76 * Manages the inventory of OpenStack router and floating IP using a {@code ConsistentMap}.
77 */
78@Service
79@Component(immediate = true)
80public class DistributedOpenstackRouterStore
81 extends AbstractStore<OpenstackRouterEvent, OpenstackRouterStoreDelegate>
82 implements OpenstackRouterStore {
83
84 protected final Logger log = getLogger(getClass());
85
86 private static final String ERR_NOT_FOUND = " does not exist";
87 private static final String ERR_DUPLICATE = " already exists";
88
89 private static final KryoNamespace SERIALIZER_NEUTRON_L3 = KryoNamespace.newBuilder()
90 .register(KryoNamespaces.API)
91 .register(Router.class)
92 .register(NeutronRouter.class)
93 .register(State.class)
94 .register(NeutronHostRoute.class)
95 .register(ExternalGateway.class)
96 .register(NeutronExternalGateway.class)
97 .register(RouterInterface.class)
98 .register(NeutronRouterInterface.class)
99 .register(NetFloatingIP.class)
100 .register(NeutronFloatingIP.class)
101 .build();
102
103 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
104 protected CoreService coreService;
105
106 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
107 protected StorageService storageService;
108
daniel parkb5817102018-02-15 00:18:51 +0900109 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
110 protected OpenstackNetworkService osNetworkService;
111
Hyunsun Moon44aac662017-02-18 02:07:01 +0900112 private final ExecutorService eventExecutor = newSingleThreadExecutor(
113 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
114 private final MapEventListener<String, Router> routerMapListener = new OpenstackRouterMapListener();
115 private final MapEventListener<String, RouterInterface> routerInterfaceMapListener =
116 new OpenstackRouterInterfaceMapListener();
117 private final MapEventListener<String, NetFloatingIP> floatingIpMapListener =
118 new OpenstackFloatingIpMapListener();
119
120 private ConsistentMap<String, Router> osRouterStore;
121 private ConsistentMap<String, RouterInterface> osRouterInterfaceStore;
122 private ConsistentMap<String, NetFloatingIP> osFloatingIpStore;
123
124 @Activate
125 protected void activate() {
126 ApplicationId appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
127
128 osRouterStore = storageService.<String, Router>consistentMapBuilder()
129 .withSerializer(Serializer.using(SERIALIZER_NEUTRON_L3))
130 .withName("openstack-routerstore")
131 .withApplicationId(appId)
132 .build();
133 osRouterStore.addListener(routerMapListener);
134
135 osRouterInterfaceStore = storageService.<String, RouterInterface>consistentMapBuilder()
136 .withSerializer(Serializer.using(SERIALIZER_NEUTRON_L3))
137 .withName("openstack-routerifacestore")
138 .withApplicationId(appId)
139 .build();
140 osRouterInterfaceStore.addListener(routerInterfaceMapListener);
141
142 osFloatingIpStore = storageService.<String, NetFloatingIP>consistentMapBuilder()
143 .withSerializer(Serializer.using(SERIALIZER_NEUTRON_L3))
144 .withName("openstack-floatingipstore")
145 .withApplicationId(appId)
146 .build();
147 osFloatingIpStore.addListener(floatingIpMapListener);
148
149 log.info("Started");
150 }
151
152 @Deactivate
153 protected void deactivate() {
154 osRouterStore.removeListener(routerMapListener);
155 osRouterInterfaceStore.removeListener(routerInterfaceMapListener);
156 osFloatingIpStore.removeListener(floatingIpMapListener);
157 eventExecutor.shutdown();
158
159 log.info("Stopped");
160 }
161
162 @Override
163 public void createRouter(Router osRouter) {
164 osRouterStore.compute(osRouter.getId(), (id, existing) -> {
165 final String error = osRouter.getName() + ERR_DUPLICATE;
166 checkArgument(existing == null, error);
167 return osRouter;
168 });
169 }
170
171 @Override
172 public void updateRouter(Router osRouter) {
173 osRouterStore.compute(osRouter.getId(), (id, existing) -> {
174 final String error = osRouter.getName() + ERR_NOT_FOUND;
175 checkArgument(existing != null, error);
176 return osRouter;
177 });
178 }
179
180 @Override
181 public Router removeRouter(String routerId) {
182 Versioned<Router> osRouter = osRouterStore.remove(routerId);
183 return osRouter == null ? null : osRouter.value();
184 }
185
186 @Override
187 public Router router(String routerId) {
Jian Li78885a22018-03-02 11:33:02 +0900188 return osRouterStore.asJavaMap().get(routerId);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900189 }
190
191 @Override
192 public Set<Router> routers() {
Jian Li78885a22018-03-02 11:33:02 +0900193 return ImmutableSet.copyOf(osRouterStore.asJavaMap().values());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900194 }
195
196 @Override
197 public void addRouterInterface(RouterInterface osRouterIface) {
198 osRouterInterfaceStore.compute(osRouterIface.getPortId(), (id, existing) -> {
199 final String error = osRouterIface.getPortId() + ERR_DUPLICATE;
200 checkArgument(existing == null, error);
201 return osRouterIface;
202 });
203 }
204
205 @Override
206 public void updateRouterInterface(RouterInterface osRouterIface) {
207 osRouterInterfaceStore.compute(osRouterIface.getPortId(), (id, existing) -> {
208 final String error = osRouterIface.getPortId() + ERR_NOT_FOUND;
209 checkArgument(existing != null, error);
210 return osRouterIface;
211 });
212 }
213
214 @Override
215 public RouterInterface removeRouterInterface(String routerIfaceId) {
216 Versioned<RouterInterface> osRouterIface = osRouterInterfaceStore.remove(routerIfaceId);
217 return osRouterIface == null ? null : osRouterIface.value();
218 }
219
220 @Override
221 public RouterInterface routerInterface(String routerIfaceId) {
Jian Li78885a22018-03-02 11:33:02 +0900222 return osRouterInterfaceStore.asJavaMap().get(routerIfaceId);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900223 }
224
225 @Override
226 public Set<RouterInterface> routerInterfaces() {
Jian Li78885a22018-03-02 11:33:02 +0900227 return ImmutableSet.copyOf(osRouterInterfaceStore.asJavaMap().values());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900228 }
229
230 @Override
231 public void createFloatingIp(NetFloatingIP osFloatingIp) {
232 osFloatingIpStore.compute(osFloatingIp.getId(), (id, existing) -> {
233 final String error = osFloatingIp.getId() + ERR_DUPLICATE;
234 checkArgument(existing == null, error);
235 return osFloatingIp;
236 });
237 }
238
239 @Override
240 public void updateFloatingIp(NetFloatingIP osFloatingIp) {
241 osFloatingIpStore.compute(osFloatingIp.getId(), (id, existing) -> {
242 final String error = osFloatingIp.getId() + ERR_NOT_FOUND;
243 checkArgument(existing != null, error);
244 return osFloatingIp;
245 });
246 }
247
248 @Override
249 public NetFloatingIP removeFloatingIp(String floatingIpId) {
250 Versioned<NetFloatingIP> osFloatingIp = osFloatingIpStore.remove(floatingIpId);
251 return osFloatingIp == null ? null : osFloatingIp.value();
252 }
253
254 @Override
255 public NetFloatingIP floatingIp(String floatingIpId) {
Jian Li78885a22018-03-02 11:33:02 +0900256 return osFloatingIpStore.asJavaMap().get(floatingIpId);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900257 }
258
259 @Override
260 public Set<NetFloatingIP> floatingIps() {
Jian Li78885a22018-03-02 11:33:02 +0900261 return ImmutableSet.copyOf(osFloatingIpStore.asJavaMap().values());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900262 }
263
Hyunsun Moonc7219222017-03-27 11:05:59 +0900264 @Override
265 public void clear() {
266 osFloatingIpStore.clear();
267 osRouterInterfaceStore.clear();
268 osRouterStore.clear();
269 }
270
Hyunsun Moon44aac662017-02-18 02:07:01 +0900271 private class OpenstackRouterMapListener implements MapEventListener<String, Router> {
272
273 @Override
274 public void event(MapEvent<String, Router> event) {
275 switch (event.type()) {
276 case UPDATE:
daniel parkb5817102018-02-15 00:18:51 +0900277 log.debug("OpenStack router updated");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900278 eventExecutor.execute(() -> {
279 notifyDelegate(new OpenstackRouterEvent(
280 OPENSTACK_ROUTER_UPDATED,
281 event.newValue().value()));
282 processGatewayUpdate(event);
283 });
284 break;
285 case INSERT:
daniel parkb5817102018-02-15 00:18:51 +0900286 log.debug("OpenStack router created");
Jian Li78885a22018-03-02 11:33:02 +0900287 eventExecutor.execute(() ->
Hyunsun Moon44aac662017-02-18 02:07:01 +0900288 notifyDelegate(new OpenstackRouterEvent(
289 OPENSTACK_ROUTER_CREATED,
Jian Li78885a22018-03-02 11:33:02 +0900290 event.newValue().value()))
291 );
Hyunsun Moon44aac662017-02-18 02:07:01 +0900292 break;
293 case REMOVE:
daniel parkb5817102018-02-15 00:18:51 +0900294 log.debug("OpenStack router removed");
Jian Li78885a22018-03-02 11:33:02 +0900295 eventExecutor.execute(() ->
Hyunsun Moon44aac662017-02-18 02:07:01 +0900296 notifyDelegate(new OpenstackRouterEvent(
297 OPENSTACK_ROUTER_REMOVED,
Jian Li78885a22018-03-02 11:33:02 +0900298 event.oldValue().value()))
299 );
Hyunsun Moon44aac662017-02-18 02:07:01 +0900300 break;
301 default:
Jian Li78885a22018-03-02 11:33:02 +0900302 log.error("Unsupported openstack router event type");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900303 break;
304 }
305 }
306
307 private void processGatewayUpdate(MapEvent<String, Router> event) {
308 ExternalGateway oldGateway = event.oldValue().value().getExternalGatewayInfo();
309 ExternalGateway newGateway = event.newValue().value().getExternalGatewayInfo();
310
311 if (oldGateway == null && newGateway != null) {
312 notifyDelegate(new OpenstackRouterEvent(
313 OPENSTACK_ROUTER_GATEWAY_ADDED,
314 event.newValue().value(), newGateway));
315 }
316 if (oldGateway != null && newGateway == null) {
317 notifyDelegate(new OpenstackRouterEvent(
Hyunsun Moona5b5f4e2017-03-17 19:01:12 +0900318 OPENSTACK_ROUTER_GATEWAY_REMOVED,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900319 event.newValue().value(), oldGateway));
320 }
321 }
322 }
323
324 private class OpenstackRouterInterfaceMapListener implements MapEventListener<String, RouterInterface> {
325
326 @Override
327 public void event(MapEvent<String, RouterInterface> event) {
328 switch (event.type()) {
329 case UPDATE:
daniel parkb5817102018-02-15 00:18:51 +0900330 log.debug("OpenStack router interface updated");
Jian Li78885a22018-03-02 11:33:02 +0900331 eventExecutor.execute(() ->
Hyunsun Moon44aac662017-02-18 02:07:01 +0900332 notifyDelegate(new OpenstackRouterEvent(
333 OPENSTACK_ROUTER_INTERFACE_UPDATED,
334 router(event.newValue().value().getId()),
Jian Li78885a22018-03-02 11:33:02 +0900335 event.newValue().value()))
336 );
Hyunsun Moon44aac662017-02-18 02:07:01 +0900337 break;
338 case INSERT:
daniel parkb5817102018-02-15 00:18:51 +0900339 log.debug("OpenStack router interface created");
Jian Li78885a22018-03-02 11:33:02 +0900340 eventExecutor.execute(() ->
Hyunsun Moon44aac662017-02-18 02:07:01 +0900341 notifyDelegate(new OpenstackRouterEvent(
342 OPENSTACK_ROUTER_INTERFACE_ADDED,
343 router(event.newValue().value().getId()),
Jian Li78885a22018-03-02 11:33:02 +0900344 event.newValue().value()))
345 );
Hyunsun Moon44aac662017-02-18 02:07:01 +0900346 break;
347 case REMOVE:
daniel parkb5817102018-02-15 00:18:51 +0900348 log.debug("OpenStack router interface removed");
Jian Li78885a22018-03-02 11:33:02 +0900349 eventExecutor.execute(() ->
Hyunsun Moon44aac662017-02-18 02:07:01 +0900350 notifyDelegate(new OpenstackRouterEvent(
351 OPENSTACK_ROUTER_INTERFACE_REMOVED,
352 router(event.oldValue().value().getId()),
Jian Li78885a22018-03-02 11:33:02 +0900353 event.oldValue().value()))
354 );
Hyunsun Moon44aac662017-02-18 02:07:01 +0900355 break;
356 default:
Jian Li78885a22018-03-02 11:33:02 +0900357 log.error("Unsupported openstack router interface event type");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900358 break;
359 }
360 }
361 }
362
363 private class OpenstackFloatingIpMapListener implements MapEventListener<String, NetFloatingIP> {
364
365 @Override
366 public void event(MapEvent<String, NetFloatingIP> event) {
367 switch (event.type()) {
368 case UPDATE:
daniel parkb5817102018-02-15 00:18:51 +0900369 log.debug("OpenStack floating IP updated");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900370 eventExecutor.execute(() -> {
371 Router osRouter = Strings.isNullOrEmpty(
372 event.newValue().value().getRouterId()) ?
373 null :
374 router(event.newValue().value().getRouterId());
375 notifyDelegate(new OpenstackRouterEvent(
376 OPENSTACK_FLOATING_IP_UPDATED,
377 osRouter,
378 event.newValue().value()));
379 processFloatingIpUpdate(event, osRouter);
380 });
381 break;
382 case INSERT:
daniel parkb5817102018-02-15 00:18:51 +0900383 log.debug("OpenStack floating IP created");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900384 eventExecutor.execute(() -> {
385 Router osRouter = Strings.isNullOrEmpty(
386 event.newValue().value().getRouterId()) ?
387 null :
388 router(event.newValue().value().getRouterId());
389 notifyDelegate(new OpenstackRouterEvent(
390 OPENSTACK_FLOATING_IP_CREATED,
391 osRouter,
392 event.newValue().value()));
393 });
394 break;
395 case REMOVE:
daniel parkb5817102018-02-15 00:18:51 +0900396 log.debug("OpenStack floating IP removed");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900397 eventExecutor.execute(() -> {
398 Router osRouter = Strings.isNullOrEmpty(
399 event.oldValue().value().getRouterId()) ?
400 null :
401 router(event.oldValue().value().getRouterId());
402 notifyDelegate(new OpenstackRouterEvent(
403 OPENSTACK_FLOATING_IP_REMOVED,
404 osRouter,
405 event.oldValue().value()));
406 });
407 break;
408 default:
Jian Li78885a22018-03-02 11:33:02 +0900409 log.error("Unsupported openstack floating IP event type");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900410 break;
411 }
412 }
413
414 private void processFloatingIpUpdate(MapEvent<String, NetFloatingIP> event,
415 Router osRouter) {
416 String oldPortId = event.oldValue().value().getPortId();
417 String newPortId = event.newValue().value().getPortId();
418
419 if (Strings.isNullOrEmpty(oldPortId) && !Strings.isNullOrEmpty(newPortId)) {
420 notifyDelegate(new OpenstackRouterEvent(
421 OPENSTACK_FLOATING_IP_ASSOCIATED,
422 osRouter,
423 event.newValue().value(), newPortId));
424 }
425 if (!Strings.isNullOrEmpty(oldPortId) && Strings.isNullOrEmpty(newPortId)) {
426 notifyDelegate(new OpenstackRouterEvent(
427 OPENSTACK_FLOATING_IP_DISASSOCIATED,
428 osRouter,
429 event.newValue().value(), oldPortId));
430 }
431 }
432 }
433}