blob: 6c06968af026d77b84bf6ca2a9592ace5cf9a487 [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 Stanke7a81b532016-06-14 15:43:51 -040025import org.onlab.packet.IpAddress;
26import org.onlab.packet.MacAddress;
27import org.onlab.packet.VlanId;
Thomas Vachuska33979fd2015-07-31 11:41:14 -070028import org.onosproject.incubator.net.tunnel.TunnelId;
29import org.onosproject.incubator.net.virtual.NetworkId;
30import org.onosproject.incubator.net.virtual.TenantId;
31import org.onosproject.incubator.net.virtual.VirtualDevice;
Brian Stanke7a81b532016-06-14 15:43:51 -040032import org.onosproject.incubator.net.virtual.VirtualHost;
Thomas Vachuska33979fd2015-07-31 11:41:14 -070033import org.onosproject.incubator.net.virtual.VirtualLink;
34import org.onosproject.incubator.net.virtual.VirtualNetwork;
35import org.onosproject.incubator.net.virtual.VirtualNetworkAdminService;
36import org.onosproject.incubator.net.virtual.VirtualNetworkEvent;
37import org.onosproject.incubator.net.virtual.VirtualNetworkListener;
Thomas Vachuska3d62fd72015-09-25 14:58:13 -070038import org.onosproject.incubator.net.virtual.VirtualNetworkProvider;
39import org.onosproject.incubator.net.virtual.VirtualNetworkProviderRegistry;
40import org.onosproject.incubator.net.virtual.VirtualNetworkProviderService;
Thomas Vachuska33979fd2015-07-31 11:41:14 -070041import org.onosproject.incubator.net.virtual.VirtualNetworkService;
42import org.onosproject.incubator.net.virtual.VirtualNetworkStore;
43import org.onosproject.incubator.net.virtual.VirtualNetworkStoreDelegate;
44import org.onosproject.incubator.net.virtual.VirtualPort;
45import org.onosproject.net.ConnectPoint;
46import org.onosproject.net.DeviceId;
Brian Stanke7a81b532016-06-14 15:43:51 -040047import org.onosproject.net.HostId;
48import org.onosproject.net.HostLocation;
Brian Stanke612cebf2016-05-02 10:21:33 -040049import org.onosproject.net.Link;
Thomas Vachuska33979fd2015-07-31 11:41:14 -070050import org.onosproject.net.Port;
51import org.onosproject.net.PortNumber;
Brian Stanke86914282016-05-25 15:36:50 -040052import org.onosproject.net.device.DeviceService;
53import org.onosproject.net.link.LinkService;
Thomas Vachuska3d62fd72015-09-25 14:58:13 -070054import org.onosproject.net.provider.AbstractListenerProviderRegistry;
55import org.onosproject.net.provider.AbstractProviderService;
Brian Stanke8e9f8d12016-06-08 14:48:33 -040056import org.onosproject.net.topology.TopologyService;
Thomas Vachuska33979fd2015-07-31 11:41:14 -070057import org.slf4j.Logger;
58import org.slf4j.LoggerFactory;
59
Brian Stanke86914282016-05-25 15:36:50 -040060import java.util.Map;
Thomas Vachuska33979fd2015-07-31 11:41:14 -070061import java.util.Set;
62
63import static com.google.common.base.Preconditions.checkNotNull;
64
65/**
66 * Implementation of the virtual network service.
67 */
68@Component(immediate = true)
69@Service
70public class VirtualNetworkManager
Thomas Vachuska3d62fd72015-09-25 14:58:13 -070071 extends AbstractListenerProviderRegistry<VirtualNetworkEvent, VirtualNetworkListener,
Brian Stanke0e5c94e2016-03-08 11:20:04 -050072 VirtualNetworkProvider, VirtualNetworkProviderService>
Thomas Vachuska3d62fd72015-09-25 14:58:13 -070073 implements VirtualNetworkService, VirtualNetworkAdminService, VirtualNetworkProviderRegistry {
Thomas Vachuska33979fd2015-07-31 11:41:14 -070074
75 private final Logger log = LoggerFactory.getLogger(getClass());
76
77 private static final String TENANT_NULL = "Tenant ID cannot be null";
78 private static final String NETWORK_NULL = "Network ID cannot be null";
79 private static final String DEVICE_NULL = "Device ID cannot be null";
80 private static final String LINK_POINT_NULL = "Link end-point cannot be null";
Brian Stanke9a108972016-04-11 15:25:17 -040081 private static final String VIRTUAL_LINK_NULL = "Virtual Link cannot be null";
Thomas Vachuska33979fd2015-07-31 11:41:14 -070082
83 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
84 protected VirtualNetworkStore store;
85
Brian Stanke0e5c94e2016-03-08 11:20:04 -050086 private VirtualNetworkStoreDelegate delegate = this::post;
Thomas Vachuska33979fd2015-07-31 11:41:14 -070087
Thomas Vachuska3d62fd72015-09-25 14:58:13 -070088 // TODO: figure out how to coordinate "implementation" of a virtual network in a cluster
Thomas Vachuska33979fd2015-07-31 11:41:14 -070089
90 @Activate
91 protected void activate() {
92 store.setDelegate(delegate);
Brian Stanke0e5c94e2016-03-08 11:20:04 -050093 eventDispatcher.addSink(VirtualNetworkEvent.class, listenerRegistry);
94
Thomas Vachuska33979fd2015-07-31 11:41:14 -070095 log.info("Started");
96 }
97
98 @Deactivate
99 protected void deactivate() {
100 store.unsetDelegate(delegate);
Brian Stanke0e5c94e2016-03-08 11:20:04 -0500101 eventDispatcher.removeSink(VirtualNetworkEvent.class);
102
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700103 log.info("Stopped");
104 }
105
106 @Override
107 public void registerTenantId(TenantId tenantId) {
108 checkNotNull(tenantId, TENANT_NULL);
109 store.addTenantId(tenantId);
110 }
111
112 @Override
113 public void unregisterTenantId(TenantId tenantId) {
114 checkNotNull(tenantId, TENANT_NULL);
115 store.removeTenantId(tenantId);
116 }
117
118 @Override
119 public Set<TenantId> getTenantIds() {
120 return store.getTenantIds();
121 }
122
123 @Override
124 public VirtualNetwork createVirtualNetwork(TenantId tenantId) {
125 checkNotNull(tenantId, TENANT_NULL);
126 return store.addNetwork(tenantId);
127 }
128
129 @Override
130 public void removeVirtualNetwork(NetworkId networkId) {
131 checkNotNull(networkId, NETWORK_NULL);
132 store.removeNetwork(networkId);
133 }
134
135 @Override
136 public VirtualDevice createVirtualDevice(NetworkId networkId, DeviceId deviceId) {
137 checkNotNull(networkId, NETWORK_NULL);
138 checkNotNull(deviceId, DEVICE_NULL);
139 return store.addDevice(networkId, deviceId);
140 }
141
142 @Override
143 public void removeVirtualDevice(NetworkId networkId, DeviceId deviceId) {
144 checkNotNull(networkId, NETWORK_NULL);
145 checkNotNull(deviceId, DEVICE_NULL);
146 store.removeDevice(networkId, deviceId);
147 }
148
149 @Override
Brian Stanke7a81b532016-06-14 15:43:51 -0400150 public VirtualHost createVirtualHost(NetworkId networkId, HostId hostId, MacAddress mac,
151 VlanId vlan, HostLocation location, Set<IpAddress> ips) {
152 checkNotNull(networkId, NETWORK_NULL);
153 checkNotNull(hostId, DEVICE_NULL);
154 return store.addHost(networkId, hostId, mac, vlan, location, ips);
155 }
156
157 @Override
158 public void removeVirtualHost(NetworkId networkId, HostId hostId) {
159 checkNotNull(networkId, NETWORK_NULL);
160 checkNotNull(hostId, DEVICE_NULL);
161 store.removeHost(networkId, hostId);
162 }
163
164 @Override
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700165 public VirtualLink createVirtualLink(NetworkId networkId,
Brian Stanke9a108972016-04-11 15:25:17 -0400166 ConnectPoint src, ConnectPoint dst) {
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700167 checkNotNull(networkId, NETWORK_NULL);
168 checkNotNull(src, LINK_POINT_NULL);
169 checkNotNull(dst, LINK_POINT_NULL);
Brian Stanke612cebf2016-05-02 10:21:33 -0400170 VirtualLink virtualLink = store.addLink(networkId, src, dst, Link.State.INACTIVE, null);
Brian Stanke9a108972016-04-11 15:25:17 -0400171 checkNotNull(virtualLink, VIRTUAL_LINK_NULL);
172
173 if (virtualLink.providerId() != null) {
174 VirtualNetworkProvider provider = getProvider(virtualLink.providerId());
175 if (provider != null) {
176 TunnelId tunnelId = provider.createTunnel(networkId, mapVirtualToPhysicalPort(networkId, src),
177 mapVirtualToPhysicalPort(networkId, dst));
Brian Stanke612cebf2016-05-02 10:21:33 -0400178 store.updateLink(virtualLink, tunnelId, Link.State.INACTIVE);
Brian Stanke9a108972016-04-11 15:25:17 -0400179 }
180 }
181 return virtualLink;
182 }
183
184 /**
185 * Maps the virtual connect point to a physical connect point.
186 *
187 * @param networkId network identifier
188 * @param virtualCp virtual connect point
189 * @return physical connect point
190 */
191 private ConnectPoint mapVirtualToPhysicalPort(NetworkId networkId,
192 ConnectPoint virtualCp) {
193 Set<VirtualPort> ports = store.getPorts(networkId, virtualCp.deviceId());
194 for (VirtualPort port : ports) {
195 if (port.element().id().equals(virtualCp.elementId()) &&
196 port.number().equals(virtualCp.port())) {
197 return new ConnectPoint(port.realizedBy().element().id(), port.realizedBy().number());
198 }
199 }
200 return null;
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700201 }
202
Brian Stanke612cebf2016-05-02 10:21:33 -0400203 /**
204 * Maps the physical connect point to a virtual connect point.
205 *
206 * @param networkId network identifier
207 * @param physicalCp physical connect point
208 * @return virtual connect point
209 */
210 private ConnectPoint mapPhysicalToVirtualToPort(NetworkId networkId,
211 ConnectPoint physicalCp) {
212 Set<VirtualPort> ports = store.getPorts(networkId, null);
213 for (VirtualPort port : ports) {
214 if (port.realizedBy().element().id().equals(physicalCp.elementId()) &&
215 port.realizedBy().number().equals(physicalCp.port())) {
216 return new ConnectPoint(port.element().id(), port.number());
217 }
218 }
219 return null;
220 }
221
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700222 @Override
223 public void removeVirtualLink(NetworkId networkId, ConnectPoint src, ConnectPoint dst) {
224 checkNotNull(networkId, NETWORK_NULL);
225 checkNotNull(src, LINK_POINT_NULL);
226 checkNotNull(dst, LINK_POINT_NULL);
Brian Stanke9a108972016-04-11 15:25:17 -0400227 VirtualLink virtualLink = store.removeLink(networkId, src, dst);
228
229 if (virtualLink != null && virtualLink.providerId() != null) {
230 VirtualNetworkProvider provider = getProvider(virtualLink.providerId());
231 if (provider != null) {
232 provider.destroyTunnel(networkId, virtualLink.tunnelId());
233 }
234 }
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700235 }
236
237 @Override
238 public VirtualPort createVirtualPort(NetworkId networkId, DeviceId deviceId,
239 PortNumber portNumber, Port realizedBy) {
240 checkNotNull(networkId, NETWORK_NULL);
241 checkNotNull(deviceId, DEVICE_NULL);
242 checkNotNull(portNumber, "Port description cannot be null");
243 return store.addPort(networkId, deviceId, portNumber, realizedBy);
244 }
245
246 @Override
247 public void removeVirtualPort(NetworkId networkId, DeviceId deviceId, PortNumber portNumber) {
248 checkNotNull(networkId, NETWORK_NULL);
249 checkNotNull(deviceId, DEVICE_NULL);
250 checkNotNull(portNumber, "Port number cannot be null");
251 store.removePort(networkId, deviceId, portNumber);
252 }
253
254 @Override
255 public Set<VirtualNetwork> getVirtualNetworks(TenantId tenantId) {
256 checkNotNull(tenantId, TENANT_NULL);
257 return store.getNetworks(tenantId);
258 }
259
Brian Stanke86914282016-05-25 15:36:50 -0400260 private VirtualNetwork getVirtualNetwork(NetworkId networkId) {
261 checkNotNull(networkId, NETWORK_NULL);
262 return store.getNetwork(networkId);
263 }
264
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700265 @Override
266 public Set<VirtualDevice> getVirtualDevices(NetworkId networkId) {
267 checkNotNull(networkId, NETWORK_NULL);
268 return store.getDevices(networkId);
269 }
270
271 @Override
Brian Stanke7a81b532016-06-14 15:43:51 -0400272 public Set<VirtualHost> getVirtualHosts(NetworkId networkId) {
273 checkNotNull(networkId, NETWORK_NULL);
274 return store.getHosts(networkId);
275 }
276
277 @Override
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700278 public Set<VirtualLink> getVirtualLinks(NetworkId networkId) {
279 checkNotNull(networkId, NETWORK_NULL);
280 return store.getLinks(networkId);
281 }
282
283 @Override
284 public Set<VirtualPort> getVirtualPorts(NetworkId networkId, DeviceId deviceId) {
285 checkNotNull(networkId, NETWORK_NULL);
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700286 return store.getPorts(networkId, deviceId);
287 }
288
Brian Stanke86914282016-05-25 15:36:50 -0400289 private final Map<ServiceKey, VnetService> networkServices = Maps.newConcurrentMap();
290
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700291 @Override
292 public <T> T get(NetworkId networkId, Class<T> serviceClass) {
293 checkNotNull(networkId, NETWORK_NULL);
Brian Stanke86914282016-05-25 15:36:50 -0400294 ServiceKey serviceKey = networkServiceKey(networkId, serviceClass);
295 VnetService service = lookup(serviceKey);
296 if (service == null) {
297 service = create(serviceKey);
298 }
299 return (T) service;
300 }
301
302 private VnetService lookup(ServiceKey serviceKey) {
303 return networkServices.get(serviceKey);
304 }
305
306 private <T> ServiceKey networkServiceKey(NetworkId networkId, Class<T> serviceClass) {
307 return new ServiceKey(networkId, serviceClass);
308 }
309
310
311 private VnetService create(ServiceKey serviceKey) {
312 VirtualNetwork network = getVirtualNetwork(serviceKey.networkId());
313 VnetService service;
314 if (serviceKey.serviceClass.equals(DeviceService.class)) {
315 service = new VirtualNetworkDeviceService(this, network);
316 } else if (serviceKey.serviceClass.equals(LinkService.class)) {
317 service = new VirtualNetworkLinkService(this, network);
Brian Stanke8e9f8d12016-06-08 14:48:33 -0400318 } else if (serviceKey.serviceClass.equals(TopologyService.class)) {
319 service = new VirtualNetworkTopologyService(this, network);
Brian Stanke86914282016-05-25 15:36:50 -0400320 } else {
321 return null;
322 }
323 networkServices.put(serviceKey, service);
324 return service;
325 }
326
327 private class ServiceKey {
328 final NetworkId networkId;
329 final Class serviceClass;
330
331 public ServiceKey(NetworkId networkId, Class serviceClass) {
332 checkNotNull(networkId, NETWORK_NULL);
333 this.networkId = networkId;
334 this.serviceClass = serviceClass;
335 }
336
337 public NetworkId networkId() {
338 return networkId;
339 }
340
341 public Class serviceClass() {
342 return serviceClass;
343 }
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700344 }
345
Thomas Vachuska3d62fd72015-09-25 14:58:13 -0700346 @Override
347 protected VirtualNetworkProviderService createProviderService(VirtualNetworkProvider provider) {
348 return new InternalVirtualNetworkProviderService(provider);
349 }
350
351 // Service issued to registered virtual network providers so that they
352 // can interact with the core.
353 private class InternalVirtualNetworkProviderService
354 extends AbstractProviderService<VirtualNetworkProvider>
355 implements VirtualNetworkProviderService {
356 InternalVirtualNetworkProviderService(VirtualNetworkProvider provider) {
357 super(provider);
358 }
Brian Stanke4d579882016-04-22 13:28:46 -0400359
360 @Override
Brian Stanke612cebf2016-05-02 10:21:33 -0400361 public void tunnelUp(NetworkId networkId, ConnectPoint src, ConnectPoint dst, TunnelId tunnelId) {
Brian Stanke4d579882016-04-22 13:28:46 -0400362
Brian Stanke612cebf2016-05-02 10:21:33 -0400363 ConnectPoint srcVirtualCp = mapPhysicalToVirtualToPort(networkId, src);
364 ConnectPoint dstVirtualCp = mapPhysicalToVirtualToPort(networkId, dst);
365 if ((srcVirtualCp == null) || (dstVirtualCp == null)) {
366 log.error("Src or dst virtual connection point was not found.");
367 }
368
369 VirtualLink virtualLink = store.getLink(networkId, srcVirtualCp, dstVirtualCp);
370 if (virtualLink != null) {
371 store.updateLink(virtualLink, tunnelId, Link.State.ACTIVE);
372 }
Brian Stanke4d579882016-04-22 13:28:46 -0400373 }
374
375 @Override
Brian Stanke612cebf2016-05-02 10:21:33 -0400376 public void tunnelDown(NetworkId networkId, ConnectPoint src, ConnectPoint dst, TunnelId tunnelId) {
377 ConnectPoint srcVirtualCp = mapPhysicalToVirtualToPort(networkId, src);
378 ConnectPoint dstVirtualCp = mapPhysicalToVirtualToPort(networkId, dst);
379 if ((srcVirtualCp == null) || (dstVirtualCp == null)) {
380 log.error("Src or dst virtual connection point was not found.");
381 }
Brian Stanke4d579882016-04-22 13:28:46 -0400382
Brian Stanke612cebf2016-05-02 10:21:33 -0400383 VirtualLink virtualLink = store.getLink(networkId, srcVirtualCp, dstVirtualCp);
384 if (virtualLink != null) {
385 store.updateLink(virtualLink, tunnelId, Link.State.INACTIVE);
386 }
Brian Stanke4d579882016-04-22 13:28:46 -0400387 }
Thomas Vachuska3d62fd72015-09-25 14:58:13 -0700388 }
389
Thomas Vachuska33979fd2015-07-31 11:41:14 -0700390}