blob: 9f2ee12f04ad610082f60604ff1dee3dc40dd5b1 [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;
21import org.apache.felix.scr.annotations.Activate;
22import org.apache.felix.scr.annotations.Component;
23import org.apache.felix.scr.annotations.Deactivate;
24import org.apache.felix.scr.annotations.Reference;
25import org.apache.felix.scr.annotations.ReferenceCardinality;
26import org.apache.felix.scr.annotations.Service;
27import org.onlab.util.KryoNamespace;
28import org.onosproject.net.DefaultAnnotations;
29import org.onosproject.net.DeviceId;
30import org.onosproject.net.SparseAnnotations;
31import org.onosproject.openstackvtap.api.OpenstackVtap;
Jimo Jung14e87bf2018-09-03 16:28:13 +090032import org.onosproject.openstackvtap.api.OpenstackVtap.Type;
Jian Li19f25262018-07-03 22:37:12 +090033import org.onosproject.openstackvtap.api.OpenstackVtapEvent;
34import org.onosproject.openstackvtap.api.OpenstackVtapId;
Jimo Jung14e87bf2018-09-03 16:28:13 +090035import org.onosproject.openstackvtap.api.OpenstackVtapNetwork;
Jian Li19f25262018-07-03 22:37:12 +090036import org.onosproject.openstackvtap.api.OpenstackVtapStore;
37import org.onosproject.openstackvtap.api.OpenstackVtapStoreDelegate;
38import org.onosproject.store.AbstractStore;
39import org.onosproject.store.serializers.KryoNamespaces;
40import org.onosproject.store.service.ConsistentMap;
41import org.onosproject.store.service.DistributedPrimitive.Status;
42import org.onosproject.store.service.MapEvent;
43import org.onosproject.store.service.MapEventListener;
44import org.onosproject.store.service.Serializer;
45import org.onosproject.store.service.StorageService;
Jimo Jung14e87bf2018-09-03 16:28:13 +090046import org.onosproject.store.service.Versioned;
Jian Li19f25262018-07-03 22:37:12 +090047import org.slf4j.Logger;
48
49import java.util.Comparator;
50import java.util.Map;
51import java.util.Objects;
52import java.util.Set;
53import java.util.UUID;
54import java.util.concurrent.ScheduledExecutorService;
55import java.util.function.Consumer;
56import java.util.stream.Collectors;
57
Jian Li19f25262018-07-03 22:37:12 +090058import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
59import static org.onlab.util.Tools.groupedThreads;
60import static org.onosproject.net.DefaultAnnotations.merge;
Jimo Jung14e87bf2018-09-03 16:28:13 +090061import static org.onosproject.store.service.Versioned.valueOrNull;
Jian Li19f25262018-07-03 22:37:12 +090062import static org.slf4j.LoggerFactory.getLogger;
63
64/**
Jimo Jung14e87bf2018-09-03 16:28:13 +090065 * Manages the inventory of openstack vtap and openstack vtap network using a {@code ConsistentMap}.
Jian Li19f25262018-07-03 22:37:12 +090066 */
67@Component(immediate = true)
68@Service
69public class DistributedOpenstackVtapStore
70 extends AbstractStore<OpenstackVtapEvent, OpenstackVtapStoreDelegate>
71 implements OpenstackVtapStore {
Jimo Jung14e87bf2018-09-03 16:28:13 +090072
Jian Li19f25262018-07-03 22:37:12 +090073 private final Logger log = getLogger(getClass());
74
75 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
76 protected StorageService storageService;
77
Jimo Jung14e87bf2018-09-03 16:28:13 +090078 private ConsistentMap<OpenstackVtapId, DefaultOpenstackVtap> vtapConsistentMap;
79 private MapEventListener<OpenstackVtapId, DefaultOpenstackVtap> vtapListener =
80 new VtapEventListener();
81 private Map<OpenstackVtapId, DefaultOpenstackVtap> vtapMap;
82
83 private ConsistentMap<Integer, DefaultOpenstackVtapNetwork> vtapNetworkConsistentMap;
84 private MapEventListener<Integer, DefaultOpenstackVtapNetwork> vtapNetworkListener =
85 new VtapNetworkEventListener();
86 private Map<Integer, DefaultOpenstackVtapNetwork> vtapNetworkMap;
87
88 private ConsistentMap<Integer, Set<DeviceId>> vtapNetworkDevicesConsistentMap;
Jian Li19f25262018-07-03 22:37:12 +090089
90 private static final Serializer SERIALIZER = Serializer
91 .using(new KryoNamespace.Builder().register(KryoNamespaces.API)
92 .register(OpenstackVtapId.class)
93 .register(UUID.class)
94 .register(DefaultOpenstackVtap.class)
Jimo Jung14e87bf2018-09-03 16:28:13 +090095 .register(Type.class)
Jian Li19f25262018-07-03 22:37:12 +090096 .register(DefaultOpenstackVtapCriterion.class)
Jimo Jung14e87bf2018-09-03 16:28:13 +090097 .register(DefaultOpenstackVtapNetwork.class)
98 .register(OpenstackVtapNetwork.Mode.class)
Jian Li19f25262018-07-03 22:37:12 +090099 .nextId(KryoNamespaces.BEGIN_USER_CUSTOM_ID)
100 .build());
101
102 private Map<DeviceId, Set<OpenstackVtapId>>
Jimo Jung14e87bf2018-09-03 16:28:13 +0900103 vtapIdsByTxDeviceId = Maps.newConcurrentMap();
Jian Li19f25262018-07-03 22:37:12 +0900104 private Map<DeviceId, Set<OpenstackVtapId>>
Jimo Jung14e87bf2018-09-03 16:28:13 +0900105 vtapIdsByRxDeviceId = Maps.newConcurrentMap();
Jian Li19f25262018-07-03 22:37:12 +0900106
107 private ScheduledExecutorService eventExecutor;
Jimo Jung14e87bf2018-09-03 16:28:13 +0900108 private Consumer<Status> vtapStatusListener;
Jian Li19f25262018-07-03 22:37:12 +0900109
Jimo Jung14e87bf2018-09-03 16:28:13 +0900110 private static final String ERR_NOT_FOUND = "ID {} does not exist";
111 private static final String ERR_DUPLICATE = "ID {} already exists";
Jian Li19f25262018-07-03 22:37:12 +0900112
113 @Activate
114 public void activate() {
115 eventExecutor = newSingleThreadScheduledExecutor(
116 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
117
Jimo Jung14e87bf2018-09-03 16:28:13 +0900118 // vtap network data
119 vtapNetworkConsistentMap = storageService.<Integer, DefaultOpenstackVtapNetwork>
Jian Li19f25262018-07-03 22:37:12 +0900120 consistentMapBuilder()
Jimo Jung14e87bf2018-09-03 16:28:13 +0900121 .withName("vtapNetworkMap")
122 .withSerializer(SERIALIZER)
123 .build();
124 vtapNetworkMap = vtapNetworkConsistentMap.asJavaMap();
125 vtapNetworkConsistentMap.addListener(vtapNetworkListener);
126
127 // vtap network devices data
128 vtapNetworkDevicesConsistentMap = storageService.<Integer, Set<DeviceId>>
129 consistentMapBuilder()
130 .withName("vtapNetworkDevicesMap")
Jian Li19f25262018-07-03 22:37:12 +0900131 .withSerializer(SERIALIZER)
132 .build();
133
Jimo Jung14e87bf2018-09-03 16:28:13 +0900134 // vtap data
135 vtapConsistentMap = storageService.<OpenstackVtapId, DefaultOpenstackVtap>
136 consistentMapBuilder()
137 .withName("vtapMap")
138 .withSerializer(SERIALIZER)
139 .build();
140 vtapMap = vtapConsistentMap.asJavaMap();
141 vtapConsistentMap.addListener(vtapListener);
Jian Li19f25262018-07-03 22:37:12 +0900142
Jimo Jung14e87bf2018-09-03 16:28:13 +0900143 // initialize vtap data
144 vtapStatusListener = status -> {
Jian Li19f25262018-07-03 22:37:12 +0900145 if (status == Status.ACTIVE) {
Jian Li26ef1302018-07-04 14:37:06 +0900146 eventExecutor.execute(this::loadVtapIds);
Jian Li19f25262018-07-03 22:37:12 +0900147 }
148 };
Jimo Jung14e87bf2018-09-03 16:28:13 +0900149 vtapConsistentMap.addStatusChangeListener(vtapStatusListener);
Jian Li19f25262018-07-03 22:37:12 +0900150
Jimo Jung14e87bf2018-09-03 16:28:13 +0900151 log.info("Started");
Jian Li19f25262018-07-03 22:37:12 +0900152 }
153
154 @Deactivate
155 public void deactivate() {
Jimo Jung14e87bf2018-09-03 16:28:13 +0900156 vtapConsistentMap.removeStatusChangeListener(vtapStatusListener);
157 vtapConsistentMap.removeListener(vtapListener);
158 vtapNetworkConsistentMap.removeListener(vtapNetworkListener);
159
Jian Li19f25262018-07-03 22:37:12 +0900160 eventExecutor.shutdown();
161
Jimo Jung14e87bf2018-09-03 16:28:13 +0900162 log.info("Stopped");
Jian Li19f25262018-07-03 22:37:12 +0900163 }
164
Jimo Jung14e87bf2018-09-03 16:28:13 +0900165 private boolean shouldUpdateVtapNetwork(DefaultOpenstackVtapNetwork existing,
166 OpenstackVtapNetwork description) {
Jian Li26ef1302018-07-04 14:37:06 +0900167 if (existing == null) {
168 return true;
169 }
170
Jimo Jung14e87bf2018-09-03 16:28:13 +0900171 if (!Objects.equals(existing.mode(), description.mode()) ||
172 !Objects.equals(existing.networkId(), description.networkId()) ||
173 !Objects.equals(existing.serverIp(), description.serverIp())) {
Jian Li26ef1302018-07-04 14:37:06 +0900174 return true;
175 }
176
Jimo Jung14e87bf2018-09-03 16:28:13 +0900177 // check to see if any of the annotations provided by description
178 // differ from those in the existing vtap network
Jian Li26ef1302018-07-04 14:37:06 +0900179 return description.annotations().keys().stream()
180 .anyMatch(k -> !Objects.equals(description.annotations().value(k),
181 existing.annotations().value(k)));
182 }
183
Jimo Jung14e87bf2018-09-03 16:28:13 +0900184 private OpenstackVtapNetwork createOrUpdateVtapNetwork(boolean update,
185 Integer key,
186 OpenstackVtapNetwork description) {
187 DefaultOpenstackVtapNetwork result =
188 vtapNetworkMap.compute(key, (id, existing) -> {
189 // Check create or update validity
190 if (update && existing == null) {
191 return null;
192 } else if (!update && existing != null) {
193 return existing;
194 }
195
196 if (shouldUpdateVtapNetwork(existing, description)) {
197 // Replace or add annotations
198 final SparseAnnotations annotations;
199 if (existing != null) {
200 annotations = merge((DefaultAnnotations) existing.annotations(),
201 (SparseAnnotations) description.annotations());
202 } else {
203 annotations = (SparseAnnotations) description.annotations();
204 }
205
206 return DefaultOpenstackVtapNetwork.builder(description)
207 .annotations(annotations)
208 .build();
209 }
210 return existing;
211 });
212 return result;
213 }
214
215 @Override
216 public OpenstackVtapNetwork createVtapNetwork(Integer key, OpenstackVtapNetwork description) {
217 if (getVtapNetwork(key) == null) {
218 OpenstackVtapNetwork vtapNetwork = createOrUpdateVtapNetwork(false, key, description);
219 if (Objects.equals(vtapNetwork, description)) {
220 return vtapNetwork;
221 }
222 }
223 log.error(ERR_DUPLICATE, key);
224 return null;
225 }
226
227 @Override
228 public OpenstackVtapNetwork updateVtapNetwork(Integer key, OpenstackVtapNetwork description) {
229 OpenstackVtapNetwork vtapNetwork = createOrUpdateVtapNetwork(true, key, description);
230 if (vtapNetwork == null) {
231 log.error(ERR_NOT_FOUND, key);
232 }
233 return vtapNetwork;
234 }
235
236 @Override
237 public OpenstackVtapNetwork removeVtapNetwork(Integer key) {
238 return vtapNetworkMap.remove(key);
239 }
240
241 @Override
242 public void clearVtapNetworks() {
243 vtapNetworkMap.clear();
244 }
245
246 @Override
247 public int getVtapNetworkCount() {
248 return vtapNetworkMap.size();
249 }
250
251 @Override
252 public OpenstackVtapNetwork getVtapNetwork(Integer key) {
253 return vtapNetworkMap.get(key);
254 }
255
256 @Override
257 public boolean addDeviceToVtapNetwork(Integer key, DeviceId deviceId) {
258 Versioned<Set<DeviceId>> result =
259 vtapNetworkDevicesConsistentMap.compute(key, (id, existing) -> {
260 // Add deviceId to deviceIds
261 if (existing == null) {
262 return Sets.newHashSet(deviceId);
263 } else if (!existing.contains(deviceId)) {
264 Set<DeviceId> deviceIds = Sets.newHashSet(existing);
265 deviceIds.add(deviceId);
266 return deviceIds;
267 } else {
268 return existing;
269 }
270 });
271 return Objects.nonNull(valueOrNull(result));
272 }
273
274 @Override
275 public boolean removeDeviceFromVtapNetwork(Integer key, DeviceId deviceId) {
276 Versioned<Set<DeviceId>> result =
277 vtapNetworkDevicesConsistentMap.compute(key, (id, existing) -> {
278 // Remove deviceId from deviceIds
279 if (existing != null && existing.contains(deviceId)) {
280 Set<DeviceId> deviceIds = Sets.newHashSet(existing);
281 deviceIds.remove(deviceId);
282 return deviceIds;
283 } else {
284 return existing;
285 }
286 });
287 return Objects.nonNull(valueOrNull(result));
288 }
289
290 @Override
291 public Set<DeviceId> getVtapNetworkDevices(Integer key) {
292 return valueOrNull(vtapNetworkDevicesConsistentMap.get(key));
293 }
294
295 private boolean shouldUpdateVtap(DefaultOpenstackVtap existing,
296 OpenstackVtap description,
297 boolean replaceDevices) {
298 if (existing == null) {
299 return true;
300 }
301
302 if (!Objects.equals(existing.type(), description.type()) ||
303 !Objects.equals(existing.vtapCriterion(), description.vtapCriterion())) {
304 return true;
305 }
306
307 if (replaceDevices) {
308 if (!Objects.equals(description.txDeviceIds(), existing.txDeviceIds()) ||
309 !Objects.equals(description.rxDeviceIds(), existing.rxDeviceIds())) {
310 return true;
311 }
312 } else {
313 if (!existing.txDeviceIds().containsAll(description.txDeviceIds()) ||
314 !existing.rxDeviceIds().containsAll(description.rxDeviceIds())) {
315 return true;
316 }
317 }
318
319 // check to see if any of the annotations provided by description
320 // differ from those in the existing vtap
321 return description.annotations().keys().stream()
322 .anyMatch(k -> !Objects.equals(description.annotations().value(k),
323 existing.annotations().value(k)));
324 }
325
326 private OpenstackVtap createOrUpdateVtap(boolean update,
327 OpenstackVtap description,
328 boolean replaceDevices) {
329 DefaultOpenstackVtap result =
330 vtapMap.compute(description.id(), (id, existing) -> {
331 // Check create or update validity
332 if (update && existing == null) {
333 return null;
334 } else if (!update && existing != null) {
335 return existing;
336 }
337
338 if (shouldUpdateVtap(existing, description, replaceDevices)) {
339 // Replace or add devices
340 final Set<DeviceId> txDeviceIds;
341 if (existing == null || replaceDevices) {
342 txDeviceIds = description.txDeviceIds();
343 } else {
344 txDeviceIds = Sets.newHashSet(existing.txDeviceIds());
345 txDeviceIds.addAll(description.txDeviceIds());
346 }
347
348 final Set<DeviceId> rxDeviceIds;
349 if (existing == null || replaceDevices) {
350 rxDeviceIds = description.rxDeviceIds();
351 } else {
352 rxDeviceIds = Sets.newHashSet(existing.rxDeviceIds());
353 rxDeviceIds.addAll(description.rxDeviceIds());
354 }
355
356 // Replace or add annotations
357 final SparseAnnotations annotations;
358 if (existing != null) {
359 annotations = merge((DefaultAnnotations) existing.annotations(),
360 (SparseAnnotations) description.annotations());
361 } else {
362 annotations = (SparseAnnotations) description.annotations();
363 }
364
365 return DefaultOpenstackVtap.builder(description)
366 .txDeviceIds(txDeviceIds)
367 .rxDeviceIds(rxDeviceIds)
368 .annotations(annotations)
369 .build();
370 }
371 return existing;
372 });
373 return result;
374 }
375
376 @Override
377 public OpenstackVtap createVtap(OpenstackVtap description) {
378 if (getVtap(description.id()) == null) {
379 OpenstackVtap vtap = createOrUpdateVtap(false, description, true);
380 if (Objects.equals(vtap, description)) {
381 return vtap;
382 }
383 }
384 log.error(ERR_DUPLICATE, description.id());
385 return null;
386 }
387
388 @Override
389 public OpenstackVtap updateVtap(OpenstackVtap description, boolean replaceDevices) {
390 OpenstackVtap vtap = createOrUpdateVtap(true, description, replaceDevices);
391 if (vtap == null) {
392 log.error(ERR_NOT_FOUND, description.id());
393 }
394 return vtap;
395 }
396
397 @Override
398 public OpenstackVtap removeVtap(OpenstackVtapId vtapId) {
399 return vtapMap.remove(vtapId);
400 }
401
402 @Override
403 public void clearVtaps() {
404 vtapMap.clear();
405 }
406
407 @Override
408 public int getVtapCount(Type type) {
409 return (int) vtapMap.values().parallelStream()
410 .filter(vtap -> vtap.type().isValid(type))
411 .count();
412 }
413
414 @Override
415 public Set<OpenstackVtap> getVtaps(Type type) {
416 return ImmutableSet.copyOf(
417 vtapMap.values().parallelStream()
418 .filter(vtap -> vtap.type().isValid(type))
419 .collect(Collectors.toSet()));
420 }
421
422 @Override
423 public OpenstackVtap getVtap(OpenstackVtapId vtapId) {
424 return vtapMap.get(vtapId);
425 }
426
427 @Override
428 public boolean addDeviceToVtap(OpenstackVtapId vtapId, Type type, DeviceId deviceId) {
429 OpenstackVtap result =
430 vtapMap.compute(vtapId, (id, existing) -> {
431 if (existing == null) {
432 return null;
433 }
434
435 // Check type validate
436 if (!existing.type().isValid(type)) {
437 log.error("Not valid OpenstackVtap type {} for requested type {}", existing.type(), type);
438 return existing;
439 }
440
441 // Add deviceId to txDeviceIds
442 final Set<DeviceId> txDeviceIds;
443 if (existing.type().isValid(Type.VTAP_TX) &&
444 (type.isValid(Type.VTAP_TX) || type == Type.VTAP_ANY) &&
445 !existing.txDeviceIds().contains(deviceId)) {
446 txDeviceIds = Sets.newHashSet(existing.txDeviceIds());
447 txDeviceIds.add(deviceId);
448 } else {
449 txDeviceIds = null;
450 }
451
452 // Add deviceId to rxDeviceIds
453 final Set<DeviceId> rxDeviceIds;
454 if (existing.type().isValid(Type.VTAP_RX) &&
455 (type.isValid(Type.VTAP_RX) || type == Type.VTAP_ANY) &&
456 !existing.rxDeviceIds().contains(deviceId)) {
457 rxDeviceIds = Sets.newHashSet(existing.rxDeviceIds());
458 rxDeviceIds.add(deviceId);
459 } else {
460 rxDeviceIds = null;
461 }
462
463 if (txDeviceIds != null || rxDeviceIds != null) {
464 return DefaultOpenstackVtap.builder()
465 .id(id)
466 .type(existing.type())
467 .vtapCriterion(existing.vtapCriterion())
468 .txDeviceIds(txDeviceIds != null ? txDeviceIds : existing.txDeviceIds())
469 .rxDeviceIds(rxDeviceIds != null ? rxDeviceIds : existing.rxDeviceIds())
470 .annotations(existing.annotations())
471 .build();
472 } else {
473 return existing;
474 }
475 });
476 return Objects.nonNull(result);
477 }
478
479 @Override
480 public boolean removeDeviceFromVtap(OpenstackVtapId vtapId, OpenstackVtap.Type type, DeviceId deviceId) {
481 OpenstackVtap result =
482 vtapMap.compute(vtapId, (id, existing) -> {
483 if (existing == null) {
484 return null;
485 }
486
487 // Check type validate
488 if (!existing.type().isValid(type)) {
489 log.error("Not valid OpenstackVtap type {} for requested type {}",
490 existing.type(), type);
491 return existing;
492 }
493
494 // Remove deviceId from txDeviceIds
495 final Set<DeviceId> txDeviceIds;
496 if (existing.type().isValid(Type.VTAP_TX) &&
497 (type.isValid(Type.VTAP_TX) || type == Type.VTAP_ANY) &&
498 existing.txDeviceIds().contains(deviceId)) {
499 txDeviceIds = Sets.newHashSet(existing.txDeviceIds());
500 txDeviceIds.remove(deviceId);
501 } else {
502 txDeviceIds = null;
503 }
504
505 // Remove deviceId from rxDeviceIds
506 final Set<DeviceId> rxDeviceIds;
507 if (existing.type().isValid(Type.VTAP_RX) &&
508 (type.isValid(Type.VTAP_RX) || type == Type.VTAP_ANY) &&
509 existing.rxDeviceIds().contains(deviceId)) {
510 rxDeviceIds = Sets.newHashSet(existing.rxDeviceIds());
511 rxDeviceIds.remove(deviceId);
512 } else {
513 rxDeviceIds = null;
514 }
515
516 if (txDeviceIds != null || rxDeviceIds != null) {
517 return DefaultOpenstackVtap.builder()
518 .id(id)
519 .type(existing.type())
520 .vtapCriterion(existing.vtapCriterion())
521 .txDeviceIds(txDeviceIds != null ? txDeviceIds : existing.txDeviceIds())
522 .rxDeviceIds(rxDeviceIds != null ? rxDeviceIds : existing.rxDeviceIds())
523 .annotations(existing.annotations())
524 .build();
525 } else {
526 return existing;
527 }
528 });
529 return Objects.nonNull(result);
530 }
531
532 @Override
533 public Set<OpenstackVtap> getVtapsByDeviceId(DeviceId deviceId) {
534 Set<OpenstackVtapId> vtapIds = Sets.newHashSet();
535 Set<OpenstackVtapId> txIds = vtapIdsByTxDeviceId.get(deviceId);
536 if (txIds != null) {
537 vtapIds.addAll(txIds);
538 }
539 Set<OpenstackVtapId> rxIds = vtapIdsByRxDeviceId.get(deviceId);
540 if (rxIds != null) {
541 vtapIds.addAll(rxIds);
542 }
543 return ImmutableSet.copyOf(
544 vtapIds.parallelStream()
545 .map(vtapId -> vtapMap.get(vtapId))
546 .filter(Objects::nonNull)
547 .collect(Collectors.toSet()));
548 }
549
Jian Li26ef1302018-07-04 14:37:06 +0900550 private class VtapComparator implements Comparator<OpenstackVtap> {
Jian Li19f25262018-07-03 22:37:12 +0900551 @Override
552 public int compare(OpenstackVtap v1, OpenstackVtap v2) {
553 int diff = (v2.type().compareTo(v1.type()));
554 if (diff == 0) {
Jimo Jung14e87bf2018-09-03 16:28:13 +0900555 return (v2.vtapCriterion().ipProtocol() - v1.vtapCriterion().ipProtocol());
Jian Li19f25262018-07-03 22:37:12 +0900556 }
557 return diff;
558 }
559 }
560
Jimo Jung14e87bf2018-09-03 16:28:13 +0900561 private void loadVtapIds() {
562 vtapIdsByTxDeviceId.clear();
563 vtapIdsByRxDeviceId.clear();
564 vtapMap.values().forEach(vtap -> refreshDeviceIdsByVtap(null, vtap));
565 }
566
567 private static Set<OpenstackVtapId> addVTapIds(OpenstackVtapId vtapId) {
Jian Li19f25262018-07-03 22:37:12 +0900568 Set<OpenstackVtapId> vtapIds = Sets.newConcurrentHashSet();
Jimo Jung14e87bf2018-09-03 16:28:13 +0900569 vtapIds.add(vtapId);
Jian Li19f25262018-07-03 22:37:12 +0900570 return vtapIds;
571 }
572
573 private static Set<OpenstackVtapId> updateVTapIds(Set<OpenstackVtapId> existingVtapIds,
Jimo Jung14e87bf2018-09-03 16:28:13 +0900574 OpenstackVtapId vtapId) {
575 existingVtapIds.add(vtapId);
Jian Li19f25262018-07-03 22:37:12 +0900576 return existingVtapIds;
577 }
578
579 private static Set<OpenstackVtapId> removeVTapIds(Set<OpenstackVtapId> existingVtapIds,
Jimo Jung14e87bf2018-09-03 16:28:13 +0900580 OpenstackVtapId vtapId) {
581 existingVtapIds.remove(vtapId);
Jian Li19f25262018-07-03 22:37:12 +0900582 if (existingVtapIds.isEmpty()) {
583 return null;
584 }
585 return existingVtapIds;
586 }
587
Jimo Jung14e87bf2018-09-03 16:28:13 +0900588 private void updateVTapIdFromTxDeviceId(OpenstackVtapId vtapId, DeviceId deviceId) {
589 vtapIdsByTxDeviceId.compute(deviceId, (k, v) -> v == null ?
590 addVTapIds(vtapId) : updateVTapIds(v, vtapId));
Jian Li19f25262018-07-03 22:37:12 +0900591 }
592
Jimo Jung14e87bf2018-09-03 16:28:13 +0900593 private void removeVTapIdFromTxDeviceId(OpenstackVtapId vtapId, DeviceId deviceId) {
594 vtapIdsByTxDeviceId.computeIfPresent(deviceId, (k, v) -> removeVTapIds(v, vtapId));
Jian Li19f25262018-07-03 22:37:12 +0900595 }
596
Jimo Jung14e87bf2018-09-03 16:28:13 +0900597 private void updateVTapIdFromRxDeviceId(OpenstackVtapId vtapId, DeviceId deviceId) {
598 vtapIdsByRxDeviceId.compute(deviceId, (k, v) -> v == null ?
599 addVTapIds(vtapId) : updateVTapIds(v, vtapId));
Jian Li19f25262018-07-03 22:37:12 +0900600 }
601
Jimo Jung14e87bf2018-09-03 16:28:13 +0900602 private void removeVTapIdFromRxDeviceId(OpenstackVtapId vtapId, DeviceId deviceId) {
603 vtapIdsByRxDeviceId.computeIfPresent(deviceId, (k, v) -> removeVTapIds(v, vtapId));
Jian Li19f25262018-07-03 22:37:12 +0900604 }
605
Jimo Jung14e87bf2018-09-03 16:28:13 +0900606 private void refreshDeviceIdsByVtap(OpenstackVtap newOpenstackVtap,
607 OpenstackVtap oldOpenstackVtap) {
608 if (Objects.equals(newOpenstackVtap, oldOpenstackVtap)) {
609 return;
610 }
611
Jian Li19f25262018-07-03 22:37:12 +0900612 if (oldOpenstackVtap != null) {
613 Set<DeviceId> removeDeviceIds;
614
Jimo Jung14e87bf2018-09-03 16:28:13 +0900615 // Remove TX vtap
Jian Li19f25262018-07-03 22:37:12 +0900616 removeDeviceIds = (newOpenstackVtap != null) ?
617 Sets.difference(oldOpenstackVtap.txDeviceIds(),
618 newOpenstackVtap.txDeviceIds()) : oldOpenstackVtap.txDeviceIds();
619 removeDeviceIds.forEach(id -> removeVTapIdFromTxDeviceId(oldOpenstackVtap.id(), id));
620
Jimo Jung14e87bf2018-09-03 16:28:13 +0900621 // Remove RX vtap
Jian Li19f25262018-07-03 22:37:12 +0900622 removeDeviceIds = (newOpenstackVtap != null) ?
623 Sets.difference(oldOpenstackVtap.rxDeviceIds(),
624 newOpenstackVtap.rxDeviceIds()) : oldOpenstackVtap.rxDeviceIds();
625 removeDeviceIds.forEach(id -> removeVTapIdFromRxDeviceId(oldOpenstackVtap.id(), id));
626 }
627
628 if (newOpenstackVtap != null) {
629 Set<DeviceId> addDeviceIds;
630
Jimo Jung14e87bf2018-09-03 16:28:13 +0900631 // Add TX vtap
Jian Li19f25262018-07-03 22:37:12 +0900632 addDeviceIds = (oldOpenstackVtap != null) ?
633 Sets.difference(newOpenstackVtap.txDeviceIds(),
634 oldOpenstackVtap.txDeviceIds()) : newOpenstackVtap.txDeviceIds();
635 addDeviceIds.forEach(id -> updateVTapIdFromTxDeviceId(newOpenstackVtap.id(), id));
636
Jimo Jung14e87bf2018-09-03 16:28:13 +0900637 // Add RX vtap
Jian Li19f25262018-07-03 22:37:12 +0900638 addDeviceIds = (oldOpenstackVtap != null) ?
639 Sets.difference(newOpenstackVtap.rxDeviceIds(),
640 oldOpenstackVtap.rxDeviceIds()) : newOpenstackVtap.rxDeviceIds();
641 addDeviceIds.forEach(id -> updateVTapIdFromRxDeviceId(newOpenstackVtap.id(), id));
642 }
643 }
644
Jian Li26ef1302018-07-04 14:37:06 +0900645 private class VtapEventListener
Jian Li19f25262018-07-03 22:37:12 +0900646 implements MapEventListener<OpenstackVtapId, DefaultOpenstackVtap> {
647 @Override
648 public void event(MapEvent<OpenstackVtapId, DefaultOpenstackVtap> event) {
649 DefaultOpenstackVtap newValue =
650 event.newValue() != null ? event.newValue().value() : null;
651 DefaultOpenstackVtap oldValue =
652 event.oldValue() != null ? event.oldValue().value() : null;
653
Jimo Jung14e87bf2018-09-03 16:28:13 +0900654 log.trace("VtapEventListener {}: {} -> {}", event.type(), oldValue, newValue);
Jian Li19f25262018-07-03 22:37:12 +0900655 switch (event.type()) {
656 case INSERT:
Jimo Jung14e87bf2018-09-03 16:28:13 +0900657 refreshDeviceIdsByVtap(newValue, oldValue);
Jian Li19f25262018-07-03 22:37:12 +0900658 notifyDelegate(new OpenstackVtapEvent(
Jimo Jung14e87bf2018-09-03 16:28:13 +0900659 OpenstackVtapEvent.Type.VTAP_ADDED, newValue, null));
Jian Li19f25262018-07-03 22:37:12 +0900660 break;
661
662 case UPDATE:
Jimo Jung14e87bf2018-09-03 16:28:13 +0900663 refreshDeviceIdsByVtap(newValue, oldValue);
664 notifyDelegate(new OpenstackVtapEvent(
665 OpenstackVtapEvent.Type.VTAP_UPDATED, newValue, oldValue));
Jian Li19f25262018-07-03 22:37:12 +0900666 break;
667
668 case REMOVE:
Jimo Jung14e87bf2018-09-03 16:28:13 +0900669 refreshDeviceIdsByVtap(newValue, oldValue);
Jian Li19f25262018-07-03 22:37:12 +0900670 notifyDelegate(new OpenstackVtapEvent(
Jimo Jung14e87bf2018-09-03 16:28:13 +0900671 OpenstackVtapEvent.Type.VTAP_REMOVED, null, oldValue));
Jian Li19f25262018-07-03 22:37:12 +0900672 break;
673
674 default:
675 log.warn("Unknown map event type: {}", event.type());
676 }
677 }
678 }
Jimo Jung14e87bf2018-09-03 16:28:13 +0900679
680 private class VtapNetworkEventListener
681 implements MapEventListener<Integer, DefaultOpenstackVtapNetwork> {
682 @Override
683 public void event(MapEvent<Integer, DefaultOpenstackVtapNetwork> event) {
684 DefaultOpenstackVtapNetwork newValue =
685 event.newValue() != null ? event.newValue().value() : null;
686 DefaultOpenstackVtapNetwork oldValue =
687 event.oldValue() != null ? event.oldValue().value() : null;
688
689 log.trace("VtapNetworkEventListener {}: {} -> {}", event.type(), oldValue, newValue);
690 switch (event.type()) {
691 case INSERT:
692 notifyDelegate(new OpenstackVtapEvent(
693 OpenstackVtapEvent.Type.VTAP_NETWORK_ADDED, newValue, null));
694 break;
695
696 case UPDATE:
697 notifyDelegate(new OpenstackVtapEvent(
698 OpenstackVtapEvent.Type.VTAP_NETWORK_UPDATED, newValue, oldValue));
699 break;
700
701 case REMOVE:
702 notifyDelegate(new OpenstackVtapEvent(
703 OpenstackVtapEvent.Type.VTAP_NETWORK_REMOVED, null, oldValue));
704 break;
705
706 default:
707 log.warn("Unknown map event type: {}", event.type());
708 }
709 }
710 }
711
Jian Li19f25262018-07-03 22:37:12 +0900712}