blob: 967504c6b765874f53360fb93f7986a76ff29c42 [file] [log] [blame]
Thomas Vachuska33979fd2015-07-31 11:41:14 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
Thomas Vachuska33979fd2015-07-31 11:41:14 -07003 *
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.incubator.store.virtual.impl;
17
Brian Stanke0e5c94e2016-03-08 11:20:04 -050018import com.google.common.collect.ImmutableSet;
19import com.google.common.collect.Sets;
Thomas Vachuska33979fd2015-07-31 11:41:14 -070020import org.apache.felix.scr.annotations.Activate;
21import org.apache.felix.scr.annotations.Component;
22import org.apache.felix.scr.annotations.Deactivate;
Brian Stanke0e5c94e2016-03-08 11:20:04 -050023import org.apache.felix.scr.annotations.Reference;
24import org.apache.felix.scr.annotations.ReferenceCardinality;
Thomas Vachuska33979fd2015-07-31 11:41:14 -070025import org.apache.felix.scr.annotations.Service;
Brian Stanke7a81b532016-06-14 15:43:51 -040026import org.onlab.packet.IpAddress;
27import org.onlab.packet.MacAddress;
28import org.onlab.packet.VlanId;
Brian Stanke0e5c94e2016-03-08 11:20:04 -050029import org.onlab.util.KryoNamespace;
30import org.onosproject.core.CoreService;
31import org.onosproject.core.IdGenerator;
Thomas Vachuska33979fd2015-07-31 11:41:14 -070032import org.onosproject.incubator.net.tunnel.TunnelId;
33import org.onosproject.incubator.net.virtual.DefaultVirtualDevice;
Brian Stanke7a81b532016-06-14 15:43:51 -040034import org.onosproject.incubator.net.virtual.DefaultVirtualHost;
Brian Stanke0e5c94e2016-03-08 11:20:04 -050035import org.onosproject.incubator.net.virtual.DefaultVirtualLink;
Thomas Vachuska33979fd2015-07-31 11:41:14 -070036import org.onosproject.incubator.net.virtual.DefaultVirtualNetwork;
Brian Stanke0e5c94e2016-03-08 11:20:04 -050037import org.onosproject.incubator.net.virtual.DefaultVirtualPort;
Thomas Vachuska33979fd2015-07-31 11:41:14 -070038import org.onosproject.incubator.net.virtual.NetworkId;
39import org.onosproject.incubator.net.virtual.TenantId;
40import org.onosproject.incubator.net.virtual.VirtualDevice;
Brian Stanke7a81b532016-06-14 15:43:51 -040041import org.onosproject.incubator.net.virtual.VirtualHost;
Thomas Vachuska33979fd2015-07-31 11:41:14 -070042import org.onosproject.incubator.net.virtual.VirtualLink;
43import org.onosproject.incubator.net.virtual.VirtualNetwork;
44import org.onosproject.incubator.net.virtual.VirtualNetworkEvent;
Brian Stanke11f6d532016-07-05 16:17:59 -040045import org.onosproject.incubator.net.virtual.VirtualNetworkIntent;
Brian Stanke0e5c94e2016-03-08 11:20:04 -050046import org.onosproject.incubator.net.virtual.VirtualNetworkService;
Thomas Vachuska33979fd2015-07-31 11:41:14 -070047import org.onosproject.incubator.net.virtual.VirtualNetworkStore;
48import org.onosproject.incubator.net.virtual.VirtualNetworkStoreDelegate;
49import org.onosproject.incubator.net.virtual.VirtualPort;
50import org.onosproject.net.ConnectPoint;
Brian Stanke0e5c94e2016-03-08 11:20:04 -050051import org.onosproject.net.Device;
Thomas Vachuska33979fd2015-07-31 11:41:14 -070052import org.onosproject.net.DeviceId;
Brian Stanke7a81b532016-06-14 15:43:51 -040053import org.onosproject.net.HostId;
54import org.onosproject.net.HostLocation;
Brian Stanke612cebf2016-05-02 10:21:33 -040055import org.onosproject.net.Link;
Thomas Vachuska33979fd2015-07-31 11:41:14 -070056import org.onosproject.net.PortNumber;
Brian Stanke11f6d532016-07-05 16:17:59 -040057import org.onosproject.net.intent.Intent;
58import org.onosproject.net.intent.IntentData;
59import org.onosproject.net.intent.IntentState;
60import org.onosproject.net.intent.Key;
Thomas Vachuska33979fd2015-07-31 11:41:14 -070061import org.onosproject.store.AbstractStore;
Brian Stanke0e5c94e2016-03-08 11:20:04 -050062import org.onosproject.store.serializers.KryoNamespaces;
63import org.onosproject.store.service.ConsistentMap;
64import org.onosproject.store.service.DistributedSet;
65import org.onosproject.store.service.MapEvent;
66import org.onosproject.store.service.MapEventListener;
67import org.onosproject.store.service.Serializer;
68import org.onosproject.store.service.SetEvent;
69import org.onosproject.store.service.SetEventListener;
70import org.onosproject.store.service.StorageService;
Brian Stanke11f6d532016-07-05 16:17:59 -040071import org.onosproject.store.service.WallClockTimestamp;
Thomas Vachuska33979fd2015-07-31 11:41:14 -070072import org.slf4j.Logger;
73
Brian Stanke0e5c94e2016-03-08 11:20:04 -050074import java.util.HashSet;
75import java.util.Map;
Thomas Vachuska33979fd2015-07-31 11:41:14 -070076import java.util.Set;
Claudine Chiu945828d2016-11-21 12:47:07 -050077import java.util.function.BiFunction;
Thomas Vachuska33979fd2015-07-31 11:41:14 -070078
Brian Stanke0e5c94e2016-03-08 11:20:04 -050079import static com.google.common.base.Preconditions.checkNotNull;
80import static com.google.common.base.Preconditions.checkState;
Thomas Vachuska33979fd2015-07-31 11:41:14 -070081import static org.slf4j.LoggerFactory.getLogger;
82
83/**
Brian Stanke0e5c94e2016-03-08 11:20:04 -050084 * Implementation of the virtual network store.
Thomas Vachuska33979fd2015-07-31 11:41:14 -070085 */
86@Component(immediate = true)
87@Service
88public class DistributedVirtualNetworkStore
89 extends AbstractStore<VirtualNetworkEvent, VirtualNetworkStoreDelegate>
90 implements VirtualNetworkStore {
91
92 private final Logger log = getLogger(getClass());
93
Brian Stanke0e5c94e2016-03-08 11:20:04 -050094 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
95 protected StorageService storageService;
Thomas Vachuska33979fd2015-07-31 11:41:14 -070096
Brian Stanke0e5c94e2016-03-08 11:20:04 -050097 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
98 protected CoreService coreService;
Thomas Vachuska33979fd2015-07-31 11:41:14 -070099
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500100 private IdGenerator idGenerator;
101
102 // Track tenants by ID
103 private DistributedSet<TenantId> tenantIdSet;
104
105 // Listener for tenant events
106 private final SetEventListener<TenantId> setListener = new InternalSetListener();
107
108 // Track virtual networks by network Id
109 private ConsistentMap<NetworkId, VirtualNetwork> networkIdVirtualNetworkConsistentMap;
110 private Map<NetworkId, VirtualNetwork> networkIdVirtualNetworkMap;
111
112 // Listener for virtual network events
Claudine Chiu945828d2016-11-21 12:47:07 -0500113 private final MapEventListener<NetworkId, VirtualNetwork> virtualNetworkMapListener =
114 new InternalMapListener<>((mapEventType, virtualNetwork) -> {
115 VirtualNetworkEvent.Type eventType =
116 mapEventType.equals(MapEvent.Type.INSERT) ? VirtualNetworkEvent.Type.NETWORK_ADDED :
117 mapEventType.equals(MapEvent.Type.UPDATE) ? VirtualNetworkEvent.Type.NETWORK_UPDATED :
118 mapEventType.equals(MapEvent.Type.REMOVE) ? VirtualNetworkEvent.Type.NETWORK_REMOVED : null;
119 return eventType == null ? null : new VirtualNetworkEvent(eventType, virtualNetwork.id());
120 });
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500121
122 // Track virtual network IDs by tenant Id
123 private ConsistentMap<TenantId, Set<NetworkId>> tenantIdNetworkIdSetConsistentMap;
124 private Map<TenantId, Set<NetworkId>> tenantIdNetworkIdSetMap;
125
126 // Track virtual devices by device Id
127 private ConsistentMap<DeviceId, VirtualDevice> deviceIdVirtualDeviceConsistentMap;
128 private Map<DeviceId, VirtualDevice> deviceIdVirtualDeviceMap;
129
Claudine Chiu945828d2016-11-21 12:47:07 -0500130 // Listener for virtual device events
131 private final MapEventListener<DeviceId, VirtualDevice> virtualDeviceMapListener =
132 new InternalMapListener<>((mapEventType, virtualDevice) -> {
133 VirtualNetworkEvent.Type eventType =
134 mapEventType.equals(MapEvent.Type.INSERT) ? VirtualNetworkEvent.Type.VIRTUAL_DEVICE_ADDED :
135 mapEventType.equals(MapEvent.Type.UPDATE) ? VirtualNetworkEvent.Type.VIRTUAL_DEVICE_UPDATED :
136 mapEventType.equals(MapEvent.Type.REMOVE) ? VirtualNetworkEvent.Type.VIRTUAL_DEVICE_REMOVED : null;
137 return eventType == null ? null :
138 new VirtualNetworkEvent(eventType, virtualDevice.networkId(), virtualDevice);
139 });
140
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500141 // Track device IDs by network Id
142 private ConsistentMap<NetworkId, Set<DeviceId>> networkIdDeviceIdSetConsistentMap;
143 private Map<NetworkId, Set<DeviceId>> networkIdDeviceIdSetMap;
144
Brian Stanke7a81b532016-06-14 15:43:51 -0400145 // Track virtual hosts by host Id
146 private ConsistentMap<HostId, VirtualHost> hostIdVirtualHostConsistentMap;
147 private Map<HostId, VirtualHost> hostIdVirtualHostMap;
148
149 // Track host IDs by network Id
150 private ConsistentMap<NetworkId, Set<HostId>> networkIdHostIdSetConsistentMap;
151 private Map<NetworkId, Set<HostId>> networkIdHostIdSetMap;
152
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500153 // Track virtual links by network Id
154 private ConsistentMap<NetworkId, Set<VirtualLink>> networkIdVirtualLinkSetConsistentMap;
155 private Map<NetworkId, Set<VirtualLink>> networkIdVirtualLinkSetMap;
156
157 // Track virtual ports by network Id
158 private ConsistentMap<NetworkId, Set<VirtualPort>> networkIdVirtualPortSetConsistentMap;
159 private Map<NetworkId, Set<VirtualPort>> networkIdVirtualPortSetMap;
160
Brian Stanke11f6d532016-07-05 16:17:59 -0400161 // Track intent key to intent data
162 private ConsistentMap<Key, IntentData> intentKeyIntentDataConsistentMap;
163 private Map<Key, IntentData> intentKeyIntentDataMap;
164
165 // Track intent ID to TunnelIds
166 private ConsistentMap<Key, Set<TunnelId>> intentKeyTunnelIdSetConsistentMap;
167 private Map<Key, Set<TunnelId>> intentKeyTunnelIdSetMap;
168
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500169 private static final Serializer SERIALIZER = Serializer
170 .using(new KryoNamespace.Builder().register(KryoNamespaces.API)
171 .register(TenantId.class)
HIGUCHI Yutac0f50452016-05-13 19:26:05 -0700172 .register(NetworkId.class)
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500173 .register(VirtualNetwork.class)
Brian Stanke5df14472016-03-11 19:34:38 -0500174 .register(DefaultVirtualNetwork.class)
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500175 .register(VirtualDevice.class)
Brian Stanke5df14472016-03-11 19:34:38 -0500176 .register(DefaultVirtualDevice.class)
Brian Stanke7a81b532016-06-14 15:43:51 -0400177 .register(VirtualHost.class)
178 .register(DefaultVirtualHost.class)
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500179 .register(VirtualLink.class)
Brian Stanke5df14472016-03-11 19:34:38 -0500180 .register(DefaultVirtualLink.class)
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500181 .register(VirtualPort.class)
Brian Stanke5df14472016-03-11 19:34:38 -0500182 .register(DefaultVirtualPort.class)
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500183 .register(Device.class)
Brian Stanke9a108972016-04-11 15:25:17 -0400184 .register(TunnelId.class)
Brian Stanke11f6d532016-07-05 16:17:59 -0400185 .register(IntentData.class)
186 .register(VirtualNetworkIntent.class)
187 .register(WallClockTimestamp.class)
HIGUCHI Yuta03666a32016-05-18 11:49:09 -0700188 .nextId(KryoNamespaces.BEGIN_USER_CUSTOM_ID)
Brian Stanke11f6d532016-07-05 16:17:59 -0400189 .build());
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500190
191 /**
192 * Distributed network store service activate method.
193 */
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700194 @Activate
195 public void activate() {
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500196 idGenerator = coreService.getIdGenerator(VirtualNetworkService.VIRTUAL_NETWORK_TOPIC);
197
198 tenantIdSet = storageService.<TenantId>setBuilder()
199 .withSerializer(SERIALIZER)
200 .withName("onos-tenantId")
201 .withRelaxedReadConsistency()
202 .build()
203 .asDistributedSet();
204 tenantIdSet.addListener(setListener);
205
206 networkIdVirtualNetworkConsistentMap = storageService.<NetworkId, VirtualNetwork>consistentMapBuilder()
207 .withSerializer(SERIALIZER)
208 .withName("onos-networkId-virtualnetwork")
209 .withRelaxedReadConsistency()
210 .build();
Claudine Chiu945828d2016-11-21 12:47:07 -0500211 networkIdVirtualNetworkConsistentMap.addListener(virtualNetworkMapListener);
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500212 networkIdVirtualNetworkMap = networkIdVirtualNetworkConsistentMap.asJavaMap();
213
214 tenantIdNetworkIdSetConsistentMap = storageService.<TenantId, Set<NetworkId>>consistentMapBuilder()
215 .withSerializer(SERIALIZER)
216 .withName("onos-tenantId-networkIds")
217 .withRelaxedReadConsistency()
218 .build();
219 tenantIdNetworkIdSetMap = tenantIdNetworkIdSetConsistentMap.asJavaMap();
220
221 deviceIdVirtualDeviceConsistentMap = storageService.<DeviceId, VirtualDevice>consistentMapBuilder()
222 .withSerializer(SERIALIZER)
223 .withName("onos-deviceId-virtualdevice")
224 .withRelaxedReadConsistency()
225 .build();
Claudine Chiu945828d2016-11-21 12:47:07 -0500226 deviceIdVirtualDeviceConsistentMap.addListener(virtualDeviceMapListener);
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500227 deviceIdVirtualDeviceMap = deviceIdVirtualDeviceConsistentMap.asJavaMap();
228
229 networkIdDeviceIdSetConsistentMap = storageService.<NetworkId, Set<DeviceId>>consistentMapBuilder()
230 .withSerializer(SERIALIZER)
231 .withName("onos-networkId-deviceIds")
232 .withRelaxedReadConsistency()
233 .build();
234 networkIdDeviceIdSetMap = networkIdDeviceIdSetConsistentMap.asJavaMap();
235
Brian Stanke7a81b532016-06-14 15:43:51 -0400236 hostIdVirtualHostConsistentMap = storageService.<HostId, VirtualHost>consistentMapBuilder()
237 .withSerializer(SERIALIZER)
238 .withName("onos-hostId-virtualhost")
239 .withRelaxedReadConsistency()
240 .build();
241 hostIdVirtualHostMap = hostIdVirtualHostConsistentMap.asJavaMap();
242
243 networkIdHostIdSetConsistentMap = storageService.<NetworkId, Set<HostId>>consistentMapBuilder()
244 .withSerializer(SERIALIZER)
245 .withName("onos-networkId-hostIds")
246 .withRelaxedReadConsistency()
247 .build();
248 networkIdHostIdSetMap = networkIdHostIdSetConsistentMap.asJavaMap();
249
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500250 networkIdVirtualLinkSetConsistentMap = storageService.<NetworkId, Set<VirtualLink>>consistentMapBuilder()
251 .withSerializer(SERIALIZER)
252 .withName("onos-networkId-virtuallinks")
253 .withRelaxedReadConsistency()
254 .build();
255 networkIdVirtualLinkSetMap = networkIdVirtualLinkSetConsistentMap.asJavaMap();
256
257 networkIdVirtualPortSetConsistentMap = storageService.<NetworkId, Set<VirtualPort>>consistentMapBuilder()
258 .withSerializer(SERIALIZER)
Brian Stanke11f6d532016-07-05 16:17:59 -0400259 .withName("onos-networkId-virtualports")
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500260 .withRelaxedReadConsistency()
261 .build();
262 networkIdVirtualPortSetMap = networkIdVirtualPortSetConsistentMap.asJavaMap();
263
Brian Stanke11f6d532016-07-05 16:17:59 -0400264 intentKeyTunnelIdSetConsistentMap = storageService.<Key, Set<TunnelId>>consistentMapBuilder()
265 .withSerializer(SERIALIZER)
266 .withName("onos-intentKey-tunnelIds")
267 .withRelaxedReadConsistency()
268 .build();
269 intentKeyTunnelIdSetMap = intentKeyTunnelIdSetConsistentMap.asJavaMap();
270
271 intentKeyIntentDataConsistentMap = storageService.<Key, IntentData>consistentMapBuilder()
272 .withSerializer(SERIALIZER)
273 .withName("onos-intentKey-intentData")
274 .withRelaxedReadConsistency()
275 .build();
276 intentKeyIntentDataMap = intentKeyIntentDataConsistentMap.asJavaMap();
277
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700278 log.info("Started");
279 }
280
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500281 /**
282 * Distributed network store service deactivate method.
283 */
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700284 @Deactivate
285 public void deactivate() {
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500286 tenantIdSet.removeListener(setListener);
Claudine Chiu945828d2016-11-21 12:47:07 -0500287 networkIdVirtualNetworkConsistentMap.removeListener(virtualNetworkMapListener);
288 deviceIdVirtualDeviceConsistentMap.removeListener(virtualDeviceMapListener);
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700289 log.info("Stopped");
290 }
291
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500292 /**
293 * This method is used for Junit tests to set the CoreService instance, which
294 * is required to set the IdGenerator instance.
295 *
296 * @param coreService core service instance
297 */
298 public void setCoreService(CoreService coreService) {
299 this.coreService = coreService;
300 }
301
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700302 @Override
303 public void addTenantId(TenantId tenantId) {
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500304 tenantIdSet.add(tenantId);
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700305 }
306
307 @Override
308 public void removeTenantId(TenantId tenantId) {
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500309 tenantIdSet.remove(tenantId);
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700310 }
311
312 @Override
313 public Set<TenantId> getTenantIds() {
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500314 return ImmutableSet.copyOf(tenantIdSet);
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700315 }
316
317 @Override
318 public VirtualNetwork addNetwork(TenantId tenantId) {
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500319
320 checkState(tenantIdSet.contains(tenantId), "The tenant has not been registered. " + tenantId.id());
321 VirtualNetwork virtualNetwork = new DefaultVirtualNetwork(genNetworkId(), tenantId);
322 //TODO update both maps in one transaction.
323 networkIdVirtualNetworkMap.put(virtualNetwork.id(), virtualNetwork);
Brian Stanke5df14472016-03-11 19:34:38 -0500324
325 Set<NetworkId> networkIdSet = tenantIdNetworkIdSetMap.get(tenantId);
326 if (networkIdSet == null) {
327 networkIdSet = new HashSet<>();
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500328 }
Brian Stanke5df14472016-03-11 19:34:38 -0500329 networkIdSet.add(virtualNetwork.id());
330 tenantIdNetworkIdSetMap.put(tenantId, networkIdSet);
331
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500332 return virtualNetwork;
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700333 }
334
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500335 /**
336 * Returns a new network identifier from a virtual network block of identifiers.
337 *
338 * @return NetworkId network identifier
339 */
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700340 private NetworkId genNetworkId() {
Kenji HIKICHIcfdf91b2016-05-25 13:04:45 +0900341 NetworkId networkId;
342 do {
343 networkId = NetworkId.networkId(idGenerator.getNewId());
344 } while (!networkId.isVirtualNetworkId());
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700345
Kenji HIKICHIcfdf91b2016-05-25 13:04:45 +0900346 return networkId;
347 }
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700348
349 @Override
350 public void removeNetwork(NetworkId networkId) {
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500351 // Make sure that the virtual network exists before attempting to remove it.
352 if (networkExists(networkId)) {
Brian Stanke5df14472016-03-11 19:34:38 -0500353 //TODO update both maps in one transaction.
354
355 VirtualNetwork virtualNetwork = networkIdVirtualNetworkMap.remove(networkId);
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500356 if (virtualNetwork == null) {
357 return;
358 }
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500359 TenantId tenantId = virtualNetwork.tenantId();
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500360
Brian Stanke5df14472016-03-11 19:34:38 -0500361 Set<NetworkId> networkIdSet = new HashSet<>();
362 tenantIdNetworkIdSetMap.get(tenantId).forEach(networkId1 -> {
363 if (networkId1.id().equals(networkId.id())) {
364 networkIdSet.add(networkId1);
365 }
366 });
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500367
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500368 tenantIdNetworkIdSetMap.compute(virtualNetwork.tenantId(), (id, existingNetworkIds) -> {
369 if (existingNetworkIds == null || existingNetworkIds.isEmpty()) {
HIGUCHI Yutac0f50452016-05-13 19:26:05 -0700370 return new HashSet<>();
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500371 } else {
HIGUCHI Yutac0f50452016-05-13 19:26:05 -0700372 return new HashSet<>(Sets.difference(existingNetworkIds, networkIdSet));
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500373 }
374 });
375 }
376 }
377
378 /**
379 * Returns if the network identifier exists.
380 *
381 * @param networkId network identifier
382 * @return true if the network identifier exists, false otherwise.
383 */
384 private boolean networkExists(NetworkId networkId) {
Brian Stanke612cebf2016-05-02 10:21:33 -0400385 checkNotNull(networkId, "The network identifier cannot be null.");
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500386 return (networkIdVirtualNetworkMap.containsKey(networkId));
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700387 }
388
389 @Override
390 public VirtualDevice addDevice(NetworkId networkId, DeviceId deviceId) {
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500391 checkState(networkExists(networkId), "The network has not been added.");
392 Set<DeviceId> deviceIdSet = networkIdDeviceIdSetMap.get(networkId);
393 if (deviceIdSet == null) {
394 deviceIdSet = new HashSet<>();
395 }
396 VirtualDevice virtualDevice = new DefaultVirtualDevice(networkId, deviceId);
397 //TODO update both maps in one transaction.
398 deviceIdVirtualDeviceMap.put(deviceId, virtualDevice);
399 deviceIdSet.add(deviceId);
400 networkIdDeviceIdSetMap.put(networkId, deviceIdSet);
401 return virtualDevice;
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700402 }
403
404 @Override
405 public void removeDevice(NetworkId networkId, DeviceId deviceId) {
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500406 checkState(networkExists(networkId), "The network has not been added.");
407 //TODO update both maps in one transaction.
Brian Stanke5df14472016-03-11 19:34:38 -0500408
409 Set<DeviceId> deviceIdSet = new HashSet<>();
410 networkIdDeviceIdSetMap.get(networkId).forEach(deviceId1 -> {
411 if (deviceId1.equals(deviceId)) {
412 deviceIdSet.add(deviceId1);
413 }
414 });
415
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500416 if (deviceIdSet != null) {
417 networkIdDeviceIdSetMap.compute(networkId, (id, existingDeviceIds) -> {
418 if (existingDeviceIds == null || existingDeviceIds.isEmpty()) {
HIGUCHI Yutac0f50452016-05-13 19:26:05 -0700419 return new HashSet<>();
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500420 } else {
HIGUCHI Yutac0f50452016-05-13 19:26:05 -0700421 return new HashSet<>(Sets.difference(existingDeviceIds, deviceIdSet));
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500422 }
423 });
424
Brian Stanke5df14472016-03-11 19:34:38 -0500425 deviceIdVirtualDeviceMap.remove(deviceId);
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500426 }
Brian Stanke7a81b532016-06-14 15:43:51 -0400427 //TODO remove virtual links and ports when removing the virtual device
428 }
429
430 @Override
431 public VirtualHost addHost(NetworkId networkId, HostId hostId, MacAddress mac,
432 VlanId vlan, HostLocation location, Set<IpAddress> ips) {
433 checkState(networkExists(networkId), "The network has not been added.");
434 Set<HostId> hostIdSet = networkIdHostIdSetMap.get(networkId);
435 if (hostIdSet == null) {
436 hostIdSet = new HashSet<>();
437 }
438 VirtualHost virtualhost = new DefaultVirtualHost(networkId, hostId, mac, vlan, location, ips);
439 //TODO update both maps in one transaction.
440 hostIdVirtualHostMap.put(hostId, virtualhost);
441 hostIdSet.add(hostId);
442 networkIdHostIdSetMap.put(networkId, hostIdSet);
443 return virtualhost;
444 }
445
446 @Override
447 public void removeHost(NetworkId networkId, HostId hostId) {
448 checkState(networkExists(networkId), "The network has not been added.");
449 //TODO update both maps in one transaction.
450
451 Set<HostId> hostIdSet = new HashSet<>();
452 networkIdHostIdSetMap.get(networkId).forEach(hostId1 -> {
453 if (hostId1.equals(hostId)) {
454 hostIdSet.add(hostId1);
455 }
456 });
457
458 if (hostIdSet != null) {
459 networkIdHostIdSetMap.compute(networkId, (id, existingHostIds) -> {
460 if (existingHostIds == null || existingHostIds.isEmpty()) {
461 return new HashSet<>();
462 } else {
463 return new HashSet<>(Sets.difference(existingHostIds, hostIdSet));
464 }
465 });
466
467 hostIdVirtualHostMap.remove(hostId);
468 }
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700469 }
470
471 @Override
Brian Stanke612cebf2016-05-02 10:21:33 -0400472 public VirtualLink addLink(NetworkId networkId, ConnectPoint src, ConnectPoint dst,
473 Link.State state, TunnelId realizedBy) {
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500474 checkState(networkExists(networkId), "The network has not been added.");
475 Set<VirtualLink> virtualLinkSet = networkIdVirtualLinkSetMap.get(networkId);
476 if (virtualLinkSet == null) {
477 virtualLinkSet = new HashSet<>();
478 }
Brian Stanke9a108972016-04-11 15:25:17 -0400479 // validate that the link does not already exist in this network
480 checkState(getLink(networkId, src, dst) == null, "The virtual link already exists");
481
482 VirtualLink virtualLink = DefaultVirtualLink.builder()
483 .networkId(networkId)
484 .src(src)
485 .dst(dst)
Brian Stanke612cebf2016-05-02 10:21:33 -0400486 .state(state)
Brian Stanke9a108972016-04-11 15:25:17 -0400487 .tunnelId(realizedBy)
488 .build();
489
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500490 virtualLinkSet.add(virtualLink);
491 networkIdVirtualLinkSetMap.put(networkId, virtualLinkSet);
492 return virtualLink;
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700493 }
494
495 @Override
Brian Stanke612cebf2016-05-02 10:21:33 -0400496 public void updateLink(VirtualLink virtualLink, TunnelId tunnelId, Link.State state) {
Brian Stanke9a108972016-04-11 15:25:17 -0400497 checkState(networkExists(virtualLink.networkId()), "The network has not been added.");
498 Set<VirtualLink> virtualLinkSet = networkIdVirtualLinkSetMap.get(virtualLink.networkId());
499 if (virtualLinkSet == null) {
500 virtualLinkSet = new HashSet<>();
501 }
502 virtualLinkSet.remove(virtualLink);
503
504 VirtualLink newVirtualLink = DefaultVirtualLink.builder()
505 .networkId(virtualLink.networkId())
506 .src(virtualLink.src())
507 .dst(virtualLink.dst())
508 .tunnelId(tunnelId)
Brian Stanke612cebf2016-05-02 10:21:33 -0400509 .state(state)
Brian Stanke9a108972016-04-11 15:25:17 -0400510 .build();
511
512 virtualLinkSet.add(newVirtualLink);
513 networkIdVirtualLinkSetMap.put(newVirtualLink.networkId(), virtualLinkSet);
514 }
515
516 @Override
517 public VirtualLink removeLink(NetworkId networkId, ConnectPoint src, ConnectPoint dst) {
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500518 checkState(networkExists(networkId), "The network has not been added.");
Brian Stanke5df14472016-03-11 19:34:38 -0500519
Brian Stanke9a108972016-04-11 15:25:17 -0400520 final VirtualLink virtualLink = getLink(networkId, src, dst);
521 if (virtualLink == null) {
522 return null;
523 }
Brian Stanke5df14472016-03-11 19:34:38 -0500524 Set<VirtualLink> virtualLinkSet = new HashSet<>();
Brian Stanke9a108972016-04-11 15:25:17 -0400525 virtualLinkSet.add(virtualLink);
Brian Stanke5df14472016-03-11 19:34:38 -0500526
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500527 if (virtualLinkSet != null) {
528 networkIdVirtualLinkSetMap.compute(networkId, (id, existingVirtualLinks) -> {
529 if (existingVirtualLinks == null || existingVirtualLinks.isEmpty()) {
HIGUCHI Yutac0f50452016-05-13 19:26:05 -0700530 return new HashSet<>();
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500531 } else {
HIGUCHI Yutac0f50452016-05-13 19:26:05 -0700532 return new HashSet<>(Sets.difference(existingVirtualLinks, virtualLinkSet));
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500533 }
534 });
535 }
Brian Stanke9a108972016-04-11 15:25:17 -0400536 return virtualLink;
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700537 }
538
539 @Override
Yoonseon Han6c603892016-09-01 11:52:21 -0700540 public VirtualPort addPort(NetworkId networkId, DeviceId deviceId,
541 PortNumber portNumber, ConnectPoint realizedBy) {
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500542 checkState(networkExists(networkId), "The network has not been added.");
543 Set<VirtualPort> virtualPortSet = networkIdVirtualPortSetMap.get(networkId);
Yoonseon Han6c603892016-09-01 11:52:21 -0700544
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500545 if (virtualPortSet == null) {
546 virtualPortSet = new HashSet<>();
547 }
Yoonseon Han6c603892016-09-01 11:52:21 -0700548
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500549 Device device = deviceIdVirtualDeviceMap.get(deviceId);
550 checkNotNull(device, "The device has not been created for deviceId: " + deviceId);
Yoonseon Han6c603892016-09-01 11:52:21 -0700551
552 boolean exist = virtualPortSet.stream().anyMatch(
553 p -> p.element().id().equals(deviceId) &&
554 p.number().equals(portNumber));
555 checkState(!exist, "The requested Port Number is already in use");
556
557 VirtualPort virtualPort = new DefaultVirtualPort(networkId, device,
558 portNumber, realizedBy);
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500559 virtualPortSet.add(virtualPort);
560 networkIdVirtualPortSetMap.put(networkId, virtualPortSet);
561 return virtualPort;
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700562 }
563
564 @Override
Yoonseon Han6c603892016-09-01 11:52:21 -0700565 public void bindPort(NetworkId networkId, DeviceId deviceId,
566 PortNumber portNumber, ConnectPoint realizedBy) {
567
568 Set<VirtualPort> virtualPortSet = networkIdVirtualPortSetMap
569 .get(networkId);
570
571 VirtualPort vPort = virtualPortSet.stream().filter(
572 p -> p.element().id().equals(deviceId) &&
573 p.number().equals(portNumber)).findFirst().get();
574 checkNotNull(vPort, "The virtual port has not been added.");
575
576 Device device = deviceIdVirtualDeviceMap.get(deviceId);
577 checkNotNull(device, "The device has not been created for deviceId: "
578 + deviceId);
579
580 virtualPortSet.remove(vPort);
581 vPort = new DefaultVirtualPort(networkId, device, portNumber, realizedBy);
582 virtualPortSet.add(vPort);
583 networkIdVirtualPortSetMap.put(networkId, virtualPortSet);
584 }
585
586 @Override
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700587 public void removePort(NetworkId networkId, DeviceId deviceId, PortNumber portNumber) {
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500588 checkState(networkExists(networkId), "The network has not been added.");
Brian Stanke5df14472016-03-11 19:34:38 -0500589
590 Set<VirtualPort> virtualPortSet = new HashSet<>();
591 networkIdVirtualPortSetMap.get(networkId).forEach(port -> {
592 if (port.element().id().equals(deviceId) && port.number().equals(portNumber)) {
593 virtualPortSet.add(port);
594 }
595 });
596
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500597 if (virtualPortSet != null) {
598 networkIdVirtualPortSetMap.compute(networkId, (id, existingVirtualPorts) -> {
599 if (existingVirtualPorts == null || existingVirtualPorts.isEmpty()) {
HIGUCHI Yutac0f50452016-05-13 19:26:05 -0700600 return new HashSet<>();
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500601 } else {
HIGUCHI Yutac0f50452016-05-13 19:26:05 -0700602 return new HashSet<>(Sets.difference(existingVirtualPorts, virtualPortSet));
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500603 }
604 });
605 }
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700606 }
607
608 @Override
609 public Set<VirtualNetwork> getNetworks(TenantId tenantId) {
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500610 Set<NetworkId> networkIdSet = tenantIdNetworkIdSetMap.get(tenantId);
611 Set<VirtualNetwork> virtualNetworkSet = new HashSet<>();
612 if (networkIdSet != null) {
613 networkIdSet.forEach(networkId -> virtualNetworkSet.add(networkIdVirtualNetworkMap.get(networkId)));
614 }
615 return ImmutableSet.copyOf(virtualNetworkSet);
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700616 }
617
618 @Override
Brian Stanke86914282016-05-25 15:36:50 -0400619 public VirtualNetwork getNetwork(NetworkId networkId) {
620 return networkIdVirtualNetworkMap.get(networkId);
621 }
622
623 @Override
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700624 public Set<VirtualDevice> getDevices(NetworkId networkId) {
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500625 checkState(networkExists(networkId), "The network has not been added.");
626 Set<DeviceId> deviceIdSet = networkIdDeviceIdSetMap.get(networkId);
627 Set<VirtualDevice> virtualDeviceSet = new HashSet<>();
628 if (deviceIdSet != null) {
629 deviceIdSet.forEach(deviceId -> virtualDeviceSet.add(deviceIdVirtualDeviceMap.get(deviceId)));
630 }
631 return ImmutableSet.copyOf(virtualDeviceSet);
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700632 }
633
634 @Override
Brian Stanke7a81b532016-06-14 15:43:51 -0400635 public Set<VirtualHost> getHosts(NetworkId networkId) {
636 checkState(networkExists(networkId), "The network has not been added.");
637 Set<HostId> hostIdSet = networkIdHostIdSetMap.get(networkId);
638 Set<VirtualHost> virtualHostSet = new HashSet<>();
639 if (hostIdSet != null) {
640 hostIdSet.forEach(hostId -> virtualHostSet.add(hostIdVirtualHostMap.get(hostId)));
641 }
642 return ImmutableSet.copyOf(virtualHostSet);
643 }
644
645 @Override
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700646 public Set<VirtualLink> getLinks(NetworkId networkId) {
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500647 checkState(networkExists(networkId), "The network has not been added.");
Brian Stanke5df14472016-03-11 19:34:38 -0500648 Set<VirtualLink> virtualLinkSet = networkIdVirtualLinkSetMap.get(networkId);
649 if (virtualLinkSet == null) {
650 virtualLinkSet = new HashSet<>();
651 }
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500652 return ImmutableSet.copyOf(virtualLinkSet);
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700653 }
654
Brian Stanke612cebf2016-05-02 10:21:33 -0400655 @Override
656 public VirtualLink getLink(NetworkId networkId, ConnectPoint src, ConnectPoint dst) {
Brian Stanke9a108972016-04-11 15:25:17 -0400657 Set<VirtualLink> virtualLinkSet = networkIdVirtualLinkSetMap.get(networkId);
658 if (virtualLinkSet == null) {
659 return null;
660 }
661
662 VirtualLink virtualLink = null;
663 for (VirtualLink link : virtualLinkSet) {
664 if (link.src().equals(src) && link.dst().equals(dst)) {
665 virtualLink = link;
666 break;
667 }
668 }
669 return virtualLink;
670 }
671
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700672 @Override
673 public Set<VirtualPort> getPorts(NetworkId networkId, DeviceId deviceId) {
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500674 checkState(networkExists(networkId), "The network has not been added.");
Brian Stanke5df14472016-03-11 19:34:38 -0500675 Set<VirtualPort> virtualPortSet = networkIdVirtualPortSetMap.get(networkId);
676 if (virtualPortSet == null) {
677 virtualPortSet = new HashSet<>();
678 }
679
Brian Stanke612cebf2016-05-02 10:21:33 -0400680 if (deviceId == null) {
681 return ImmutableSet.copyOf(virtualPortSet);
682 }
683
Brian Stanke5df14472016-03-11 19:34:38 -0500684 Set<VirtualPort> portSet = new HashSet<>();
685 virtualPortSet.forEach(virtualPort -> {
686 if (virtualPort.element().id().equals(deviceId)) {
687 portSet.add(virtualPort);
688 }
689 });
690 return ImmutableSet.copyOf(portSet);
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500691 }
692
Brian Stanke11f6d532016-07-05 16:17:59 -0400693 @Override
694 public synchronized void addOrUpdateIntent(Intent intent, IntentState state) {
695 checkNotNull(intent, "Intent cannot be null");
696 IntentData intentData = removeIntent(intent.key());
697 if (intentData == null) {
698 intentData = new IntentData(intent, state, new WallClockTimestamp(System.currentTimeMillis()));
699 } else {
700 intentData = new IntentData(intent, state, intentData.version());
701 }
702 intentKeyIntentDataMap.put(intent.key(), intentData);
703 }
704
705 @Override
706 public IntentData removeIntent(Key intentKey) {
707 checkNotNull(intentKey, "Intent key cannot be null");
708 return intentKeyIntentDataMap.remove(intentKey);
709 }
710
711 @Override
712 public void addTunnelId(Intent intent, TunnelId tunnelId) {
713 // Add the tunnelId to the intent key set map
714 Set<TunnelId> tunnelIdSet = intentKeyTunnelIdSetMap.remove(intent.key());
715 if (tunnelIdSet == null) {
716 tunnelIdSet = new HashSet<>();
717 }
718 tunnelIdSet.add(tunnelId);
719 intentKeyTunnelIdSetMap.put(intent.key(), tunnelIdSet);
720 }
721
722 @Override
723 public Set<TunnelId> getTunnelIds(Intent intent) {
724 Set<TunnelId> tunnelIdSet = intentKeyTunnelIdSetMap.get(intent.key());
725 return tunnelIdSet == null ? new HashSet<TunnelId>() : ImmutableSet.copyOf(tunnelIdSet);
726 }
727
728 @Override
729 public void removeTunnelId(Intent intent, TunnelId tunnelId) {
730 Set<TunnelId> tunnelIdSet = new HashSet<>();
731 intentKeyTunnelIdSetMap.get(intent.key()).forEach(tunnelId1 -> {
732 if (tunnelId1.equals(tunnelId)) {
733 tunnelIdSet.add(tunnelId);
734 }
735 });
736
737 if (!tunnelIdSet.isEmpty()) {
738 intentKeyTunnelIdSetMap.compute(intent.key(), (key, existingTunnelIds) -> {
739 if (existingTunnelIds == null || existingTunnelIds.isEmpty()) {
740 return new HashSet<>();
741 } else {
742 return new HashSet<>(Sets.difference(existingTunnelIds, tunnelIdSet));
743 }
744 });
745 }
746 }
747
748 @Override
749 public Set<Intent> getIntents() {
750 Set<Intent> intents = new HashSet<>();
751 intentKeyIntentDataMap.values().forEach(intentData -> intents.add(intentData.intent()));
752 return ImmutableSet.copyOf(intents);
753 }
754
755 @Override
756 public Intent getIntent(Key key) {
757 IntentData intentData = intentKeyIntentDataMap.get(key);
758 return intentData == null ? null : intentData.intent();
759 }
760
761 @Override
762 public Set<IntentData> getIntentData() {
763 return ImmutableSet.copyOf(intentKeyIntentDataMap.values());
764 }
765
766 @Override
767 public IntentData getIntentData(Key key) {
768 IntentData intentData = intentKeyIntentDataMap.get(key);
769 return intentData == null ? null : new IntentData(intentData);
770 }
771
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500772 /**
773 * Listener class to map listener set events to the virtual network events.
774 */
775 private class InternalSetListener implements SetEventListener<TenantId> {
776 @Override
777 public void event(SetEvent<TenantId> event) {
778 VirtualNetworkEvent.Type type = null;
779 switch (event.type()) {
780 case ADD:
781 type = VirtualNetworkEvent.Type.TENANT_REGISTERED;
782 break;
783 case REMOVE:
784 type = VirtualNetworkEvent.Type.TENANT_UNREGISTERED;
785 break;
786 default:
787 log.error("Unsupported event type: " + event.type());
788 }
789 notifyDelegate(new VirtualNetworkEvent(type, null));
790 }
791 }
792
793 /**
794 * Listener class to map listener map events to the virtual network events.
795 */
Claudine Chiu945828d2016-11-21 12:47:07 -0500796 private class InternalMapListener<K, V> implements MapEventListener<K, V> {
797
798 private final BiFunction<MapEvent.Type, V, VirtualNetworkEvent> createEvent;
799
800 InternalMapListener(BiFunction<MapEvent.Type, V, VirtualNetworkEvent> createEvent) {
801 this.createEvent = createEvent;
802 }
803
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500804 @Override
Claudine Chiu945828d2016-11-21 12:47:07 -0500805 public void event(MapEvent<K, V> event) {
806 checkNotNull(event.key());
807 VirtualNetworkEvent vnetEvent = null;
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500808 switch (event.type()) {
809 case INSERT:
Claudine Chiu945828d2016-11-21 12:47:07 -0500810 vnetEvent = createEvent.apply(event.type(), event.newValue().value());
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500811 break;
812 case UPDATE:
813 if ((event.oldValue().value() != null) && (event.newValue().value() == null)) {
Claudine Chiu945828d2016-11-21 12:47:07 -0500814 vnetEvent = createEvent.apply(MapEvent.Type.REMOVE, event.oldValue().value());
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500815 } else {
Claudine Chiu945828d2016-11-21 12:47:07 -0500816 vnetEvent = createEvent.apply(event.type(), event.newValue().value());
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500817 }
818 break;
819 case REMOVE:
Claudine Chiu945828d2016-11-21 12:47:07 -0500820 if (event.oldValue() != null) {
821 vnetEvent = createEvent.apply(event.type(), event.oldValue().value());
822 }
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500823 break;
824 default:
825 log.error("Unsupported event type: " + event.type());
826 }
Claudine Chiu945828d2016-11-21 12:47:07 -0500827 if (vnetEvent != null) {
828 notifyDelegate(vnetEvent);
829 }
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500830 }
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700831 }
832}