blob: 0f955e5b4147c43f97bd70095aa03542464e6ffc [file] [log] [blame]
Jian Li19f25262018-07-03 22:37:12 +09001/*
2 * Copyright 2018-present Open Networking Foundation
3 *
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.openstackvtap.impl;
17
18import com.google.common.collect.ImmutableSet;
19import com.google.common.collect.Maps;
20import com.google.common.collect.Sets;
Jian Li19f25262018-07-03 22:37:12 +090021import org.onlab.util.KryoNamespace;
22import org.onosproject.net.DefaultAnnotations;
23import org.onosproject.net.DeviceId;
24import org.onosproject.net.SparseAnnotations;
25import org.onosproject.openstackvtap.api.OpenstackVtap;
Jimo Jung14e87bf2018-09-03 16:28:13 +090026import org.onosproject.openstackvtap.api.OpenstackVtap.Type;
Jian Li19f25262018-07-03 22:37:12 +090027import org.onosproject.openstackvtap.api.OpenstackVtapEvent;
28import org.onosproject.openstackvtap.api.OpenstackVtapId;
Jimo Jung14e87bf2018-09-03 16:28:13 +090029import org.onosproject.openstackvtap.api.OpenstackVtapNetwork;
Jian Li19f25262018-07-03 22:37:12 +090030import org.onosproject.openstackvtap.api.OpenstackVtapStore;
31import org.onosproject.openstackvtap.api.OpenstackVtapStoreDelegate;
32import org.onosproject.store.AbstractStore;
33import org.onosproject.store.serializers.KryoNamespaces;
34import org.onosproject.store.service.ConsistentMap;
35import org.onosproject.store.service.DistributedPrimitive.Status;
36import org.onosproject.store.service.MapEvent;
37import org.onosproject.store.service.MapEventListener;
38import org.onosproject.store.service.Serializer;
39import org.onosproject.store.service.StorageService;
Jimo Jung14e87bf2018-09-03 16:28:13 +090040import org.onosproject.store.service.Versioned;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070041import org.osgi.service.component.annotations.Activate;
42import org.osgi.service.component.annotations.Component;
43import org.osgi.service.component.annotations.Deactivate;
44import org.osgi.service.component.annotations.Reference;
45import org.osgi.service.component.annotations.ReferenceCardinality;
Jian Li19f25262018-07-03 22:37:12 +090046import org.slf4j.Logger;
47
48import java.util.Comparator;
49import java.util.Map;
50import java.util.Objects;
51import java.util.Set;
52import java.util.UUID;
53import java.util.concurrent.ScheduledExecutorService;
54import java.util.function.Consumer;
55import java.util.stream.Collectors;
56
Jian Li19f25262018-07-03 22:37:12 +090057import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
58import static org.onlab.util.Tools.groupedThreads;
59import static org.onosproject.net.DefaultAnnotations.merge;
Jimo Jung14e87bf2018-09-03 16:28:13 +090060import static org.onosproject.store.service.Versioned.valueOrNull;
Jian Li19f25262018-07-03 22:37:12 +090061import static org.slf4j.LoggerFactory.getLogger;
62
63/**
Jimo Jung14e87bf2018-09-03 16:28:13 +090064 * Manages the inventory of openstack vtap and openstack vtap network using a {@code ConsistentMap}.
Jian Li19f25262018-07-03 22:37:12 +090065 */
Ray Milkeyd84f89b2018-08-17 14:54:17 -070066@Component(immediate = true, service = OpenstackVtapStore.class)
Jian Li19f25262018-07-03 22:37:12 +090067public class DistributedOpenstackVtapStore
68 extends AbstractStore<OpenstackVtapEvent, OpenstackVtapStoreDelegate>
69 implements OpenstackVtapStore {
Jimo Jung14e87bf2018-09-03 16:28:13 +090070
Jian Li19f25262018-07-03 22:37:12 +090071 private final Logger log = getLogger(getClass());
72
Ray Milkeyd84f89b2018-08-17 14:54:17 -070073 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li19f25262018-07-03 22:37:12 +090074 protected StorageService storageService;
75
Jimo Jung14e87bf2018-09-03 16:28:13 +090076 private ConsistentMap<OpenstackVtapId, DefaultOpenstackVtap> vtapConsistentMap;
77 private MapEventListener<OpenstackVtapId, DefaultOpenstackVtap> vtapListener =
78 new VtapEventListener();
79 private Map<OpenstackVtapId, DefaultOpenstackVtap> vtapMap;
80
81 private ConsistentMap<Integer, DefaultOpenstackVtapNetwork> vtapNetworkConsistentMap;
82 private MapEventListener<Integer, DefaultOpenstackVtapNetwork> vtapNetworkListener =
83 new VtapNetworkEventListener();
84 private Map<Integer, DefaultOpenstackVtapNetwork> vtapNetworkMap;
85
86 private ConsistentMap<Integer, Set<DeviceId>> vtapNetworkDevicesConsistentMap;
Jian Li19f25262018-07-03 22:37:12 +090087
88 private static final Serializer SERIALIZER = Serializer
89 .using(new KryoNamespace.Builder().register(KryoNamespaces.API)
90 .register(OpenstackVtapId.class)
91 .register(UUID.class)
92 .register(DefaultOpenstackVtap.class)
Jimo Jung14e87bf2018-09-03 16:28:13 +090093 .register(Type.class)
Jian Li19f25262018-07-03 22:37:12 +090094 .register(DefaultOpenstackVtapCriterion.class)
Jimo Jung14e87bf2018-09-03 16:28:13 +090095 .register(DefaultOpenstackVtapNetwork.class)
96 .register(OpenstackVtapNetwork.Mode.class)
Jian Li19f25262018-07-03 22:37:12 +090097 .nextId(KryoNamespaces.BEGIN_USER_CUSTOM_ID)
98 .build());
99
100 private Map<DeviceId, Set<OpenstackVtapId>>
Jimo Jung14e87bf2018-09-03 16:28:13 +0900101 vtapIdsByTxDeviceId = Maps.newConcurrentMap();
Jian Li19f25262018-07-03 22:37:12 +0900102 private Map<DeviceId, Set<OpenstackVtapId>>
Jimo Jung14e87bf2018-09-03 16:28:13 +0900103 vtapIdsByRxDeviceId = Maps.newConcurrentMap();
Jian Li19f25262018-07-03 22:37:12 +0900104
105 private ScheduledExecutorService eventExecutor;
Jimo Jung14e87bf2018-09-03 16:28:13 +0900106 private Consumer<Status> vtapStatusListener;
Jian Li19f25262018-07-03 22:37:12 +0900107
Jimo Jung14e87bf2018-09-03 16:28:13 +0900108 private static final String ERR_NOT_FOUND = "ID {} does not exist";
109 private static final String ERR_DUPLICATE = "ID {} already exists";
Jian Li19f25262018-07-03 22:37:12 +0900110
111 @Activate
112 public void activate() {
113 eventExecutor = newSingleThreadScheduledExecutor(
114 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
115
Jimo Jung14e87bf2018-09-03 16:28:13 +0900116 // vtap network data
117 vtapNetworkConsistentMap = storageService.<Integer, DefaultOpenstackVtapNetwork>
Jian Li19f25262018-07-03 22:37:12 +0900118 consistentMapBuilder()
Jimo Jung14e87bf2018-09-03 16:28:13 +0900119 .withName("vtapNetworkMap")
120 .withSerializer(SERIALIZER)
121 .build();
122 vtapNetworkMap = vtapNetworkConsistentMap.asJavaMap();
123 vtapNetworkConsistentMap.addListener(vtapNetworkListener);
124
125 // vtap network devices data
126 vtapNetworkDevicesConsistentMap = storageService.<Integer, Set<DeviceId>>
127 consistentMapBuilder()
128 .withName("vtapNetworkDevicesMap")
Jian Li19f25262018-07-03 22:37:12 +0900129 .withSerializer(SERIALIZER)
130 .build();
131
Jimo Jung14e87bf2018-09-03 16:28:13 +0900132 // vtap data
133 vtapConsistentMap = storageService.<OpenstackVtapId, DefaultOpenstackVtap>
134 consistentMapBuilder()
135 .withName("vtapMap")
136 .withSerializer(SERIALIZER)
137 .build();
138 vtapMap = vtapConsistentMap.asJavaMap();
139 vtapConsistentMap.addListener(vtapListener);
Jian Li19f25262018-07-03 22:37:12 +0900140
Jimo Jung14e87bf2018-09-03 16:28:13 +0900141 // initialize vtap data
142 vtapStatusListener = status -> {
Jian Li19f25262018-07-03 22:37:12 +0900143 if (status == Status.ACTIVE) {
Jian Li26ef1302018-07-04 14:37:06 +0900144 eventExecutor.execute(this::loadVtapIds);
Jian Li19f25262018-07-03 22:37:12 +0900145 }
146 };
Jimo Jung14e87bf2018-09-03 16:28:13 +0900147 vtapConsistentMap.addStatusChangeListener(vtapStatusListener);
Jian Li19f25262018-07-03 22:37:12 +0900148
Jimo Jung14e87bf2018-09-03 16:28:13 +0900149 log.info("Started");
Jian Li19f25262018-07-03 22:37:12 +0900150 }
151
152 @Deactivate
153 public void deactivate() {
Jimo Jung14e87bf2018-09-03 16:28:13 +0900154 vtapConsistentMap.removeStatusChangeListener(vtapStatusListener);
155 vtapConsistentMap.removeListener(vtapListener);
156 vtapNetworkConsistentMap.removeListener(vtapNetworkListener);
157
Jian Li19f25262018-07-03 22:37:12 +0900158 eventExecutor.shutdown();
159
Jimo Jung14e87bf2018-09-03 16:28:13 +0900160 log.info("Stopped");
Jian Li19f25262018-07-03 22:37:12 +0900161 }
162
Jimo Jung14e87bf2018-09-03 16:28:13 +0900163 private boolean shouldUpdateVtapNetwork(DefaultOpenstackVtapNetwork existing,
164 OpenstackVtapNetwork description) {
Jian Li26ef1302018-07-04 14:37:06 +0900165 if (existing == null) {
166 return true;
167 }
168
Jimo Jung14e87bf2018-09-03 16:28:13 +0900169 if (!Objects.equals(existing.mode(), description.mode()) ||
170 !Objects.equals(existing.networkId(), description.networkId()) ||
171 !Objects.equals(existing.serverIp(), description.serverIp())) {
Jian Li26ef1302018-07-04 14:37:06 +0900172 return true;
173 }
174
Jimo Jung14e87bf2018-09-03 16:28:13 +0900175 // check to see if any of the annotations provided by description
176 // differ from those in the existing vtap network
Jian Li26ef1302018-07-04 14:37:06 +0900177 return description.annotations().keys().stream()
178 .anyMatch(k -> !Objects.equals(description.annotations().value(k),
179 existing.annotations().value(k)));
180 }
181
Jimo Jung14e87bf2018-09-03 16:28:13 +0900182 private OpenstackVtapNetwork createOrUpdateVtapNetwork(boolean update,
183 Integer key,
184 OpenstackVtapNetwork description) {
185 DefaultOpenstackVtapNetwork result =
186 vtapNetworkMap.compute(key, (id, existing) -> {
187 // Check create or update validity
188 if (update && existing == null) {
189 return null;
190 } else if (!update && existing != null) {
191 return existing;
192 }
193
194 if (shouldUpdateVtapNetwork(existing, description)) {
195 // Replace or add annotations
196 final SparseAnnotations annotations;
197 if (existing != null) {
198 annotations = merge((DefaultAnnotations) existing.annotations(),
199 (SparseAnnotations) description.annotations());
200 } else {
201 annotations = (SparseAnnotations) description.annotations();
202 }
203
204 return DefaultOpenstackVtapNetwork.builder(description)
205 .annotations(annotations)
206 .build();
207 }
208 return existing;
209 });
210 return result;
211 }
212
213 @Override
214 public OpenstackVtapNetwork createVtapNetwork(Integer key, OpenstackVtapNetwork description) {
215 if (getVtapNetwork(key) == null) {
216 OpenstackVtapNetwork vtapNetwork = createOrUpdateVtapNetwork(false, key, description);
217 if (Objects.equals(vtapNetwork, description)) {
218 return vtapNetwork;
219 }
220 }
221 log.error(ERR_DUPLICATE, key);
222 return null;
223 }
224
225 @Override
226 public OpenstackVtapNetwork updateVtapNetwork(Integer key, OpenstackVtapNetwork description) {
227 OpenstackVtapNetwork vtapNetwork = createOrUpdateVtapNetwork(true, key, description);
228 if (vtapNetwork == null) {
229 log.error(ERR_NOT_FOUND, key);
230 }
231 return vtapNetwork;
232 }
233
234 @Override
235 public OpenstackVtapNetwork removeVtapNetwork(Integer key) {
236 return vtapNetworkMap.remove(key);
237 }
238
239 @Override
240 public void clearVtapNetworks() {
241 vtapNetworkMap.clear();
242 }
243
244 @Override
245 public int getVtapNetworkCount() {
246 return vtapNetworkMap.size();
247 }
248
249 @Override
250 public OpenstackVtapNetwork getVtapNetwork(Integer key) {
251 return vtapNetworkMap.get(key);
252 }
253
254 @Override
255 public boolean addDeviceToVtapNetwork(Integer key, DeviceId deviceId) {
256 Versioned<Set<DeviceId>> result =
257 vtapNetworkDevicesConsistentMap.compute(key, (id, existing) -> {
258 // Add deviceId to deviceIds
259 if (existing == null) {
260 return Sets.newHashSet(deviceId);
261 } else if (!existing.contains(deviceId)) {
262 Set<DeviceId> deviceIds = Sets.newHashSet(existing);
263 deviceIds.add(deviceId);
264 return deviceIds;
265 } else {
266 return existing;
267 }
268 });
269 return Objects.nonNull(valueOrNull(result));
270 }
271
272 @Override
273 public boolean removeDeviceFromVtapNetwork(Integer key, DeviceId deviceId) {
274 Versioned<Set<DeviceId>> result =
275 vtapNetworkDevicesConsistentMap.compute(key, (id, existing) -> {
276 // Remove deviceId from deviceIds
277 if (existing != null && existing.contains(deviceId)) {
278 Set<DeviceId> deviceIds = Sets.newHashSet(existing);
279 deviceIds.remove(deviceId);
280 return deviceIds;
281 } else {
282 return existing;
283 }
284 });
285 return Objects.nonNull(valueOrNull(result));
286 }
287
288 @Override
289 public Set<DeviceId> getVtapNetworkDevices(Integer key) {
290 return valueOrNull(vtapNetworkDevicesConsistentMap.get(key));
291 }
292
293 private boolean shouldUpdateVtap(DefaultOpenstackVtap existing,
294 OpenstackVtap description,
295 boolean replaceDevices) {
296 if (existing == null) {
297 return true;
298 }
299
300 if (!Objects.equals(existing.type(), description.type()) ||
301 !Objects.equals(existing.vtapCriterion(), description.vtapCriterion())) {
302 return true;
303 }
304
305 if (replaceDevices) {
306 if (!Objects.equals(description.txDeviceIds(), existing.txDeviceIds()) ||
307 !Objects.equals(description.rxDeviceIds(), existing.rxDeviceIds())) {
308 return true;
309 }
310 } else {
311 if (!existing.txDeviceIds().containsAll(description.txDeviceIds()) ||
312 !existing.rxDeviceIds().containsAll(description.rxDeviceIds())) {
313 return true;
314 }
315 }
316
317 // check to see if any of the annotations provided by description
318 // differ from those in the existing vtap
319 return description.annotations().keys().stream()
320 .anyMatch(k -> !Objects.equals(description.annotations().value(k),
321 existing.annotations().value(k)));
322 }
323
324 private OpenstackVtap createOrUpdateVtap(boolean update,
325 OpenstackVtap description,
326 boolean replaceDevices) {
327 DefaultOpenstackVtap result =
328 vtapMap.compute(description.id(), (id, existing) -> {
329 // Check create or update validity
330 if (update && existing == null) {
331 return null;
332 } else if (!update && existing != null) {
333 return existing;
334 }
335
336 if (shouldUpdateVtap(existing, description, replaceDevices)) {
337 // Replace or add devices
338 final Set<DeviceId> txDeviceIds;
339 if (existing == null || replaceDevices) {
340 txDeviceIds = description.txDeviceIds();
341 } else {
342 txDeviceIds = Sets.newHashSet(existing.txDeviceIds());
343 txDeviceIds.addAll(description.txDeviceIds());
344 }
345
346 final Set<DeviceId> rxDeviceIds;
347 if (existing == null || replaceDevices) {
348 rxDeviceIds = description.rxDeviceIds();
349 } else {
350 rxDeviceIds = Sets.newHashSet(existing.rxDeviceIds());
351 rxDeviceIds.addAll(description.rxDeviceIds());
352 }
353
354 // Replace or add annotations
355 final SparseAnnotations annotations;
356 if (existing != null) {
357 annotations = merge((DefaultAnnotations) existing.annotations(),
358 (SparseAnnotations) description.annotations());
359 } else {
360 annotations = (SparseAnnotations) description.annotations();
361 }
362
363 return DefaultOpenstackVtap.builder(description)
364 .txDeviceIds(txDeviceIds)
365 .rxDeviceIds(rxDeviceIds)
366 .annotations(annotations)
367 .build();
368 }
369 return existing;
370 });
371 return result;
372 }
373
374 @Override
375 public OpenstackVtap createVtap(OpenstackVtap description) {
376 if (getVtap(description.id()) == null) {
377 OpenstackVtap vtap = createOrUpdateVtap(false, description, true);
378 if (Objects.equals(vtap, description)) {
379 return vtap;
380 }
381 }
382 log.error(ERR_DUPLICATE, description.id());
383 return null;
384 }
385
386 @Override
387 public OpenstackVtap updateVtap(OpenstackVtap description, boolean replaceDevices) {
388 OpenstackVtap vtap = createOrUpdateVtap(true, description, replaceDevices);
389 if (vtap == null) {
390 log.error(ERR_NOT_FOUND, description.id());
391 }
392 return vtap;
393 }
394
395 @Override
396 public OpenstackVtap removeVtap(OpenstackVtapId vtapId) {
397 return vtapMap.remove(vtapId);
398 }
399
400 @Override
401 public void clearVtaps() {
402 vtapMap.clear();
403 }
404
405 @Override
406 public int getVtapCount(Type type) {
407 return (int) vtapMap.values().parallelStream()
408 .filter(vtap -> vtap.type().isValid(type))
409 .count();
410 }
411
412 @Override
413 public Set<OpenstackVtap> getVtaps(Type type) {
414 return ImmutableSet.copyOf(
415 vtapMap.values().parallelStream()
416 .filter(vtap -> vtap.type().isValid(type))
417 .collect(Collectors.toSet()));
418 }
419
420 @Override
421 public OpenstackVtap getVtap(OpenstackVtapId vtapId) {
422 return vtapMap.get(vtapId);
423 }
424
425 @Override
426 public boolean addDeviceToVtap(OpenstackVtapId vtapId, Type type, DeviceId deviceId) {
427 OpenstackVtap result =
428 vtapMap.compute(vtapId, (id, existing) -> {
429 if (existing == null) {
430 return null;
431 }
432
433 // Check type validate
434 if (!existing.type().isValid(type)) {
435 log.error("Not valid OpenstackVtap type {} for requested type {}", existing.type(), type);
436 return existing;
437 }
438
439 // Add deviceId to txDeviceIds
440 final Set<DeviceId> txDeviceIds;
441 if (existing.type().isValid(Type.VTAP_TX) &&
442 (type.isValid(Type.VTAP_TX) || type == Type.VTAP_ANY) &&
443 !existing.txDeviceIds().contains(deviceId)) {
444 txDeviceIds = Sets.newHashSet(existing.txDeviceIds());
445 txDeviceIds.add(deviceId);
446 } else {
447 txDeviceIds = null;
448 }
449
450 // Add deviceId to rxDeviceIds
451 final Set<DeviceId> rxDeviceIds;
452 if (existing.type().isValid(Type.VTAP_RX) &&
453 (type.isValid(Type.VTAP_RX) || type == Type.VTAP_ANY) &&
454 !existing.rxDeviceIds().contains(deviceId)) {
455 rxDeviceIds = Sets.newHashSet(existing.rxDeviceIds());
456 rxDeviceIds.add(deviceId);
457 } else {
458 rxDeviceIds = null;
459 }
460
461 if (txDeviceIds != null || rxDeviceIds != null) {
462 return DefaultOpenstackVtap.builder()
463 .id(id)
464 .type(existing.type())
465 .vtapCriterion(existing.vtapCriterion())
466 .txDeviceIds(txDeviceIds != null ? txDeviceIds : existing.txDeviceIds())
467 .rxDeviceIds(rxDeviceIds != null ? rxDeviceIds : existing.rxDeviceIds())
468 .annotations(existing.annotations())
469 .build();
470 } else {
471 return existing;
472 }
473 });
474 return Objects.nonNull(result);
475 }
476
477 @Override
478 public boolean removeDeviceFromVtap(OpenstackVtapId vtapId, OpenstackVtap.Type type, DeviceId deviceId) {
479 OpenstackVtap result =
480 vtapMap.compute(vtapId, (id, existing) -> {
481 if (existing == null) {
482 return null;
483 }
484
485 // Check type validate
486 if (!existing.type().isValid(type)) {
487 log.error("Not valid OpenstackVtap type {} for requested type {}",
488 existing.type(), type);
489 return existing;
490 }
491
492 // Remove deviceId from txDeviceIds
493 final Set<DeviceId> txDeviceIds;
494 if (existing.type().isValid(Type.VTAP_TX) &&
495 (type.isValid(Type.VTAP_TX) || type == Type.VTAP_ANY) &&
496 existing.txDeviceIds().contains(deviceId)) {
497 txDeviceIds = Sets.newHashSet(existing.txDeviceIds());
498 txDeviceIds.remove(deviceId);
499 } else {
500 txDeviceIds = null;
501 }
502
503 // Remove deviceId from rxDeviceIds
504 final Set<DeviceId> rxDeviceIds;
505 if (existing.type().isValid(Type.VTAP_RX) &&
506 (type.isValid(Type.VTAP_RX) || type == Type.VTAP_ANY) &&
507 existing.rxDeviceIds().contains(deviceId)) {
508 rxDeviceIds = Sets.newHashSet(existing.rxDeviceIds());
509 rxDeviceIds.remove(deviceId);
510 } else {
511 rxDeviceIds = null;
512 }
513
514 if (txDeviceIds != null || rxDeviceIds != null) {
515 return DefaultOpenstackVtap.builder()
516 .id(id)
517 .type(existing.type())
518 .vtapCriterion(existing.vtapCriterion())
519 .txDeviceIds(txDeviceIds != null ? txDeviceIds : existing.txDeviceIds())
520 .rxDeviceIds(rxDeviceIds != null ? rxDeviceIds : existing.rxDeviceIds())
521 .annotations(existing.annotations())
522 .build();
523 } else {
524 return existing;
525 }
526 });
527 return Objects.nonNull(result);
528 }
529
530 @Override
531 public Set<OpenstackVtap> getVtapsByDeviceId(DeviceId deviceId) {
532 Set<OpenstackVtapId> vtapIds = Sets.newHashSet();
533 Set<OpenstackVtapId> txIds = vtapIdsByTxDeviceId.get(deviceId);
534 if (txIds != null) {
535 vtapIds.addAll(txIds);
536 }
537 Set<OpenstackVtapId> rxIds = vtapIdsByRxDeviceId.get(deviceId);
538 if (rxIds != null) {
539 vtapIds.addAll(rxIds);
540 }
541 return ImmutableSet.copyOf(
542 vtapIds.parallelStream()
543 .map(vtapId -> vtapMap.get(vtapId))
544 .filter(Objects::nonNull)
545 .collect(Collectors.toSet()));
546 }
547
Jian Li26ef1302018-07-04 14:37:06 +0900548 private class VtapComparator implements Comparator<OpenstackVtap> {
Jian Li19f25262018-07-03 22:37:12 +0900549 @Override
550 public int compare(OpenstackVtap v1, OpenstackVtap v2) {
551 int diff = (v2.type().compareTo(v1.type()));
552 if (diff == 0) {
Jimo Jung14e87bf2018-09-03 16:28:13 +0900553 return (v2.vtapCriterion().ipProtocol() - v1.vtapCriterion().ipProtocol());
Jian Li19f25262018-07-03 22:37:12 +0900554 }
555 return diff;
556 }
557 }
558
Jimo Jung14e87bf2018-09-03 16:28:13 +0900559 private void loadVtapIds() {
560 vtapIdsByTxDeviceId.clear();
561 vtapIdsByRxDeviceId.clear();
562 vtapMap.values().forEach(vtap -> refreshDeviceIdsByVtap(null, vtap));
563 }
564
565 private static Set<OpenstackVtapId> addVTapIds(OpenstackVtapId vtapId) {
Jian Li19f25262018-07-03 22:37:12 +0900566 Set<OpenstackVtapId> vtapIds = Sets.newConcurrentHashSet();
Jimo Jung14e87bf2018-09-03 16:28:13 +0900567 vtapIds.add(vtapId);
Jian Li19f25262018-07-03 22:37:12 +0900568 return vtapIds;
569 }
570
571 private static Set<OpenstackVtapId> updateVTapIds(Set<OpenstackVtapId> existingVtapIds,
Jimo Jung14e87bf2018-09-03 16:28:13 +0900572 OpenstackVtapId vtapId) {
573 existingVtapIds.add(vtapId);
Jian Li19f25262018-07-03 22:37:12 +0900574 return existingVtapIds;
575 }
576
577 private static Set<OpenstackVtapId> removeVTapIds(Set<OpenstackVtapId> existingVtapIds,
Jimo Jung14e87bf2018-09-03 16:28:13 +0900578 OpenstackVtapId vtapId) {
579 existingVtapIds.remove(vtapId);
Jian Li19f25262018-07-03 22:37:12 +0900580 if (existingVtapIds.isEmpty()) {
581 return null;
582 }
583 return existingVtapIds;
584 }
585
Jimo Jung14e87bf2018-09-03 16:28:13 +0900586 private void updateVTapIdFromTxDeviceId(OpenstackVtapId vtapId, DeviceId deviceId) {
587 vtapIdsByTxDeviceId.compute(deviceId, (k, v) -> v == null ?
588 addVTapIds(vtapId) : updateVTapIds(v, vtapId));
Jian Li19f25262018-07-03 22:37:12 +0900589 }
590
Jimo Jung14e87bf2018-09-03 16:28:13 +0900591 private void removeVTapIdFromTxDeviceId(OpenstackVtapId vtapId, DeviceId deviceId) {
592 vtapIdsByTxDeviceId.computeIfPresent(deviceId, (k, v) -> removeVTapIds(v, vtapId));
Jian Li19f25262018-07-03 22:37:12 +0900593 }
594
Jimo Jung14e87bf2018-09-03 16:28:13 +0900595 private void updateVTapIdFromRxDeviceId(OpenstackVtapId vtapId, DeviceId deviceId) {
596 vtapIdsByRxDeviceId.compute(deviceId, (k, v) -> v == null ?
597 addVTapIds(vtapId) : updateVTapIds(v, vtapId));
Jian Li19f25262018-07-03 22:37:12 +0900598 }
599
Jimo Jung14e87bf2018-09-03 16:28:13 +0900600 private void removeVTapIdFromRxDeviceId(OpenstackVtapId vtapId, DeviceId deviceId) {
601 vtapIdsByRxDeviceId.computeIfPresent(deviceId, (k, v) -> removeVTapIds(v, vtapId));
Jian Li19f25262018-07-03 22:37:12 +0900602 }
603
Jimo Jung14e87bf2018-09-03 16:28:13 +0900604 private void refreshDeviceIdsByVtap(OpenstackVtap newOpenstackVtap,
605 OpenstackVtap oldOpenstackVtap) {
606 if (Objects.equals(newOpenstackVtap, oldOpenstackVtap)) {
607 return;
608 }
609
Jian Li19f25262018-07-03 22:37:12 +0900610 if (oldOpenstackVtap != null) {
611 Set<DeviceId> removeDeviceIds;
612
Jimo Jung14e87bf2018-09-03 16:28:13 +0900613 // Remove TX vtap
Jian Li19f25262018-07-03 22:37:12 +0900614 removeDeviceIds = (newOpenstackVtap != null) ?
615 Sets.difference(oldOpenstackVtap.txDeviceIds(),
616 newOpenstackVtap.txDeviceIds()) : oldOpenstackVtap.txDeviceIds();
617 removeDeviceIds.forEach(id -> removeVTapIdFromTxDeviceId(oldOpenstackVtap.id(), id));
618
Jimo Jung14e87bf2018-09-03 16:28:13 +0900619 // Remove RX vtap
Jian Li19f25262018-07-03 22:37:12 +0900620 removeDeviceIds = (newOpenstackVtap != null) ?
621 Sets.difference(oldOpenstackVtap.rxDeviceIds(),
622 newOpenstackVtap.rxDeviceIds()) : oldOpenstackVtap.rxDeviceIds();
623 removeDeviceIds.forEach(id -> removeVTapIdFromRxDeviceId(oldOpenstackVtap.id(), id));
624 }
625
626 if (newOpenstackVtap != null) {
627 Set<DeviceId> addDeviceIds;
628
Jimo Jung14e87bf2018-09-03 16:28:13 +0900629 // Add TX vtap
Jian Li19f25262018-07-03 22:37:12 +0900630 addDeviceIds = (oldOpenstackVtap != null) ?
631 Sets.difference(newOpenstackVtap.txDeviceIds(),
632 oldOpenstackVtap.txDeviceIds()) : newOpenstackVtap.txDeviceIds();
633 addDeviceIds.forEach(id -> updateVTapIdFromTxDeviceId(newOpenstackVtap.id(), id));
634
Jimo Jung14e87bf2018-09-03 16:28:13 +0900635 // Add RX vtap
Jian Li19f25262018-07-03 22:37:12 +0900636 addDeviceIds = (oldOpenstackVtap != null) ?
637 Sets.difference(newOpenstackVtap.rxDeviceIds(),
638 oldOpenstackVtap.rxDeviceIds()) : newOpenstackVtap.rxDeviceIds();
639 addDeviceIds.forEach(id -> updateVTapIdFromRxDeviceId(newOpenstackVtap.id(), id));
640 }
641 }
642
Jian Li26ef1302018-07-04 14:37:06 +0900643 private class VtapEventListener
Jian Li19f25262018-07-03 22:37:12 +0900644 implements MapEventListener<OpenstackVtapId, DefaultOpenstackVtap> {
645 @Override
646 public void event(MapEvent<OpenstackVtapId, DefaultOpenstackVtap> event) {
647 DefaultOpenstackVtap newValue =
648 event.newValue() != null ? event.newValue().value() : null;
649 DefaultOpenstackVtap oldValue =
650 event.oldValue() != null ? event.oldValue().value() : null;
651
Jimo Jung14e87bf2018-09-03 16:28:13 +0900652 log.trace("VtapEventListener {}: {} -> {}", event.type(), oldValue, newValue);
Jian Li19f25262018-07-03 22:37:12 +0900653 switch (event.type()) {
654 case INSERT:
Jimo Jung14e87bf2018-09-03 16:28:13 +0900655 refreshDeviceIdsByVtap(newValue, oldValue);
Jian Li19f25262018-07-03 22:37:12 +0900656 notifyDelegate(new OpenstackVtapEvent(
Jimo Jung14e87bf2018-09-03 16:28:13 +0900657 OpenstackVtapEvent.Type.VTAP_ADDED, newValue, null));
Jian Li19f25262018-07-03 22:37:12 +0900658 break;
659
660 case UPDATE:
Jimo Jung14e87bf2018-09-03 16:28:13 +0900661 refreshDeviceIdsByVtap(newValue, oldValue);
662 notifyDelegate(new OpenstackVtapEvent(
663 OpenstackVtapEvent.Type.VTAP_UPDATED, newValue, oldValue));
Jian Li19f25262018-07-03 22:37:12 +0900664 break;
665
666 case REMOVE:
Jimo Jung14e87bf2018-09-03 16:28:13 +0900667 refreshDeviceIdsByVtap(newValue, oldValue);
Jian Li19f25262018-07-03 22:37:12 +0900668 notifyDelegate(new OpenstackVtapEvent(
Jimo Jung14e87bf2018-09-03 16:28:13 +0900669 OpenstackVtapEvent.Type.VTAP_REMOVED, null, oldValue));
Jian Li19f25262018-07-03 22:37:12 +0900670 break;
671
672 default:
673 log.warn("Unknown map event type: {}", event.type());
674 }
675 }
676 }
Jimo Jung14e87bf2018-09-03 16:28:13 +0900677
678 private class VtapNetworkEventListener
679 implements MapEventListener<Integer, DefaultOpenstackVtapNetwork> {
680 @Override
681 public void event(MapEvent<Integer, DefaultOpenstackVtapNetwork> event) {
682 DefaultOpenstackVtapNetwork newValue =
683 event.newValue() != null ? event.newValue().value() : null;
684 DefaultOpenstackVtapNetwork oldValue =
685 event.oldValue() != null ? event.oldValue().value() : null;
686
687 log.trace("VtapNetworkEventListener {}: {} -> {}", event.type(), oldValue, newValue);
688 switch (event.type()) {
689 case INSERT:
690 notifyDelegate(new OpenstackVtapEvent(
691 OpenstackVtapEvent.Type.VTAP_NETWORK_ADDED, newValue, null));
692 break;
693
694 case UPDATE:
695 notifyDelegate(new OpenstackVtapEvent(
696 OpenstackVtapEvent.Type.VTAP_NETWORK_UPDATED, newValue, oldValue));
697 break;
698
699 case REMOVE:
700 notifyDelegate(new OpenstackVtapEvent(
701 OpenstackVtapEvent.Type.VTAP_NETWORK_REMOVED, null, oldValue));
702 break;
703
704 default:
705 log.warn("Unknown map event type: {}", event.type());
706 }
707 }
708 }
709
Jian Li19f25262018-07-03 22:37:12 +0900710}