blob: d16647c8f35a882e2126f9b7e297ba73165afdfd [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
Jian Li0488c732018-09-14 20:53:07 +0900324 private class OpenstackRouterInterfaceMapListener
325 implements MapEventListener<String, RouterInterface> {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900326
327 @Override
328 public void event(MapEvent<String, RouterInterface> event) {
329 switch (event.type()) {
330 case UPDATE:
daniel parkb5817102018-02-15 00:18:51 +0900331 log.debug("OpenStack router interface updated");
Jian Li78885a22018-03-02 11:33:02 +0900332 eventExecutor.execute(() ->
Hyunsun Moon44aac662017-02-18 02:07:01 +0900333 notifyDelegate(new OpenstackRouterEvent(
334 OPENSTACK_ROUTER_INTERFACE_UPDATED,
335 router(event.newValue().value().getId()),
Jian Li78885a22018-03-02 11:33:02 +0900336 event.newValue().value()))
337 );
Hyunsun Moon44aac662017-02-18 02:07:01 +0900338 break;
339 case INSERT:
daniel parkb5817102018-02-15 00:18:51 +0900340 log.debug("OpenStack router interface created");
Jian Li78885a22018-03-02 11:33:02 +0900341 eventExecutor.execute(() ->
Hyunsun Moon44aac662017-02-18 02:07:01 +0900342 notifyDelegate(new OpenstackRouterEvent(
343 OPENSTACK_ROUTER_INTERFACE_ADDED,
344 router(event.newValue().value().getId()),
Jian Li78885a22018-03-02 11:33:02 +0900345 event.newValue().value()))
346 );
Hyunsun Moon44aac662017-02-18 02:07:01 +0900347 break;
348 case REMOVE:
daniel parkb5817102018-02-15 00:18:51 +0900349 log.debug("OpenStack router interface removed");
Jian Li78885a22018-03-02 11:33:02 +0900350 eventExecutor.execute(() ->
Hyunsun Moon44aac662017-02-18 02:07:01 +0900351 notifyDelegate(new OpenstackRouterEvent(
352 OPENSTACK_ROUTER_INTERFACE_REMOVED,
353 router(event.oldValue().value().getId()),
Jian Li78885a22018-03-02 11:33:02 +0900354 event.oldValue().value()))
355 );
Hyunsun Moon44aac662017-02-18 02:07:01 +0900356 break;
357 default:
Jian Li78885a22018-03-02 11:33:02 +0900358 log.error("Unsupported openstack router interface event type");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900359 break;
360 }
361 }
362 }
363
Jian Li0488c732018-09-14 20:53:07 +0900364 private class OpenstackFloatingIpMapListener
365 implements MapEventListener<String, NetFloatingIP> {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900366
367 @Override
368 public void event(MapEvent<String, NetFloatingIP> event) {
369 switch (event.type()) {
370 case UPDATE:
daniel parkb5817102018-02-15 00:18:51 +0900371 log.debug("OpenStack floating IP updated");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900372 eventExecutor.execute(() -> {
373 Router osRouter = Strings.isNullOrEmpty(
374 event.newValue().value().getRouterId()) ?
375 null :
376 router(event.newValue().value().getRouterId());
377 notifyDelegate(new OpenstackRouterEvent(
378 OPENSTACK_FLOATING_IP_UPDATED,
379 osRouter,
380 event.newValue().value()));
381 processFloatingIpUpdate(event, osRouter);
382 });
383 break;
384 case INSERT:
daniel parkb5817102018-02-15 00:18:51 +0900385 log.debug("OpenStack floating IP created");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900386 eventExecutor.execute(() -> {
387 Router osRouter = Strings.isNullOrEmpty(
388 event.newValue().value().getRouterId()) ?
389 null :
390 router(event.newValue().value().getRouterId());
391 notifyDelegate(new OpenstackRouterEvent(
392 OPENSTACK_FLOATING_IP_CREATED,
393 osRouter,
394 event.newValue().value()));
395 });
396 break;
397 case REMOVE:
daniel parkb5817102018-02-15 00:18:51 +0900398 log.debug("OpenStack floating IP removed");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900399 eventExecutor.execute(() -> {
400 Router osRouter = Strings.isNullOrEmpty(
401 event.oldValue().value().getRouterId()) ?
402 null :
403 router(event.oldValue().value().getRouterId());
404 notifyDelegate(new OpenstackRouterEvent(
405 OPENSTACK_FLOATING_IP_REMOVED,
406 osRouter,
407 event.oldValue().value()));
408 });
409 break;
410 default:
Jian Li78885a22018-03-02 11:33:02 +0900411 log.error("Unsupported openstack floating IP event type");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900412 break;
413 }
414 }
415
416 private void processFloatingIpUpdate(MapEvent<String, NetFloatingIP> event,
417 Router osRouter) {
418 String oldPortId = event.oldValue().value().getPortId();
419 String newPortId = event.newValue().value().getPortId();
420
421 if (Strings.isNullOrEmpty(oldPortId) && !Strings.isNullOrEmpty(newPortId)) {
422 notifyDelegate(new OpenstackRouterEvent(
423 OPENSTACK_FLOATING_IP_ASSOCIATED,
424 osRouter,
425 event.newValue().value(), newPortId));
426 }
427 if (!Strings.isNullOrEmpty(oldPortId) && Strings.isNullOrEmpty(newPortId)) {
428 notifyDelegate(new OpenstackRouterEvent(
429 OPENSTACK_FLOATING_IP_DISASSOCIATED,
430 osRouter,
431 event.newValue().value(), oldPortId));
432 }
433 }
434 }
435}