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