blob: fba15997d93ae449f3edfb2783c3b590186fe28d [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;
Hyunsun Moon44aac662017-02-18 02:07:01 +090020import org.onlab.util.KryoNamespace;
21import org.onosproject.core.ApplicationId;
22import org.onosproject.core.CoreService;
23import org.onosproject.openstacknetworking.api.OpenstackNetworkEvent;
24import org.onosproject.openstacknetworking.api.OpenstackNetworkStore;
25import org.onosproject.openstacknetworking.api.OpenstackNetworkStoreDelegate;
26import org.onosproject.store.AbstractStore;
27import org.onosproject.store.serializers.KryoNamespaces;
28import org.onosproject.store.service.ConsistentMap;
29import org.onosproject.store.service.MapEvent;
30import org.onosproject.store.service.MapEventListener;
31import org.onosproject.store.service.Serializer;
32import org.onosproject.store.service.StorageService;
33import org.onosproject.store.service.Versioned;
34import org.openstack4j.model.network.IPVersionType;
Jian Li02a94982018-02-03 02:49:07 +090035import org.openstack4j.model.network.Ipv6AddressMode;
36import org.openstack4j.model.network.Ipv6RaMode;
Hyunsun Moon44aac662017-02-18 02:07:01 +090037import org.openstack4j.model.network.Network;
38import org.openstack4j.model.network.NetworkType;
39import org.openstack4j.model.network.Port;
40import org.openstack4j.model.network.State;
41import org.openstack4j.model.network.Subnet;
42import org.openstack4j.openstack.networking.domain.NeutronAllowedAddressPair;
43import org.openstack4j.openstack.networking.domain.NeutronExtraDhcpOptCreate;
44import org.openstack4j.openstack.networking.domain.NeutronHostRoute;
45import org.openstack4j.openstack.networking.domain.NeutronIP;
46import org.openstack4j.openstack.networking.domain.NeutronNetwork;
47import org.openstack4j.openstack.networking.domain.NeutronPool;
48import org.openstack4j.openstack.networking.domain.NeutronPort;
49import org.openstack4j.openstack.networking.domain.NeutronSubnet;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070050import org.osgi.service.component.annotations.Activate;
51import org.osgi.service.component.annotations.Component;
52import org.osgi.service.component.annotations.Deactivate;
53import org.osgi.service.component.annotations.Reference;
54import org.osgi.service.component.annotations.ReferenceCardinality;
Hyunsun Moon44aac662017-02-18 02:07:01 +090055import org.slf4j.Logger;
56
Jian Licaedc8b2018-02-19 17:21:06 +090057import java.util.LinkedHashMap;
Hyunsun Moonae51e732017-04-25 17:46:21 +090058import java.util.List;
Jian Lib7873422018-08-18 22:34:39 +090059import java.util.Objects;
Hyunsun Moon44aac662017-02-18 02:07:01 +090060import java.util.Set;
61import java.util.concurrent.ExecutorService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090062
63import static com.google.common.base.Preconditions.checkArgument;
64import static java.util.concurrent.Executors.newSingleThreadExecutor;
65import static org.onlab.util.Tools.groupedThreads;
66import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
Jian Li78885a22018-03-02 11:33:02 +090067import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_NETWORK_CREATED;
68import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_NETWORK_REMOVED;
69import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_NETWORK_UPDATED;
70import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_PORT_CREATED;
Jian Li8f64feb2018-07-24 13:20:16 +090071import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_PORT_PRE_REMOVE;
Jian Li78885a22018-03-02 11:33:02 +090072import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_PORT_REMOVED;
73import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_PORT_SECURITY_GROUP_ADDED;
74import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_PORT_SECURITY_GROUP_REMOVED;
75import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_PORT_UPDATED;
76import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_SUBNET_CREATED;
77import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_SUBNET_REMOVED;
78import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_SUBNET_UPDATED;
Hyunsun Moon44aac662017-02-18 02:07:01 +090079import static org.slf4j.LoggerFactory.getLogger;
80
81/**
82 * Manages the inventory of OpenStack network, subnet, and port using a {@code ConsistentMap}.
83 */
Ray Milkeyd84f89b2018-08-17 14:54:17 -070084@Component(immediate = true, service = OpenstackNetworkStore.class)
Hyunsun Moon44aac662017-02-18 02:07:01 +090085public class DistributedOpenstackNetworkStore
86 extends AbstractStore<OpenstackNetworkEvent, OpenstackNetworkStoreDelegate>
87 implements OpenstackNetworkStore {
88
89 protected final Logger log = getLogger(getClass());
90
91 private static final String ERR_NOT_FOUND = " does not exist";
92 private static final String ERR_DUPLICATE = " already exists";
93
94 private static final KryoNamespace SERIALIZER_NEUTRON_L2 = KryoNamespace.newBuilder()
95 .register(KryoNamespaces.API)
96 .register(Network.class)
97 .register(NeutronNetwork.class)
98 .register(State.class)
99 .register(NetworkType.class)
100 .register(Port.class)
101 .register(NeutronPort.class)
102 .register(NeutronIP.class)
103 .register(NeutronAllowedAddressPair.class)
104 .register(NeutronExtraDhcpOptCreate.class)
105 .register(Subnet.class)
106 .register(NeutronSubnet.class)
107 .register(NeutronPool.class)
108 .register(NeutronHostRoute.class)
109 .register(IPVersionType.class)
Jian Li02a94982018-02-03 02:49:07 +0900110 .register(Ipv6AddressMode.class)
111 .register(Ipv6RaMode.class)
Jian Licaedc8b2018-02-19 17:21:06 +0900112 .register(LinkedHashMap.class)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900113 .build();
114
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700115 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900116 protected CoreService coreService;
117
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700118 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900119 protected StorageService storageService;
120
121 private final ExecutorService eventExecutor = newSingleThreadExecutor(
122 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
123
124 private final MapEventListener<String, Network> networkMapListener = new OpenstackNetworkMapListener();
125 private final MapEventListener<String, Subnet> subnetMapListener = new OpenstackSubnetMapListener();
126 private final MapEventListener<String, Port> portMapListener = new OpenstackPortMapListener();
127
128 private ConsistentMap<String, Network> osNetworkStore;
129 private ConsistentMap<String, Subnet> osSubnetStore;
130 private ConsistentMap<String, Port> osPortStore;
131
132 @Activate
133 protected void activate() {
134 ApplicationId appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
135
136 osNetworkStore = storageService.<String, Network>consistentMapBuilder()
137 .withSerializer(Serializer.using(SERIALIZER_NEUTRON_L2))
138 .withName("openstack-networkstore")
139 .withApplicationId(appId)
140 .build();
141 osNetworkStore.addListener(networkMapListener);
142
143 osSubnetStore = storageService.<String, Subnet>consistentMapBuilder()
144 .withSerializer(Serializer.using(SERIALIZER_NEUTRON_L2))
145 .withName("openstack-subnetstore")
146 .withApplicationId(appId)
147 .build();
148 osSubnetStore.addListener(subnetMapListener);
149
150 osPortStore = storageService.<String, Port>consistentMapBuilder()
151 .withSerializer(Serializer.using(SERIALIZER_NEUTRON_L2))
152 .withName("openstack-portstore")
153 .withApplicationId(appId)
154 .build();
155 osPortStore.addListener(portMapListener);
156
157 log.info("Started");
158 }
159
160 @Deactivate
161 protected void deactivate() {
162 osNetworkStore.removeListener(networkMapListener);
163 osSubnetStore.removeListener(subnetMapListener);
164 osPortStore.removeListener(portMapListener);
165 eventExecutor.shutdown();
166
167 log.info("Stopped");
168 }
169
170 @Override
171 public void createNetwork(Network osNet) {
172 osNetworkStore.compute(osNet.getId(), (id, existing) -> {
173 final String error = osNet.getName() + ERR_DUPLICATE;
174 checkArgument(existing == null, error);
175 return osNet;
176 });
177 }
178
179 @Override
180 public void updateNetwork(Network osNet) {
181 osNetworkStore.compute(osNet.getId(), (id, existing) -> {
182 final String error = osNet.getName() + ERR_NOT_FOUND;
183 checkArgument(existing != null, error);
184 return osNet;
185 });
186 }
187
188 @Override
189 public Network removeNetwork(String netId) {
190 Versioned<Network> osNet = osNetworkStore.remove(netId);
191 return osNet == null ? null : osNet.value();
192 }
193
194 @Override
195 public Network network(String netId) {
Jian Li78885a22018-03-02 11:33:02 +0900196 return osNetworkStore.asJavaMap().get(netId);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900197 }
198
199 @Override
200 public Set<Network> networks() {
Jian Li78885a22018-03-02 11:33:02 +0900201 return ImmutableSet.copyOf(osNetworkStore.asJavaMap().values());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900202 }
203
204 @Override
205 public void createSubnet(Subnet osSubnet) {
206 osSubnetStore.compute(osSubnet.getId(), (id, existing) -> {
207 final String error = osSubnet.getId() + ERR_DUPLICATE;
208 checkArgument(existing == null, error);
209 return osSubnet;
210 });
211 }
212
213 @Override
214 public void updateSubnet(Subnet osSubnet) {
215 osSubnetStore.compute(osSubnet.getId(), (id, existing) -> {
216 final String error = osSubnet.getId() + ERR_NOT_FOUND;
217 checkArgument(existing != null, error);
218 return osSubnet;
219 });
220 }
221
222 @Override
223 public Subnet removeSubnet(String subnetId) {
224 Versioned<Subnet> osSubnet = osSubnetStore.remove(subnetId);
225 return osSubnet == null ? null : osSubnet.value();
226 }
227
228 @Override
229 public Subnet subnet(String subnetId) {
Jian Li78885a22018-03-02 11:33:02 +0900230 return osSubnetStore.asJavaMap().get(subnetId);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900231 }
232
233 @Override
234 public Set<Subnet> subnets() {
Jian Li78885a22018-03-02 11:33:02 +0900235 return ImmutableSet.copyOf(osSubnetStore.asJavaMap().values());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900236 }
237
238 @Override
239 public void createPort(Port osPort) {
240 osPortStore.compute(osPort.getId(), (id, existing) -> {
241 final String error = osPort.getId() + ERR_DUPLICATE;
242 checkArgument(existing == null, error);
243 return osPort;
244 });
245 }
246
247 @Override
248 public void updatePort(Port osPort) {
249 osPortStore.compute(osPort.getId(), (id, existing) -> {
250 final String error = osPort.getId() + ERR_NOT_FOUND;
251 checkArgument(existing != null, error);
252 return osPort;
253 });
254 }
255
256 @Override
257 public Port removePort(String portId) {
258 Versioned<Port> osPort = osPortStore.remove(portId);
259 return osPort == null ? null : osPort.value();
260 }
261
262 @Override
263 public Port port(String portId) {
Jian Li78885a22018-03-02 11:33:02 +0900264 return osPortStore.asJavaMap().get(portId);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900265 }
266
267 @Override
268 public Set<Port> ports() {
Jian Li78885a22018-03-02 11:33:02 +0900269 return ImmutableSet.copyOf(osPortStore.asJavaMap().values());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900270 }
271
Hyunsun Moonc7219222017-03-27 11:05:59 +0900272 @Override
273 public void clear() {
274 osPortStore.clear();
275 osSubnetStore.clear();
276 osNetworkStore.clear();
277 }
278
Hyunsun Moon44aac662017-02-18 02:07:01 +0900279 private class OpenstackNetworkMapListener implements MapEventListener<String, Network> {
280
281 @Override
282 public void event(MapEvent<String, Network> event) {
283 switch (event.type()) {
284 case UPDATE:
daniel parkb5817102018-02-15 00:18:51 +0900285 log.debug("OpenStack network updated");
Jian Li78885a22018-03-02 11:33:02 +0900286 eventExecutor.execute(() ->
Hyunsun Moon44aac662017-02-18 02:07:01 +0900287 notifyDelegate(new OpenstackNetworkEvent(
288 OPENSTACK_NETWORK_UPDATED,
Jian Li78885a22018-03-02 11:33:02 +0900289 event.newValue().value()))
290 );
Hyunsun Moon44aac662017-02-18 02:07:01 +0900291 break;
292 case INSERT:
daniel parkb5817102018-02-15 00:18:51 +0900293 log.debug("OpenStack network created");
Jian Li78885a22018-03-02 11:33:02 +0900294 eventExecutor.execute(() ->
Hyunsun Moon44aac662017-02-18 02:07:01 +0900295 notifyDelegate(new OpenstackNetworkEvent(
296 OPENSTACK_NETWORK_CREATED,
Jian Li78885a22018-03-02 11:33:02 +0900297 event.newValue().value()))
298 );
Hyunsun Moon44aac662017-02-18 02:07:01 +0900299 break;
300 case REMOVE:
daniel parkb5817102018-02-15 00:18:51 +0900301 log.debug("OpenStack network removed");
Jian Li78885a22018-03-02 11:33:02 +0900302 eventExecutor.execute(() ->
Hyunsun Moon44aac662017-02-18 02:07:01 +0900303 notifyDelegate(new OpenstackNetworkEvent(
304 OPENSTACK_NETWORK_REMOVED,
Jian Li78885a22018-03-02 11:33:02 +0900305 event.oldValue().value()))
306 );
Hyunsun Moon44aac662017-02-18 02:07:01 +0900307 break;
308 default:
Jian Li78885a22018-03-02 11:33:02 +0900309 log.error("Unsupported openstack network event type");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900310 break;
311 }
312 }
313 }
314
315 private class OpenstackSubnetMapListener implements MapEventListener<String, Subnet> {
316
317 @Override
318 public void event(MapEvent<String, Subnet> event) {
319 switch (event.type()) {
320 case UPDATE:
daniel parkb5817102018-02-15 00:18:51 +0900321 log.debug("OpenStack subnet updated");
Jian Li78885a22018-03-02 11:33:02 +0900322 eventExecutor.execute(() ->
Hyunsun Moon44aac662017-02-18 02:07:01 +0900323 notifyDelegate(new OpenstackNetworkEvent(
324 OPENSTACK_SUBNET_UPDATED,
325 network(event.newValue().value().getNetworkId()),
Jian Li78885a22018-03-02 11:33:02 +0900326 event.newValue().value()))
327 );
Hyunsun Moon44aac662017-02-18 02:07:01 +0900328 break;
329 case INSERT:
daniel parkb5817102018-02-15 00:18:51 +0900330 log.debug("OpenStack subnet created");
Jian Li78885a22018-03-02 11:33:02 +0900331 eventExecutor.execute(() ->
Hyunsun Moon44aac662017-02-18 02:07:01 +0900332 notifyDelegate(new OpenstackNetworkEvent(
333 OPENSTACK_SUBNET_CREATED,
334 network(event.newValue().value().getNetworkId()),
Jian Li78885a22018-03-02 11:33:02 +0900335 event.newValue().value()))
336 );
Hyunsun Moon44aac662017-02-18 02:07:01 +0900337 break;
338 case REMOVE:
daniel parkb5817102018-02-15 00:18:51 +0900339 log.debug("OpenStack subnet removed");
Jian Li78885a22018-03-02 11:33:02 +0900340 eventExecutor.execute(() ->
Hyunsun Moon44aac662017-02-18 02:07:01 +0900341 notifyDelegate(new OpenstackNetworkEvent(
342 OPENSTACK_SUBNET_REMOVED,
343 network(event.oldValue().value().getNetworkId()),
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 subnet event type");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900349 break;
350 }
351 }
352 }
353
354 private class OpenstackPortMapListener implements MapEventListener<String, Port> {
355
356 @Override
357 public void event(MapEvent<String, Port> event) {
358 switch (event.type()) {
359 case UPDATE:
Hyunsun Moon44aac662017-02-18 02:07:01 +0900360 eventExecutor.execute(() -> {
sangho6a9ff0d2017-03-27 11:23:37 +0900361 Port oldPort = event.oldValue().value();
362 Port newPort = event.newValue().value();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900363 notifyDelegate(new OpenstackNetworkEvent(
364 OPENSTACK_PORT_UPDATED,
sangho6a9ff0d2017-03-27 11:23:37 +0900365 network(event.newValue().value().getNetworkId()), newPort));
Hyunsun Moonae51e732017-04-25 17:46:21 +0900366 processSecurityGroupUpdate(oldPort, newPort);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900367 });
368 break;
369 case INSERT:
daniel parkb5817102018-02-15 00:18:51 +0900370 log.debug("OpenStack port created");
Jian Li78885a22018-03-02 11:33:02 +0900371 eventExecutor.execute(() ->
Hyunsun Moon44aac662017-02-18 02:07:01 +0900372 notifyDelegate(new OpenstackNetworkEvent(
373 OPENSTACK_PORT_CREATED,
374 network(event.newValue().value().getNetworkId()),
Jian Li78885a22018-03-02 11:33:02 +0900375 event.newValue().value()))
376 );
Hyunsun Moon44aac662017-02-18 02:07:01 +0900377 break;
378 case REMOVE:
daniel parkb5817102018-02-15 00:18:51 +0900379 log.debug("OpenStack port removed");
Jian Li628a7cb2018-08-11 23:04:24 +0900380
381 eventExecutor.execute(() ->
382 notifyDelegate(new OpenstackNetworkEvent(
383 OPENSTACK_PORT_PRE_REMOVE,
384 network(event.oldValue().value().getNetworkId()),
385 event.oldValue().value()))
386 );
387
Jian Li78885a22018-03-02 11:33:02 +0900388 eventExecutor.execute(() ->
Hyunsun Moon44aac662017-02-18 02:07:01 +0900389 notifyDelegate(new OpenstackNetworkEvent(
390 OPENSTACK_PORT_REMOVED,
391 network(event.oldValue().value().getNetworkId()),
Jian Li78885a22018-03-02 11:33:02 +0900392 event.oldValue().value()))
393 );
Hyunsun Moon44aac662017-02-18 02:07:01 +0900394 break;
395 default:
Jian Li78885a22018-03-02 11:33:02 +0900396 log.error("Unsupported openstack port event type");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900397 break;
398 }
399 }
Hyunsun Moonae51e732017-04-25 17:46:21 +0900400
401 private void processSecurityGroupUpdate(Port oldPort, Port newPort) {
402 List<String> oldSecurityGroups = oldPort.getSecurityGroups() == null ?
403 ImmutableList.of() : oldPort.getSecurityGroups();
404 List<String> newSecurityGroups = newPort.getSecurityGroups() == null ?
405 ImmutableList.of() : newPort.getSecurityGroups();
406
407 oldSecurityGroups.stream()
Jian Lib7873422018-08-18 22:34:39 +0900408 .filter(sgId -> !Objects.requireNonNull(newPort.getSecurityGroups()).contains(sgId))
Hyunsun Moonae51e732017-04-25 17:46:21 +0900409 .forEach(sgId -> notifyDelegate(new OpenstackNetworkEvent(
410 OPENSTACK_PORT_SECURITY_GROUP_REMOVED, newPort, sgId
411 )));
412
413 newSecurityGroups.stream()
414 .filter(sgId -> !oldPort.getSecurityGroups().contains(sgId))
415 .forEach(sgId -> notifyDelegate(new OpenstackNetworkEvent(
416 OPENSTACK_PORT_SECURITY_GROUP_ADDED, newPort, sgId
417 )));
418 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900419 }
420}