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