blob: 04ca5942de233704838898c06d7c8ba0fa0b1689 [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
Hyunsun Moonae51e732017-04-25 17:46:21 +090018import com.google.common.collect.ImmutableList;
Hyunsun Moon44aac662017-02-18 02:07:01 +090019import 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;
Hyunsun Moon44aac662017-02-18 02:07:01 +090024import org.apache.felix.scr.annotations.ReferenceCardinality;
sangho6a9ff0d2017-03-27 11:23:37 +090025import org.apache.felix.scr.annotations.Service;
Hyunsun Moon44aac662017-02-18 02:07:01 +090026import org.onlab.util.KryoNamespace;
27import org.onosproject.core.ApplicationId;
28import org.onosproject.core.CoreService;
29import org.onosproject.openstacknetworking.api.OpenstackNetworkEvent;
30import org.onosproject.openstacknetworking.api.OpenstackNetworkStore;
31import org.onosproject.openstacknetworking.api.OpenstackNetworkStoreDelegate;
Jian Li8f64feb2018-07-24 13:20:16 +090032import org.onosproject.openstacknetworking.api.PreCommitPortService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090033import org.onosproject.store.AbstractStore;
34import org.onosproject.store.serializers.KryoNamespaces;
35import org.onosproject.store.service.ConsistentMap;
36import org.onosproject.store.service.MapEvent;
37import org.onosproject.store.service.MapEventListener;
38import org.onosproject.store.service.Serializer;
39import org.onosproject.store.service.StorageService;
40import org.onosproject.store.service.Versioned;
41import org.openstack4j.model.network.IPVersionType;
Jian Li02a94982018-02-03 02:49:07 +090042import org.openstack4j.model.network.Ipv6AddressMode;
43import org.openstack4j.model.network.Ipv6RaMode;
Hyunsun Moon44aac662017-02-18 02:07:01 +090044import org.openstack4j.model.network.Network;
45import org.openstack4j.model.network.NetworkType;
46import org.openstack4j.model.network.Port;
47import org.openstack4j.model.network.State;
48import org.openstack4j.model.network.Subnet;
49import org.openstack4j.openstack.networking.domain.NeutronAllowedAddressPair;
50import org.openstack4j.openstack.networking.domain.NeutronExtraDhcpOptCreate;
51import org.openstack4j.openstack.networking.domain.NeutronHostRoute;
52import org.openstack4j.openstack.networking.domain.NeutronIP;
53import org.openstack4j.openstack.networking.domain.NeutronNetwork;
54import org.openstack4j.openstack.networking.domain.NeutronPool;
55import org.openstack4j.openstack.networking.domain.NeutronPort;
56import org.openstack4j.openstack.networking.domain.NeutronSubnet;
57import org.slf4j.Logger;
58
Jian Licaedc8b2018-02-19 17:21:06 +090059import java.util.LinkedHashMap;
Hyunsun Moonae51e732017-04-25 17:46:21 +090060import java.util.List;
Hyunsun Moon44aac662017-02-18 02:07:01 +090061import java.util.Set;
62import java.util.concurrent.ExecutorService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090063
64import static com.google.common.base.Preconditions.checkArgument;
65import static java.util.concurrent.Executors.newSingleThreadExecutor;
66import static org.onlab.util.Tools.groupedThreads;
67import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
Jian Li78885a22018-03-02 11:33:02 +090068import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_NETWORK_CREATED;
69import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_NETWORK_REMOVED;
70import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_NETWORK_UPDATED;
71import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_PORT_CREATED;
Jian Li8f64feb2018-07-24 13:20:16 +090072import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_PORT_PRE_REMOVE;
Jian Li78885a22018-03-02 11:33:02 +090073import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_PORT_REMOVED;
74import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_PORT_SECURITY_GROUP_ADDED;
75import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_PORT_SECURITY_GROUP_REMOVED;
76import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_PORT_UPDATED;
77import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_SUBNET_CREATED;
78import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_SUBNET_REMOVED;
79import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_SUBNET_UPDATED;
Hyunsun Moon44aac662017-02-18 02:07:01 +090080import static org.slf4j.LoggerFactory.getLogger;
81
82/**
83 * Manages the inventory of OpenStack network, subnet, and port using a {@code ConsistentMap}.
84 */
85@Service
86@Component(immediate = true)
87public class DistributedOpenstackNetworkStore
88 extends AbstractStore<OpenstackNetworkEvent, OpenstackNetworkStoreDelegate>
89 implements OpenstackNetworkStore {
90
91 protected final Logger log = getLogger(getClass());
92
93 private static final String ERR_NOT_FOUND = " does not exist";
94 private static final String ERR_DUPLICATE = " already exists";
95
Jian Lida03ce92018-07-24 21:41:53 +090096 private static final long TIMEOUT_MS = 2000; // wait for 2s
97
Hyunsun Moon44aac662017-02-18 02:07:01 +090098 private static final KryoNamespace SERIALIZER_NEUTRON_L2 = KryoNamespace.newBuilder()
99 .register(KryoNamespaces.API)
100 .register(Network.class)
101 .register(NeutronNetwork.class)
102 .register(State.class)
103 .register(NetworkType.class)
104 .register(Port.class)
105 .register(NeutronPort.class)
106 .register(NeutronIP.class)
107 .register(NeutronAllowedAddressPair.class)
108 .register(NeutronExtraDhcpOptCreate.class)
109 .register(Subnet.class)
110 .register(NeutronSubnet.class)
111 .register(NeutronPool.class)
112 .register(NeutronHostRoute.class)
113 .register(IPVersionType.class)
Jian Li02a94982018-02-03 02:49:07 +0900114 .register(Ipv6AddressMode.class)
115 .register(Ipv6RaMode.class)
Jian Licaedc8b2018-02-19 17:21:06 +0900116 .register(LinkedHashMap.class)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900117 .build();
118
119 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
120 protected CoreService coreService;
121
122 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
123 protected StorageService storageService;
124
Jian Li8f64feb2018-07-24 13:20:16 +0900125 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
126 protected PreCommitPortService preCommitPortService;
127
Hyunsun Moon44aac662017-02-18 02:07:01 +0900128 private final ExecutorService eventExecutor = newSingleThreadExecutor(
129 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
130
131 private final MapEventListener<String, Network> networkMapListener = new OpenstackNetworkMapListener();
132 private final MapEventListener<String, Subnet> subnetMapListener = new OpenstackSubnetMapListener();
133 private final MapEventListener<String, Port> portMapListener = new OpenstackPortMapListener();
134
135 private ConsistentMap<String, Network> osNetworkStore;
136 private ConsistentMap<String, Subnet> osSubnetStore;
137 private ConsistentMap<String, Port> osPortStore;
138
139 @Activate
140 protected void activate() {
141 ApplicationId appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
142
143 osNetworkStore = storageService.<String, Network>consistentMapBuilder()
144 .withSerializer(Serializer.using(SERIALIZER_NEUTRON_L2))
145 .withName("openstack-networkstore")
146 .withApplicationId(appId)
147 .build();
148 osNetworkStore.addListener(networkMapListener);
149
150 osSubnetStore = storageService.<String, Subnet>consistentMapBuilder()
151 .withSerializer(Serializer.using(SERIALIZER_NEUTRON_L2))
152 .withName("openstack-subnetstore")
153 .withApplicationId(appId)
154 .build();
155 osSubnetStore.addListener(subnetMapListener);
156
157 osPortStore = storageService.<String, Port>consistentMapBuilder()
158 .withSerializer(Serializer.using(SERIALIZER_NEUTRON_L2))
159 .withName("openstack-portstore")
160 .withApplicationId(appId)
161 .build();
162 osPortStore.addListener(portMapListener);
163
164 log.info("Started");
165 }
166
167 @Deactivate
168 protected void deactivate() {
169 osNetworkStore.removeListener(networkMapListener);
170 osSubnetStore.removeListener(subnetMapListener);
171 osPortStore.removeListener(portMapListener);
172 eventExecutor.shutdown();
173
174 log.info("Stopped");
175 }
176
177 @Override
178 public void createNetwork(Network osNet) {
179 osNetworkStore.compute(osNet.getId(), (id, existing) -> {
180 final String error = osNet.getName() + ERR_DUPLICATE;
181 checkArgument(existing == null, error);
182 return osNet;
183 });
184 }
185
186 @Override
187 public void updateNetwork(Network osNet) {
188 osNetworkStore.compute(osNet.getId(), (id, existing) -> {
189 final String error = osNet.getName() + ERR_NOT_FOUND;
190 checkArgument(existing != null, error);
191 return osNet;
192 });
193 }
194
195 @Override
196 public Network removeNetwork(String netId) {
197 Versioned<Network> osNet = osNetworkStore.remove(netId);
198 return osNet == null ? null : osNet.value();
199 }
200
201 @Override
202 public Network network(String netId) {
Jian Li78885a22018-03-02 11:33:02 +0900203 return osNetworkStore.asJavaMap().get(netId);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900204 }
205
206 @Override
207 public Set<Network> networks() {
Jian Li78885a22018-03-02 11:33:02 +0900208 return ImmutableSet.copyOf(osNetworkStore.asJavaMap().values());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900209 }
210
211 @Override
212 public void createSubnet(Subnet osSubnet) {
213 osSubnetStore.compute(osSubnet.getId(), (id, existing) -> {
214 final String error = osSubnet.getId() + ERR_DUPLICATE;
215 checkArgument(existing == null, error);
216 return osSubnet;
217 });
218 }
219
220 @Override
221 public void updateSubnet(Subnet osSubnet) {
222 osSubnetStore.compute(osSubnet.getId(), (id, existing) -> {
223 final String error = osSubnet.getId() + ERR_NOT_FOUND;
224 checkArgument(existing != null, error);
225 return osSubnet;
226 });
227 }
228
229 @Override
230 public Subnet removeSubnet(String subnetId) {
231 Versioned<Subnet> osSubnet = osSubnetStore.remove(subnetId);
232 return osSubnet == null ? null : osSubnet.value();
233 }
234
235 @Override
236 public Subnet subnet(String subnetId) {
Jian Li78885a22018-03-02 11:33:02 +0900237 return osSubnetStore.asJavaMap().get(subnetId);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900238 }
239
240 @Override
241 public Set<Subnet> subnets() {
Jian Li78885a22018-03-02 11:33:02 +0900242 return ImmutableSet.copyOf(osSubnetStore.asJavaMap().values());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900243 }
244
245 @Override
246 public void createPort(Port osPort) {
247 osPortStore.compute(osPort.getId(), (id, existing) -> {
248 final String error = osPort.getId() + ERR_DUPLICATE;
249 checkArgument(existing == null, error);
250 return osPort;
251 });
252 }
253
254 @Override
255 public void updatePort(Port osPort) {
256 osPortStore.compute(osPort.getId(), (id, existing) -> {
257 final String error = osPort.getId() + ERR_NOT_FOUND;
258 checkArgument(existing != null, error);
259 return osPort;
260 });
261 }
262
263 @Override
264 public Port removePort(String portId) {
Jian Li8f64feb2018-07-24 13:20:16 +0900265
266 Port port = osPortStore.asJavaMap().get(portId);
267
268 if (port == null) {
269 return null;
270 }
271
272 eventExecutor.execute(() ->
273 notifyDelegate(new OpenstackNetworkEvent(
274 OPENSTACK_PORT_PRE_REMOVE,
275 network(port.getNetworkId()), port))
276 );
277
278 log.debug("Prepare OpenStack port remove");
279
Jian Lida03ce92018-07-24 21:41:53 +0900280 long timeoutExpiredMs = System.currentTimeMillis() + TIMEOUT_MS;
281
Jian Li8f64feb2018-07-24 13:20:16 +0900282 while (true) {
Jian Lida03ce92018-07-24 21:41:53 +0900283
284 long waitMs = timeoutExpiredMs - System.currentTimeMillis();
285
Jian Li8f64feb2018-07-24 13:20:16 +0900286 if (preCommitPortService.subscriberCountByEventType(
287 portId, OPENSTACK_PORT_PRE_REMOVE) == 0) {
288 break;
289 }
Jian Lida03ce92018-07-24 21:41:53 +0900290
291 if (waitMs <= 0) {
292 log.debug("Timeout waiting for port removal.");
293 break;
294 }
Jian Li8f64feb2018-07-24 13:20:16 +0900295 }
296
Hyunsun Moon44aac662017-02-18 02:07:01 +0900297 Versioned<Port> osPort = osPortStore.remove(portId);
298 return osPort == null ? null : osPort.value();
299 }
300
301 @Override
302 public Port port(String portId) {
Jian Li78885a22018-03-02 11:33:02 +0900303 return osPortStore.asJavaMap().get(portId);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900304 }
305
306 @Override
307 public Set<Port> ports() {
Jian Li78885a22018-03-02 11:33:02 +0900308 return ImmutableSet.copyOf(osPortStore.asJavaMap().values());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900309 }
310
Hyunsun Moonc7219222017-03-27 11:05:59 +0900311 @Override
312 public void clear() {
313 osPortStore.clear();
314 osSubnetStore.clear();
315 osNetworkStore.clear();
316 }
317
Hyunsun Moon44aac662017-02-18 02:07:01 +0900318 private class OpenstackNetworkMapListener implements MapEventListener<String, Network> {
319
320 @Override
321 public void event(MapEvent<String, Network> event) {
322 switch (event.type()) {
323 case UPDATE:
daniel parkb5817102018-02-15 00:18:51 +0900324 log.debug("OpenStack network updated");
Jian Li78885a22018-03-02 11:33:02 +0900325 eventExecutor.execute(() ->
Hyunsun Moon44aac662017-02-18 02:07:01 +0900326 notifyDelegate(new OpenstackNetworkEvent(
327 OPENSTACK_NETWORK_UPDATED,
Jian Li78885a22018-03-02 11:33:02 +0900328 event.newValue().value()))
329 );
Hyunsun Moon44aac662017-02-18 02:07:01 +0900330 break;
331 case INSERT:
daniel parkb5817102018-02-15 00:18:51 +0900332 log.debug("OpenStack network created");
Jian Li78885a22018-03-02 11:33:02 +0900333 eventExecutor.execute(() ->
Hyunsun Moon44aac662017-02-18 02:07:01 +0900334 notifyDelegate(new OpenstackNetworkEvent(
335 OPENSTACK_NETWORK_CREATED,
Jian Li78885a22018-03-02 11:33:02 +0900336 event.newValue().value()))
337 );
Hyunsun Moon44aac662017-02-18 02:07:01 +0900338 break;
339 case REMOVE:
daniel parkb5817102018-02-15 00:18:51 +0900340 log.debug("OpenStack network removed");
Jian Li78885a22018-03-02 11:33:02 +0900341 eventExecutor.execute(() ->
Hyunsun Moon44aac662017-02-18 02:07:01 +0900342 notifyDelegate(new OpenstackNetworkEvent(
343 OPENSTACK_NETWORK_REMOVED,
Jian Li78885a22018-03-02 11:33:02 +0900344 event.oldValue().value()))
345 );
Hyunsun Moon44aac662017-02-18 02:07:01 +0900346 break;
347 default:
Jian Li78885a22018-03-02 11:33:02 +0900348 log.error("Unsupported openstack network event type");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900349 break;
350 }
351 }
352 }
353
354 private class OpenstackSubnetMapListener implements MapEventListener<String, Subnet> {
355
356 @Override
357 public void event(MapEvent<String, Subnet> event) {
358 switch (event.type()) {
359 case UPDATE:
daniel parkb5817102018-02-15 00:18:51 +0900360 log.debug("OpenStack subnet updated");
Jian Li78885a22018-03-02 11:33:02 +0900361 eventExecutor.execute(() ->
Hyunsun Moon44aac662017-02-18 02:07:01 +0900362 notifyDelegate(new OpenstackNetworkEvent(
363 OPENSTACK_SUBNET_UPDATED,
364 network(event.newValue().value().getNetworkId()),
Jian Li78885a22018-03-02 11:33:02 +0900365 event.newValue().value()))
366 );
Hyunsun Moon44aac662017-02-18 02:07:01 +0900367 break;
368 case INSERT:
daniel parkb5817102018-02-15 00:18:51 +0900369 log.debug("OpenStack subnet created");
Jian Li78885a22018-03-02 11:33:02 +0900370 eventExecutor.execute(() ->
Hyunsun Moon44aac662017-02-18 02:07:01 +0900371 notifyDelegate(new OpenstackNetworkEvent(
372 OPENSTACK_SUBNET_CREATED,
373 network(event.newValue().value().getNetworkId()),
Jian Li78885a22018-03-02 11:33:02 +0900374 event.newValue().value()))
375 );
Hyunsun Moon44aac662017-02-18 02:07:01 +0900376 break;
377 case REMOVE:
daniel parkb5817102018-02-15 00:18:51 +0900378 log.debug("OpenStack subnet removed");
Jian Li78885a22018-03-02 11:33:02 +0900379 eventExecutor.execute(() ->
Hyunsun Moon44aac662017-02-18 02:07:01 +0900380 notifyDelegate(new OpenstackNetworkEvent(
381 OPENSTACK_SUBNET_REMOVED,
382 network(event.oldValue().value().getNetworkId()),
Jian Li78885a22018-03-02 11:33:02 +0900383 event.oldValue().value()))
384 );
Hyunsun Moon44aac662017-02-18 02:07:01 +0900385 break;
386 default:
Jian Li78885a22018-03-02 11:33:02 +0900387 log.error("Unsupported openstack subnet event type");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900388 break;
389 }
390 }
391 }
392
393 private class OpenstackPortMapListener implements MapEventListener<String, Port> {
394
395 @Override
396 public void event(MapEvent<String, Port> event) {
397 switch (event.type()) {
398 case UPDATE:
daniel parkb5817102018-02-15 00:18:51 +0900399 log.debug("OpenStack port updated");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900400 eventExecutor.execute(() -> {
sangho6a9ff0d2017-03-27 11:23:37 +0900401 Port oldPort = event.oldValue().value();
402 Port newPort = event.newValue().value();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900403 notifyDelegate(new OpenstackNetworkEvent(
404 OPENSTACK_PORT_UPDATED,
sangho6a9ff0d2017-03-27 11:23:37 +0900405 network(event.newValue().value().getNetworkId()), newPort));
Hyunsun Moonae51e732017-04-25 17:46:21 +0900406 processSecurityGroupUpdate(oldPort, newPort);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900407 });
408 break;
409 case INSERT:
daniel parkb5817102018-02-15 00:18:51 +0900410 log.debug("OpenStack port created");
Jian Li78885a22018-03-02 11:33:02 +0900411 eventExecutor.execute(() ->
Hyunsun Moon44aac662017-02-18 02:07:01 +0900412 notifyDelegate(new OpenstackNetworkEvent(
413 OPENSTACK_PORT_CREATED,
414 network(event.newValue().value().getNetworkId()),
Jian Li78885a22018-03-02 11:33:02 +0900415 event.newValue().value()))
416 );
Hyunsun Moon44aac662017-02-18 02:07:01 +0900417 break;
418 case REMOVE:
daniel parkb5817102018-02-15 00:18:51 +0900419 log.debug("OpenStack port removed");
Jian Li78885a22018-03-02 11:33:02 +0900420 eventExecutor.execute(() ->
Hyunsun Moon44aac662017-02-18 02:07:01 +0900421 notifyDelegate(new OpenstackNetworkEvent(
422 OPENSTACK_PORT_REMOVED,
423 network(event.oldValue().value().getNetworkId()),
Jian Li78885a22018-03-02 11:33:02 +0900424 event.oldValue().value()))
425 );
Hyunsun Moon44aac662017-02-18 02:07:01 +0900426 break;
427 default:
Jian Li78885a22018-03-02 11:33:02 +0900428 log.error("Unsupported openstack port event type");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900429 break;
430 }
431 }
Hyunsun Moonae51e732017-04-25 17:46:21 +0900432
433 private void processSecurityGroupUpdate(Port oldPort, Port newPort) {
434 List<String> oldSecurityGroups = oldPort.getSecurityGroups() == null ?
435 ImmutableList.of() : oldPort.getSecurityGroups();
436 List<String> newSecurityGroups = newPort.getSecurityGroups() == null ?
437 ImmutableList.of() : newPort.getSecurityGroups();
438
439 oldSecurityGroups.stream()
440 .filter(sgId -> !newPort.getSecurityGroups().contains(sgId))
441 .forEach(sgId -> notifyDelegate(new OpenstackNetworkEvent(
442 OPENSTACK_PORT_SECURITY_GROUP_REMOVED, newPort, sgId
443 )));
444
445 newSecurityGroups.stream()
446 .filter(sgId -> !oldPort.getSecurityGroups().contains(sgId))
447 .forEach(sgId -> notifyDelegate(new OpenstackNetworkEvent(
448 OPENSTACK_PORT_SECURITY_GROUP_ADDED, newPort, sgId
449 )));
450 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900451 }
452}