blob: 19650e39fc833172da73c62b3d7aeea3ceaeae28 [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;
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.IPVersionType;
Jian Li02a94982018-02-03 02:49:07 +090041import org.openstack4j.model.network.Ipv6AddressMode;
42import org.openstack4j.model.network.Ipv6RaMode;
Hyunsun Moon44aac662017-02-18 02:07:01 +090043import org.openstack4j.model.network.Network;
44import org.openstack4j.model.network.NetworkType;
45import org.openstack4j.model.network.Port;
46import org.openstack4j.model.network.State;
47import org.openstack4j.model.network.Subnet;
48import org.openstack4j.openstack.networking.domain.NeutronAllowedAddressPair;
49import org.openstack4j.openstack.networking.domain.NeutronExtraDhcpOptCreate;
50import org.openstack4j.openstack.networking.domain.NeutronHostRoute;
51import org.openstack4j.openstack.networking.domain.NeutronIP;
52import org.openstack4j.openstack.networking.domain.NeutronNetwork;
53import org.openstack4j.openstack.networking.domain.NeutronPool;
54import org.openstack4j.openstack.networking.domain.NeutronPort;
55import org.openstack4j.openstack.networking.domain.NeutronSubnet;
56import org.slf4j.Logger;
57
Jian Licaedc8b2018-02-19 17:21:06 +090058import java.util.LinkedHashMap;
Hyunsun Moonae51e732017-04-25 17:46:21 +090059import java.util.List;
Hyunsun Moon44aac662017-02-18 02:07:01 +090060import java.util.Set;
61import java.util.concurrent.ExecutorService;
62import java.util.stream.Collectors;
63
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;
68import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.*;
69import static org.slf4j.LoggerFactory.getLogger;
70
71/**
72 * Manages the inventory of OpenStack network, subnet, and port using a {@code ConsistentMap}.
73 */
74@Service
75@Component(immediate = true)
76public class DistributedOpenstackNetworkStore
77 extends AbstractStore<OpenstackNetworkEvent, OpenstackNetworkStoreDelegate>
78 implements OpenstackNetworkStore {
79
80 protected final Logger log = getLogger(getClass());
81
82 private static final String ERR_NOT_FOUND = " does not exist";
83 private static final String ERR_DUPLICATE = " already exists";
84
85 private static final KryoNamespace SERIALIZER_NEUTRON_L2 = KryoNamespace.newBuilder()
86 .register(KryoNamespaces.API)
87 .register(Network.class)
88 .register(NeutronNetwork.class)
89 .register(State.class)
90 .register(NetworkType.class)
91 .register(Port.class)
92 .register(NeutronPort.class)
93 .register(NeutronIP.class)
94 .register(NeutronAllowedAddressPair.class)
95 .register(NeutronExtraDhcpOptCreate.class)
96 .register(Subnet.class)
97 .register(NeutronSubnet.class)
98 .register(NeutronPool.class)
99 .register(NeutronHostRoute.class)
100 .register(IPVersionType.class)
Jian Li02a94982018-02-03 02:49:07 +0900101 .register(Ipv6AddressMode.class)
102 .register(Ipv6RaMode.class)
Jian Licaedc8b2018-02-19 17:21:06 +0900103 .register(LinkedHashMap.class)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900104 .build();
105
106 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
107 protected CoreService coreService;
108
109 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
110 protected StorageService storageService;
111
112 private final ExecutorService eventExecutor = newSingleThreadExecutor(
113 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
114
115 private final MapEventListener<String, Network> networkMapListener = new OpenstackNetworkMapListener();
116 private final MapEventListener<String, Subnet> subnetMapListener = new OpenstackSubnetMapListener();
117 private final MapEventListener<String, Port> portMapListener = new OpenstackPortMapListener();
118
119 private ConsistentMap<String, Network> osNetworkStore;
120 private ConsistentMap<String, Subnet> osSubnetStore;
121 private ConsistentMap<String, Port> osPortStore;
122
123 @Activate
124 protected void activate() {
125 ApplicationId appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
126
127 osNetworkStore = storageService.<String, Network>consistentMapBuilder()
128 .withSerializer(Serializer.using(SERIALIZER_NEUTRON_L2))
129 .withName("openstack-networkstore")
130 .withApplicationId(appId)
131 .build();
132 osNetworkStore.addListener(networkMapListener);
133
134 osSubnetStore = storageService.<String, Subnet>consistentMapBuilder()
135 .withSerializer(Serializer.using(SERIALIZER_NEUTRON_L2))
136 .withName("openstack-subnetstore")
137 .withApplicationId(appId)
138 .build();
139 osSubnetStore.addListener(subnetMapListener);
140
141 osPortStore = storageService.<String, Port>consistentMapBuilder()
142 .withSerializer(Serializer.using(SERIALIZER_NEUTRON_L2))
143 .withName("openstack-portstore")
144 .withApplicationId(appId)
145 .build();
146 osPortStore.addListener(portMapListener);
147
148 log.info("Started");
149 }
150
151 @Deactivate
152 protected void deactivate() {
153 osNetworkStore.removeListener(networkMapListener);
154 osSubnetStore.removeListener(subnetMapListener);
155 osPortStore.removeListener(portMapListener);
156 eventExecutor.shutdown();
157
158 log.info("Stopped");
159 }
160
161 @Override
162 public void createNetwork(Network osNet) {
163 osNetworkStore.compute(osNet.getId(), (id, existing) -> {
164 final String error = osNet.getName() + ERR_DUPLICATE;
165 checkArgument(existing == null, error);
166 return osNet;
167 });
168 }
169
170 @Override
171 public void updateNetwork(Network osNet) {
172 osNetworkStore.compute(osNet.getId(), (id, existing) -> {
173 final String error = osNet.getName() + ERR_NOT_FOUND;
174 checkArgument(existing != null, error);
175 return osNet;
176 });
177 }
178
179 @Override
180 public Network removeNetwork(String netId) {
181 Versioned<Network> osNet = osNetworkStore.remove(netId);
182 return osNet == null ? null : osNet.value();
183 }
184
185 @Override
186 public Network network(String netId) {
187 Versioned<Network> versioned = osNetworkStore.get(netId);
188 return versioned == null ? null : versioned.value();
189 }
190
191 @Override
192 public Set<Network> networks() {
193 Set<Network> osNets = osNetworkStore.values().stream()
194 .map(Versioned::value)
195 .collect(Collectors.toSet());
196 return ImmutableSet.copyOf(osNets);
197 }
198
199 @Override
200 public void createSubnet(Subnet osSubnet) {
201 osSubnetStore.compute(osSubnet.getId(), (id, existing) -> {
202 final String error = osSubnet.getId() + ERR_DUPLICATE;
203 checkArgument(existing == null, error);
204 return osSubnet;
205 });
206 }
207
208 @Override
209 public void updateSubnet(Subnet osSubnet) {
210 osSubnetStore.compute(osSubnet.getId(), (id, existing) -> {
211 final String error = osSubnet.getId() + ERR_NOT_FOUND;
212 checkArgument(existing != null, error);
213 return osSubnet;
214 });
215 }
216
217 @Override
218 public Subnet removeSubnet(String subnetId) {
219 Versioned<Subnet> osSubnet = osSubnetStore.remove(subnetId);
220 return osSubnet == null ? null : osSubnet.value();
221 }
222
223 @Override
224 public Subnet subnet(String subnetId) {
225 Versioned<Subnet> osSubnet = osSubnetStore.get(subnetId);
226 return osSubnet == null ? null : osSubnet.value();
227 }
228
229 @Override
230 public Set<Subnet> subnets() {
231 Set<Subnet> osSubnets = osSubnetStore.values().stream()
232 .map(Versioned::value)
233 .collect(Collectors.toSet());
234 return ImmutableSet.copyOf(osSubnets);
235 }
236
237 @Override
238 public void createPort(Port osPort) {
239 osPortStore.compute(osPort.getId(), (id, existing) -> {
240 final String error = osPort.getId() + ERR_DUPLICATE;
241 checkArgument(existing == null, error);
242 return osPort;
243 });
244 }
245
246 @Override
247 public void updatePort(Port osPort) {
248 osPortStore.compute(osPort.getId(), (id, existing) -> {
249 final String error = osPort.getId() + ERR_NOT_FOUND;
250 checkArgument(existing != null, error);
251 return osPort;
252 });
253 }
254
255 @Override
256 public Port removePort(String portId) {
257 Versioned<Port> osPort = osPortStore.remove(portId);
258 return osPort == null ? null : osPort.value();
259 }
260
261 @Override
262 public Port port(String portId) {
263 Versioned<Port> osPort = osPortStore.get(portId);
264 return osPort == null ? null : osPort.value();
265 }
266
267 @Override
268 public Set<Port> ports() {
269 Set<Port> osPorts = osPortStore.values().stream()
270 .map(Versioned::value)
271 .collect(Collectors.toSet());
272 return ImmutableSet.copyOf(osPorts);
273 }
274
Hyunsun Moonc7219222017-03-27 11:05:59 +0900275 @Override
276 public void clear() {
277 osPortStore.clear();
278 osSubnetStore.clear();
279 osNetworkStore.clear();
280 }
281
Hyunsun Moon44aac662017-02-18 02:07:01 +0900282 private class OpenstackNetworkMapListener implements MapEventListener<String, Network> {
283
284 @Override
285 public void event(MapEvent<String, Network> event) {
286 switch (event.type()) {
287 case UPDATE:
daniel parkb5817102018-02-15 00:18:51 +0900288 log.debug("OpenStack network updated");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900289 eventExecutor.execute(() -> {
290 notifyDelegate(new OpenstackNetworkEvent(
291 OPENSTACK_NETWORK_UPDATED,
292 event.newValue().value()));
293 });
294 break;
295 case INSERT:
daniel parkb5817102018-02-15 00:18:51 +0900296 log.debug("OpenStack network created");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900297 eventExecutor.execute(() -> {
298 notifyDelegate(new OpenstackNetworkEvent(
299 OPENSTACK_NETWORK_CREATED,
300 event.newValue().value()));
301 });
302 break;
303 case REMOVE:
daniel parkb5817102018-02-15 00:18:51 +0900304 log.debug("OpenStack network removed");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900305 eventExecutor.execute(() -> {
306 notifyDelegate(new OpenstackNetworkEvent(
307 OPENSTACK_NETWORK_REMOVED,
308 event.oldValue().value()));
309 });
310 break;
311 default:
312 log.error("Unsupported event type");
313 break;
314 }
315 }
316 }
317
318 private class OpenstackSubnetMapListener implements MapEventListener<String, Subnet> {
319
320 @Override
321 public void event(MapEvent<String, Subnet> event) {
322 switch (event.type()) {
323 case UPDATE:
daniel parkb5817102018-02-15 00:18:51 +0900324 log.debug("OpenStack subnet updated");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900325 eventExecutor.execute(() -> {
326 notifyDelegate(new OpenstackNetworkEvent(
327 OPENSTACK_SUBNET_UPDATED,
328 network(event.newValue().value().getNetworkId()),
329 event.newValue().value()));
330 });
331 break;
332 case INSERT:
daniel parkb5817102018-02-15 00:18:51 +0900333 log.debug("OpenStack subnet created");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900334 eventExecutor.execute(() -> {
335 notifyDelegate(new OpenstackNetworkEvent(
336 OPENSTACK_SUBNET_CREATED,
337 network(event.newValue().value().getNetworkId()),
338 event.newValue().value()));
339 });
340 break;
341 case REMOVE:
daniel parkb5817102018-02-15 00:18:51 +0900342 log.debug("OpenStack subnet removed");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900343 eventExecutor.execute(() -> {
344 notifyDelegate(new OpenstackNetworkEvent(
345 OPENSTACK_SUBNET_REMOVED,
346 network(event.oldValue().value().getNetworkId()),
347 event.oldValue().value()));
348 });
349 break;
350 default:
351 log.error("Unsupported event type");
352 break;
353 }
354 }
355 }
356
357 private class OpenstackPortMapListener implements MapEventListener<String, Port> {
358
359 @Override
360 public void event(MapEvent<String, Port> event) {
361 switch (event.type()) {
362 case UPDATE:
daniel parkb5817102018-02-15 00:18:51 +0900363 log.debug("OpenStack port updated");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900364 eventExecutor.execute(() -> {
sangho6a9ff0d2017-03-27 11:23:37 +0900365 Port oldPort = event.oldValue().value();
366 Port newPort = event.newValue().value();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900367 notifyDelegate(new OpenstackNetworkEvent(
368 OPENSTACK_PORT_UPDATED,
sangho6a9ff0d2017-03-27 11:23:37 +0900369 network(event.newValue().value().getNetworkId()), newPort));
Hyunsun Moonae51e732017-04-25 17:46:21 +0900370 processSecurityGroupUpdate(oldPort, newPort);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900371 });
372 break;
373 case INSERT:
daniel parkb5817102018-02-15 00:18:51 +0900374 log.debug("OpenStack port created");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900375 eventExecutor.execute(() -> {
376 notifyDelegate(new OpenstackNetworkEvent(
377 OPENSTACK_PORT_CREATED,
378 network(event.newValue().value().getNetworkId()),
379 event.newValue().value()));
380 });
381 break;
382 case REMOVE:
daniel parkb5817102018-02-15 00:18:51 +0900383 log.debug("OpenStack port removed");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900384 eventExecutor.execute(() -> {
385 notifyDelegate(new OpenstackNetworkEvent(
386 OPENSTACK_PORT_REMOVED,
387 network(event.oldValue().value().getNetworkId()),
388 event.oldValue().value()));
389 });
390 break;
391 default:
392 log.error("Unsupported event type");
393 break;
394 }
395 }
Hyunsun Moonae51e732017-04-25 17:46:21 +0900396
397 private void processSecurityGroupUpdate(Port oldPort, Port newPort) {
398 List<String> oldSecurityGroups = oldPort.getSecurityGroups() == null ?
399 ImmutableList.of() : oldPort.getSecurityGroups();
400 List<String> newSecurityGroups = newPort.getSecurityGroups() == null ?
401 ImmutableList.of() : newPort.getSecurityGroups();
402
403 oldSecurityGroups.stream()
404 .filter(sgId -> !newPort.getSecurityGroups().contains(sgId))
405 .forEach(sgId -> notifyDelegate(new OpenstackNetworkEvent(
406 OPENSTACK_PORT_SECURITY_GROUP_REMOVED, newPort, sgId
407 )));
408
409 newSecurityGroups.stream()
410 .filter(sgId -> !oldPort.getSecurityGroups().contains(sgId))
411 .forEach(sgId -> notifyDelegate(new OpenstackNetworkEvent(
412 OPENSTACK_PORT_SECURITY_GROUP_ADDED, newPort, sgId
413 )));
414 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900415 }
416}