blob: f26465826affe2a1bc557b080c8cd775b69cecd4 [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.net.virtual.impl;
17
Brian Stanke86914282016-05-25 15:36:50 -040018import com.google.common.collect.Maps;
Thomas Vachuska33979fd2015-07-31 11:41:14 -070019import org.apache.felix.scr.annotations.Activate;
20import org.apache.felix.scr.annotations.Component;
21import org.apache.felix.scr.annotations.Deactivate;
22import org.apache.felix.scr.annotations.Reference;
23import org.apache.felix.scr.annotations.ReferenceCardinality;
24import org.apache.felix.scr.annotations.Service;
Brian Stanke11f6d532016-07-05 16:17:59 -040025import org.onlab.osgi.DefaultServiceDirectory;
Brian Stanke7a81b532016-06-14 15:43:51 -040026import org.onlab.packet.IpAddress;
27import org.onlab.packet.MacAddress;
28import org.onlab.packet.VlanId;
Thomas Vachuska33979fd2015-07-31 11:41:14 -070029import org.onosproject.incubator.net.tunnel.TunnelId;
30import org.onosproject.incubator.net.virtual.NetworkId;
31import org.onosproject.incubator.net.virtual.TenantId;
32import org.onosproject.incubator.net.virtual.VirtualDevice;
Brian Stanke7a81b532016-06-14 15:43:51 -040033import org.onosproject.incubator.net.virtual.VirtualHost;
Thomas Vachuska33979fd2015-07-31 11:41:14 -070034import org.onosproject.incubator.net.virtual.VirtualLink;
35import org.onosproject.incubator.net.virtual.VirtualNetwork;
36import org.onosproject.incubator.net.virtual.VirtualNetworkAdminService;
37import org.onosproject.incubator.net.virtual.VirtualNetworkEvent;
Brian Stanke11f6d532016-07-05 16:17:59 -040038import org.onosproject.incubator.net.virtual.VirtualNetworkIntent;
Thomas Vachuska33979fd2015-07-31 11:41:14 -070039import org.onosproject.incubator.net.virtual.VirtualNetworkListener;
Thomas Vachuska3d62fd72015-09-25 14:58:13 -070040import org.onosproject.incubator.net.virtual.VirtualNetworkProvider;
Thomas Vachuska3d62fd72015-09-25 14:58:13 -070041import org.onosproject.incubator.net.virtual.VirtualNetworkProviderService;
Thomas Vachuska33979fd2015-07-31 11:41:14 -070042import org.onosproject.incubator.net.virtual.VirtualNetworkService;
43import org.onosproject.incubator.net.virtual.VirtualNetworkStore;
44import org.onosproject.incubator.net.virtual.VirtualNetworkStoreDelegate;
45import org.onosproject.incubator.net.virtual.VirtualPort;
46import org.onosproject.net.ConnectPoint;
47import org.onosproject.net.DeviceId;
Brian Stanke7a81b532016-06-14 15:43:51 -040048import org.onosproject.net.HostId;
49import org.onosproject.net.HostLocation;
Brian Stanke612cebf2016-05-02 10:21:33 -040050import org.onosproject.net.Link;
Thomas Vachuska33979fd2015-07-31 11:41:14 -070051import org.onosproject.net.Port;
52import org.onosproject.net.PortNumber;
Brian Stanke86914282016-05-25 15:36:50 -040053import org.onosproject.net.device.DeviceService;
Brian Stanke11f6d532016-07-05 16:17:59 -040054import org.onosproject.net.intent.IntentEvent;
55import org.onosproject.net.intent.IntentListener;
56import org.onosproject.net.intent.IntentService;
57import org.onosproject.net.intent.IntentState;
Brian Stanke86914282016-05-25 15:36:50 -040058import org.onosproject.net.link.LinkService;
Thomas Vachuska3d62fd72015-09-25 14:58:13 -070059import org.onosproject.net.provider.AbstractListenerProviderRegistry;
60import org.onosproject.net.provider.AbstractProviderService;
Brian Stanke8e9f8d12016-06-08 14:48:33 -040061import org.onosproject.net.topology.TopologyService;
Thomas Vachuska33979fd2015-07-31 11:41:14 -070062import org.slf4j.Logger;
63import org.slf4j.LoggerFactory;
64
Brian Stanke86914282016-05-25 15:36:50 -040065import java.util.Map;
Thomas Vachuska33979fd2015-07-31 11:41:14 -070066import java.util.Set;
67
68import static com.google.common.base.Preconditions.checkNotNull;
69
70/**
71 * Implementation of the virtual network service.
72 */
73@Component(immediate = true)
74@Service
75public class VirtualNetworkManager
Thomas Vachuska3d62fd72015-09-25 14:58:13 -070076 extends AbstractListenerProviderRegistry<VirtualNetworkEvent, VirtualNetworkListener,
Brian Stanke0e5c94e2016-03-08 11:20:04 -050077 VirtualNetworkProvider, VirtualNetworkProviderService>
Brian Stanke11f6d532016-07-05 16:17:59 -040078 implements VirtualNetworkService, VirtualNetworkAdminService {
Thomas Vachuska33979fd2015-07-31 11:41:14 -070079
80 private final Logger log = LoggerFactory.getLogger(getClass());
81
82 private static final String TENANT_NULL = "Tenant ID cannot be null";
83 private static final String NETWORK_NULL = "Network ID cannot be null";
84 private static final String DEVICE_NULL = "Device ID cannot be null";
85 private static final String LINK_POINT_NULL = "Link end-point cannot be null";
86
87 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
88 protected VirtualNetworkStore store;
89
Brian Stanke11f6d532016-07-05 16:17:59 -040090 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
91 protected IntentService intentService;
92
93 private final InternalVirtualIntentListener intentListener = new InternalVirtualIntentListener();
94
Brian Stanke0e5c94e2016-03-08 11:20:04 -050095 private VirtualNetworkStoreDelegate delegate = this::post;
Thomas Vachuska33979fd2015-07-31 11:41:14 -070096
Thomas Vachuska3d62fd72015-09-25 14:58:13 -070097 // TODO: figure out how to coordinate "implementation" of a virtual network in a cluster
Thomas Vachuska33979fd2015-07-31 11:41:14 -070098
Brian Stanke11f6d532016-07-05 16:17:59 -040099 /**
100 * Only used for Junit test methods outside of this package.
101 *
102 * @param store virtual network store
103 */
104 public void setStore(VirtualNetworkStore store) {
105 this.store = store;
106 }
107
108 /**
109 * Only used for Junit test methods outside of this package.
110 *
111 * @param intentService intent service
112 */
113
114 public void setIntentService(IntentService intentService) {
115 this.intentService = intentService;
116 }
117
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700118 @Activate
Brian Stanke11f6d532016-07-05 16:17:59 -0400119 public void activate() {
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700120 store.setDelegate(delegate);
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500121 eventDispatcher.addSink(VirtualNetworkEvent.class, listenerRegistry);
Brian Stanke11f6d532016-07-05 16:17:59 -0400122 intentService.addListener(intentListener);
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700123 log.info("Started");
124 }
125
126 @Deactivate
Brian Stanke11f6d532016-07-05 16:17:59 -0400127 public void deactivate() {
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700128 store.unsetDelegate(delegate);
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500129 eventDispatcher.removeSink(VirtualNetworkEvent.class);
Brian Stanke11f6d532016-07-05 16:17:59 -0400130 intentService.removeListener(intentListener);
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700131 log.info("Stopped");
132 }
133
134 @Override
135 public void registerTenantId(TenantId tenantId) {
136 checkNotNull(tenantId, TENANT_NULL);
137 store.addTenantId(tenantId);
138 }
139
140 @Override
141 public void unregisterTenantId(TenantId tenantId) {
142 checkNotNull(tenantId, TENANT_NULL);
143 store.removeTenantId(tenantId);
144 }
145
146 @Override
147 public Set<TenantId> getTenantIds() {
148 return store.getTenantIds();
149 }
150
151 @Override
152 public VirtualNetwork createVirtualNetwork(TenantId tenantId) {
153 checkNotNull(tenantId, TENANT_NULL);
154 return store.addNetwork(tenantId);
155 }
156
157 @Override
158 public void removeVirtualNetwork(NetworkId networkId) {
159 checkNotNull(networkId, NETWORK_NULL);
160 store.removeNetwork(networkId);
161 }
162
163 @Override
164 public VirtualDevice createVirtualDevice(NetworkId networkId, DeviceId deviceId) {
165 checkNotNull(networkId, NETWORK_NULL);
166 checkNotNull(deviceId, DEVICE_NULL);
167 return store.addDevice(networkId, deviceId);
168 }
169
170 @Override
171 public void removeVirtualDevice(NetworkId networkId, DeviceId deviceId) {
172 checkNotNull(networkId, NETWORK_NULL);
173 checkNotNull(deviceId, DEVICE_NULL);
174 store.removeDevice(networkId, deviceId);
175 }
176
177 @Override
Brian Stanke7a81b532016-06-14 15:43:51 -0400178 public VirtualHost createVirtualHost(NetworkId networkId, HostId hostId, MacAddress mac,
179 VlanId vlan, HostLocation location, Set<IpAddress> ips) {
180 checkNotNull(networkId, NETWORK_NULL);
181 checkNotNull(hostId, DEVICE_NULL);
182 return store.addHost(networkId, hostId, mac, vlan, location, ips);
183 }
184
185 @Override
186 public void removeVirtualHost(NetworkId networkId, HostId hostId) {
187 checkNotNull(networkId, NETWORK_NULL);
188 checkNotNull(hostId, DEVICE_NULL);
189 store.removeHost(networkId, hostId);
190 }
191
192 @Override
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700193 public VirtualLink createVirtualLink(NetworkId networkId,
Brian Stanke9a108972016-04-11 15:25:17 -0400194 ConnectPoint src, ConnectPoint dst) {
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700195 checkNotNull(networkId, NETWORK_NULL);
196 checkNotNull(src, LINK_POINT_NULL);
197 checkNotNull(dst, LINK_POINT_NULL);
Brian Stanke11f6d532016-07-05 16:17:59 -0400198 return store.addLink(networkId, src, dst, Link.State.ACTIVE, null);
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700199 }
200
Brian Stanke612cebf2016-05-02 10:21:33 -0400201 /**
202 * Maps the physical connect point to a virtual connect point.
203 *
Brian Stanke11f6d532016-07-05 16:17:59 -0400204 * @param networkId network identifier
Brian Stanke612cebf2016-05-02 10:21:33 -0400205 * @param physicalCp physical connect point
206 * @return virtual connect point
207 */
208 private ConnectPoint mapPhysicalToVirtualToPort(NetworkId networkId,
Brian Stanke11f6d532016-07-05 16:17:59 -0400209 ConnectPoint physicalCp) {
Brian Stanke612cebf2016-05-02 10:21:33 -0400210 Set<VirtualPort> ports = store.getPorts(networkId, null);
211 for (VirtualPort port : ports) {
212 if (port.realizedBy().element().id().equals(physicalCp.elementId()) &&
213 port.realizedBy().number().equals(physicalCp.port())) {
214 return new ConnectPoint(port.element().id(), port.number());
215 }
216 }
217 return null;
218 }
219
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700220 @Override
221 public void removeVirtualLink(NetworkId networkId, ConnectPoint src, ConnectPoint dst) {
222 checkNotNull(networkId, NETWORK_NULL);
223 checkNotNull(src, LINK_POINT_NULL);
224 checkNotNull(dst, LINK_POINT_NULL);
Brian Stanke11f6d532016-07-05 16:17:59 -0400225 store.removeLink(networkId, src, dst);
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700226 }
227
228 @Override
229 public VirtualPort createVirtualPort(NetworkId networkId, DeviceId deviceId,
230 PortNumber portNumber, Port realizedBy) {
231 checkNotNull(networkId, NETWORK_NULL);
232 checkNotNull(deviceId, DEVICE_NULL);
233 checkNotNull(portNumber, "Port description cannot be null");
234 return store.addPort(networkId, deviceId, portNumber, realizedBy);
235 }
236
237 @Override
238 public void removeVirtualPort(NetworkId networkId, DeviceId deviceId, PortNumber portNumber) {
239 checkNotNull(networkId, NETWORK_NULL);
240 checkNotNull(deviceId, DEVICE_NULL);
241 checkNotNull(portNumber, "Port number cannot be null");
242 store.removePort(networkId, deviceId, portNumber);
243 }
244
245 @Override
246 public Set<VirtualNetwork> getVirtualNetworks(TenantId tenantId) {
247 checkNotNull(tenantId, TENANT_NULL);
248 return store.getNetworks(tenantId);
249 }
250
Brian Stanke11f6d532016-07-05 16:17:59 -0400251 /**
252 * Returns the virtual network matching the network identifier.
253 *
254 * @param networkId network identifier
255 * @return virtual network
256 */
Brian Stanke86914282016-05-25 15:36:50 -0400257 private VirtualNetwork getVirtualNetwork(NetworkId networkId) {
258 checkNotNull(networkId, NETWORK_NULL);
259 return store.getNetwork(networkId);
260 }
261
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700262 @Override
263 public Set<VirtualDevice> getVirtualDevices(NetworkId networkId) {
264 checkNotNull(networkId, NETWORK_NULL);
265 return store.getDevices(networkId);
266 }
267
268 @Override
Brian Stanke7a81b532016-06-14 15:43:51 -0400269 public Set<VirtualHost> getVirtualHosts(NetworkId networkId) {
270 checkNotNull(networkId, NETWORK_NULL);
271 return store.getHosts(networkId);
272 }
273
274 @Override
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700275 public Set<VirtualLink> getVirtualLinks(NetworkId networkId) {
276 checkNotNull(networkId, NETWORK_NULL);
277 return store.getLinks(networkId);
278 }
279
280 @Override
281 public Set<VirtualPort> getVirtualPorts(NetworkId networkId, DeviceId deviceId) {
282 checkNotNull(networkId, NETWORK_NULL);
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700283 return store.getPorts(networkId, deviceId);
284 }
285
Brian Stanke86914282016-05-25 15:36:50 -0400286 private final Map<ServiceKey, VnetService> networkServices = Maps.newConcurrentMap();
287
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700288 @Override
289 public <T> T get(NetworkId networkId, Class<T> serviceClass) {
290 checkNotNull(networkId, NETWORK_NULL);
Brian Stanke86914282016-05-25 15:36:50 -0400291 ServiceKey serviceKey = networkServiceKey(networkId, serviceClass);
292 VnetService service = lookup(serviceKey);
293 if (service == null) {
294 service = create(serviceKey);
295 }
296 return (T) service;
297 }
298
Brian Stanke11f6d532016-07-05 16:17:59 -0400299 /**
300 * Returns the Vnet service matching the service key.
301 *
302 * @param serviceKey service key
303 * @return vnet service
304 */
Brian Stanke86914282016-05-25 15:36:50 -0400305 private VnetService lookup(ServiceKey serviceKey) {
306 return networkServices.get(serviceKey);
307 }
308
Brian Stanke11f6d532016-07-05 16:17:59 -0400309 /**
310 * Creates a new service key using the specified network identifier and service class.
311 *
312 * @param networkId network identifier
313 * @param serviceClass service class
314 * @param <T> type of service
315 * @return service key
316 */
Brian Stanke86914282016-05-25 15:36:50 -0400317 private <T> ServiceKey networkServiceKey(NetworkId networkId, Class<T> serviceClass) {
318 return new ServiceKey(networkId, serviceClass);
319 }
320
321
Brian Stanke11f6d532016-07-05 16:17:59 -0400322 /**
323 * Create a new vnet service instance.
324 *
325 * @param serviceKey service key
326 * @return vnet service
327 */
Brian Stanke86914282016-05-25 15:36:50 -0400328 private VnetService create(ServiceKey serviceKey) {
329 VirtualNetwork network = getVirtualNetwork(serviceKey.networkId());
Brian Stanke11f6d532016-07-05 16:17:59 -0400330 checkNotNull(network, NETWORK_NULL);
Brian Stanke86914282016-05-25 15:36:50 -0400331 VnetService service;
332 if (serviceKey.serviceClass.equals(DeviceService.class)) {
333 service = new VirtualNetworkDeviceService(this, network);
334 } else if (serviceKey.serviceClass.equals(LinkService.class)) {
335 service = new VirtualNetworkLinkService(this, network);
Brian Stanke8e9f8d12016-06-08 14:48:33 -0400336 } else if (serviceKey.serviceClass.equals(TopologyService.class)) {
337 service = new VirtualNetworkTopologyService(this, network);
Brian Stanke11f6d532016-07-05 16:17:59 -0400338 } else if (serviceKey.serviceClass.equals(IntentService.class)) {
339 service = new VirtualNetworkIntentService(this, network, new DefaultServiceDirectory());
Brian Stanke86914282016-05-25 15:36:50 -0400340 } else {
341 return null;
342 }
343 networkServices.put(serviceKey, service);
344 return service;
345 }
346
Brian Stanke11f6d532016-07-05 16:17:59 -0400347 /**
348 * Service key class.
349 */
Brian Stanke86914282016-05-25 15:36:50 -0400350 private class ServiceKey {
351 final NetworkId networkId;
352 final Class serviceClass;
353
Brian Stanke11f6d532016-07-05 16:17:59 -0400354 /**
355 * Constructor for service key.
356 *
357 * @param networkId network identifier
358 * @param serviceClass service class
359 */
Brian Stanke86914282016-05-25 15:36:50 -0400360 public ServiceKey(NetworkId networkId, Class serviceClass) {
361 checkNotNull(networkId, NETWORK_NULL);
362 this.networkId = networkId;
363 this.serviceClass = serviceClass;
364 }
365
Brian Stanke11f6d532016-07-05 16:17:59 -0400366 /**
367 * Returns the network identifier.
368 *
369 * @return network identifier
370 */
Brian Stanke86914282016-05-25 15:36:50 -0400371 public NetworkId networkId() {
372 return networkId;
373 }
374
Brian Stanke11f6d532016-07-05 16:17:59 -0400375 /**
376 * Returns the service class.
377 *
378 * @return service class
379 */
Brian Stanke86914282016-05-25 15:36:50 -0400380 public Class serviceClass() {
381 return serviceClass;
382 }
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700383 }
384
Brian Stanke11f6d532016-07-05 16:17:59 -0400385 /**
386 * Internal intent event listener.
387 */
388 private class InternalVirtualIntentListener implements IntentListener {
389 @Override
390 public void event(IntentEvent event) {
391
392 // Ignore intent events that are not relevant.
393 if (!isRelevant(event)) {
394 return;
395 }
396
397 VirtualNetworkIntent intent = (VirtualNetworkIntent) event.subject();
398
399 switch (event.type()) {
400 case INSTALL_REQ:
401 store.addOrUpdateIntent(intent, IntentState.INSTALL_REQ);
402 break;
403 case INSTALLED:
404 store.addOrUpdateIntent(intent, IntentState.INSTALLED);
405 break;
406 case WITHDRAW_REQ:
407 store.addOrUpdateIntent(intent, IntentState.WITHDRAW_REQ);
408 break;
409 case WITHDRAWN:
410 store.addOrUpdateIntent(intent, IntentState.WITHDRAWN);
411 break;
412 case FAILED:
413 store.addOrUpdateIntent(intent, IntentState.FAILED);
414 break;
415 case CORRUPT:
416 store.addOrUpdateIntent(intent, IntentState.CORRUPT);
417 break;
418 case PURGED:
419 store.removeIntent(intent.key());
420 default:
421 break;
422 }
423 }
424
425 @Override
426 public boolean isRelevant(IntentEvent event) {
427 if (event.subject() instanceof VirtualNetworkIntent) {
428 return true;
429 }
430 return false;
431 }
432 }
433
434
Thomas Vachuska3d62fd72015-09-25 14:58:13 -0700435 @Override
436 protected VirtualNetworkProviderService createProviderService(VirtualNetworkProvider provider) {
437 return new InternalVirtualNetworkProviderService(provider);
438 }
439
440 // Service issued to registered virtual network providers so that they
441 // can interact with the core.
442 private class InternalVirtualNetworkProviderService
443 extends AbstractProviderService<VirtualNetworkProvider>
444 implements VirtualNetworkProviderService {
445 InternalVirtualNetworkProviderService(VirtualNetworkProvider provider) {
446 super(provider);
447 }
Brian Stanke4d579882016-04-22 13:28:46 -0400448
449 @Override
Brian Stanke612cebf2016-05-02 10:21:33 -0400450 public void tunnelUp(NetworkId networkId, ConnectPoint src, ConnectPoint dst, TunnelId tunnelId) {
Brian Stanke4d579882016-04-22 13:28:46 -0400451
Brian Stanke612cebf2016-05-02 10:21:33 -0400452 ConnectPoint srcVirtualCp = mapPhysicalToVirtualToPort(networkId, src);
453 ConnectPoint dstVirtualCp = mapPhysicalToVirtualToPort(networkId, dst);
454 if ((srcVirtualCp == null) || (dstVirtualCp == null)) {
455 log.error("Src or dst virtual connection point was not found.");
456 }
457
458 VirtualLink virtualLink = store.getLink(networkId, srcVirtualCp, dstVirtualCp);
459 if (virtualLink != null) {
460 store.updateLink(virtualLink, tunnelId, Link.State.ACTIVE);
461 }
Brian Stanke4d579882016-04-22 13:28:46 -0400462 }
463
464 @Override
Brian Stanke612cebf2016-05-02 10:21:33 -0400465 public void tunnelDown(NetworkId networkId, ConnectPoint src, ConnectPoint dst, TunnelId tunnelId) {
466 ConnectPoint srcVirtualCp = mapPhysicalToVirtualToPort(networkId, src);
467 ConnectPoint dstVirtualCp = mapPhysicalToVirtualToPort(networkId, dst);
468 if ((srcVirtualCp == null) || (dstVirtualCp == null)) {
469 log.error("Src or dst virtual connection point was not found.");
470 }
Brian Stanke4d579882016-04-22 13:28:46 -0400471
Brian Stanke612cebf2016-05-02 10:21:33 -0400472 VirtualLink virtualLink = store.getLink(networkId, srcVirtualCp, dstVirtualCp);
473 if (virtualLink != null) {
474 store.updateLink(virtualLink, tunnelId, Link.State.INACTIVE);
475 }
Brian Stanke4d579882016-04-22 13:28:46 -0400476 }
Thomas Vachuska3d62fd72015-09-25 14:58:13 -0700477 }
478
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700479}