ec9ca3ef75d6797cefebfa7e80f1bfbbd1ffd9c2
[onosfw.git] /
1 /*
2  * Copyright 2015 Open Networking Laboratory
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  */
16 package org.onosproject.vtnrsc.service.impl;
17
18 import static com.google.common.base.Preconditions.checkNotNull;
19 import static org.slf4j.LoggerFactory.getLogger;
20
21 import java.util.HashSet;
22 import java.util.Iterator;
23 import java.util.Set;
24
25 import org.apache.felix.scr.annotations.Activate;
26 import org.apache.felix.scr.annotations.Component;
27 import org.apache.felix.scr.annotations.Deactivate;
28 import org.apache.felix.scr.annotations.Reference;
29 import org.apache.felix.scr.annotations.ReferenceCardinality;
30 import org.apache.felix.scr.annotations.Service;
31 import org.onlab.packet.IpAddress;
32 import org.onlab.packet.MacAddress;
33 import org.onlab.util.KryoNamespace;
34 import org.onosproject.core.CoreService;
35 import org.onosproject.net.Device;
36 import org.onosproject.net.DeviceId;
37 import org.onosproject.net.Host;
38 import org.onosproject.net.HostId;
39 import org.onosproject.net.host.HostEvent;
40 import org.onosproject.net.host.HostListener;
41 import org.onosproject.net.host.HostService;
42 import org.onosproject.net.device.DeviceService;
43 import org.onosproject.store.serializers.KryoNamespaces;
44 import org.onosproject.store.service.EventuallyConsistentMap;
45 import org.onosproject.store.service.LogicalClockService;
46 import org.onosproject.store.service.StorageService;
47 import org.onosproject.vtnrsc.FixedIp;
48 import org.onosproject.vtnrsc.FloatingIp;
49 import org.onosproject.vtnrsc.Router;
50 import org.onosproject.vtnrsc.RouterInterface;
51 import org.onosproject.vtnrsc.SegmentationId;
52 import org.onosproject.vtnrsc.Subnet;
53 import org.onosproject.vtnrsc.SubnetId;
54 import org.onosproject.vtnrsc.TenantId;
55 import org.onosproject.vtnrsc.VirtualPort;
56 import org.onosproject.vtnrsc.VirtualPortId;
57 import org.onosproject.vtnrsc.event.VtnRscEvent;
58 import org.onosproject.vtnrsc.event.VtnRscEventFeedback;
59 import org.onosproject.vtnrsc.event.VtnRscListener;
60 import org.onosproject.vtnrsc.floatingip.FloatingIpEvent;
61 import org.onosproject.vtnrsc.floatingip.FloatingIpListener;
62 import org.onosproject.vtnrsc.floatingip.FloatingIpService;
63 import org.onosproject.vtnrsc.router.RouterEvent;
64 import org.onosproject.vtnrsc.router.RouterListener;
65 import org.onosproject.vtnrsc.router.RouterService;
66 import org.onosproject.vtnrsc.routerinterface.RouterInterfaceEvent;
67 import org.onosproject.vtnrsc.routerinterface.RouterInterfaceListener;
68 import org.onosproject.vtnrsc.routerinterface.RouterInterfaceService;
69 import org.onosproject.vtnrsc.service.VtnRscService;
70 import org.onosproject.vtnrsc.subnet.SubnetService;
71 import org.onosproject.vtnrsc.tenantnetwork.TenantNetworkService;
72 import org.onosproject.vtnrsc.virtualport.VirtualPortService;
73 import org.slf4j.Logger;
74
75 import com.google.common.collect.Sets;
76
77 /**
78  * Provides implementation of the VtnRsc service.
79  */
80 @Component(immediate = true)
81 @Service
82 public class VtnRscManager implements VtnRscService {
83     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
84     protected CoreService coreService;
85     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
86     protected StorageService storageService;
87     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
88     protected LogicalClockService clockService;
89
90     private final Logger log = getLogger(getClass());
91     private final Set<VtnRscListener> listeners = Sets.newCopyOnWriteArraySet();
92     private HostListener hostListener = new InnerHostListener();
93     private FloatingIpListener floatingIpListener = new InnerFloatingIpListener();
94     private RouterListener routerListener = new InnerRouterListener();
95     private RouterInterfaceListener routerInterfaceListener = new InnerRouterInterfaceListener();
96
97     private EventuallyConsistentMap<TenantId, SegmentationId> l3vniMap;
98     private EventuallyConsistentMap<TenantId, Set<DeviceId>> classifierOvsMap;
99     private EventuallyConsistentMap<TenantId, Set<DeviceId>> sffOvsMap;
100
101     private static final String IFACEID = "ifaceid";
102     private static final String RUNNELOPTOPOIC = "tunnel-ops-ids";
103     private static final String LISTENER_NOT_NULL = "listener cannot be null";
104     private static final String EVENT_NOT_NULL = "event cannot be null";
105     private static final String TENANTID_NOT_NULL = "tenantId cannot be null";
106     private static final String DEVICEID_NOT_NULL = "deviceId cannot be null";
107     private static final String OVSMAP_NOT_NULL = "ovsMap cannot be null";
108     private static final String L3VNIMAP = "l3vniMap";
109     private static final String CLASSIFIEROVSMAP = "classifierOvsMap";
110     private static final String SFFOVSMAP = "sffOvsMap";
111
112     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
113     protected RouterService routerService;
114     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
115     protected FloatingIpService floatingIpService;
116     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
117     protected RouterInterfaceService routerInterfaceService;
118     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
119     protected VirtualPortService virtualPortService;
120     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
121     protected HostService hostService;
122     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
123     protected SubnetService subnetService;
124     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
125     protected TenantNetworkService tenantNetworkService;
126     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
127     protected DeviceService deviceService;
128
129     @Activate
130     public void activate() {
131         hostService.addListener(hostListener);
132         floatingIpService.addListener(floatingIpListener);
133         routerService.addListener(routerListener);
134         routerInterfaceService.addListener(routerInterfaceListener);
135
136         KryoNamespace.Builder serializer = KryoNamespace.newBuilder()
137                 .register(KryoNamespaces.API)
138                 .register(TenantId.class, DeviceId.class);
139         l3vniMap = storageService
140                 .<TenantId, SegmentationId>eventuallyConsistentMapBuilder()
141                 .withName(L3VNIMAP).withSerializer(serializer)
142                 .withTimestampProvider((k, v) -> clockService.getTimestamp())
143                 .build();
144
145         classifierOvsMap = storageService
146                 .<TenantId, Set<DeviceId>>eventuallyConsistentMapBuilder()
147                 .withName(CLASSIFIEROVSMAP).withSerializer(serializer)
148                 .withTimestampProvider((k, v) -> clockService.getTimestamp())
149                 .build();
150
151         sffOvsMap = storageService
152                 .<TenantId, Set<DeviceId>>eventuallyConsistentMapBuilder()
153                 .withName(SFFOVSMAP).withSerializer(serializer)
154                 .withTimestampProvider((k, v) -> clockService.getTimestamp())
155                 .build();
156     }
157
158     @Deactivate
159     public void deactivate() {
160         hostService.removeListener(hostListener);
161         floatingIpService.removeListener(floatingIpListener);
162         routerService.removeListener(routerListener);
163         routerInterfaceService.removeListener(routerInterfaceListener);
164         l3vniMap.destroy();
165         classifierOvsMap.destroy();
166         sffOvsMap.destroy();
167         listeners.clear();
168         log.info("Stopped");
169     }
170
171     @Override
172     public void addListener(VtnRscListener listener) {
173         checkNotNull(listener, LISTENER_NOT_NULL);
174         listeners.add(listener);
175     }
176
177     @Override
178     public void removeListener(VtnRscListener listener) {
179         checkNotNull(listener, LISTENER_NOT_NULL);
180         listeners.add(listener);
181     }
182
183     @Override
184     public SegmentationId getL3vni(TenantId tenantId) {
185         checkNotNull(tenantId, "tenantId cannot be null");
186         SegmentationId l3vni = l3vniMap.get(tenantId);
187         if (l3vni == null) {
188             long segmentationId = coreService.getIdGenerator(RUNNELOPTOPOIC)
189                     .getNewId();
190             l3vni = SegmentationId.segmentationId(String
191                     .valueOf(segmentationId));
192             l3vniMap.put(tenantId, l3vni);
193         }
194         return l3vni;
195     }
196
197     private class InnerHostListener implements HostListener {
198
199         @Override
200         public void event(HostEvent event) {
201             checkNotNull(event, EVENT_NOT_NULL);
202             Host host = event.subject();
203             String ifaceId = host.annotations().value(IFACEID);
204             VirtualPortId hPortId = VirtualPortId.portId(ifaceId);
205             TenantId tenantId = virtualPortService.getPort(hPortId).tenantId();
206             DeviceId deviceId = host.location().deviceId();
207             if (HostEvent.Type.HOST_ADDED == event.type()) {
208                 if (isServiceFunction(hPortId)) {
209                     addDeviceIdOfOvsMap(tenantId, deviceId, sffOvsMap);
210                 } else {
211                     addDeviceIdOfOvsMap(tenantId, deviceId, classifierOvsMap);
212                 }
213             } else if (HostEvent.Type.HOST_REMOVED == event.type()) {
214                 if (isLastSFHostOfTenant(host, deviceId, tenantId)) {
215                     removeDeviceIdOfOvsMap(tenantId, deviceId, sffOvsMap);
216                 }
217                 if (isLastClassifierHostOfTenant(host, deviceId, tenantId)) {
218                     removeDeviceIdOfOvsMap(tenantId, deviceId, classifierOvsMap);
219                 }
220             }
221         }
222     }
223
224     private class InnerFloatingIpListener implements FloatingIpListener {
225
226         @Override
227         public void event(FloatingIpEvent event) {
228             checkNotNull(event, EVENT_NOT_NULL);
229             FloatingIp floatingIp = event.subject();
230             if (FloatingIpEvent.Type.FLOATINGIP_PUT == event.type()) {
231                 notifyListeners(new VtnRscEvent(
232                                                 VtnRscEvent.Type.FLOATINGIP_PUT,
233                                                 new VtnRscEventFeedback(
234                                                                         floatingIp)));
235             }
236             if (FloatingIpEvent.Type.FLOATINGIP_DELETE == event.type()) {
237                 notifyListeners(new VtnRscEvent(
238                                                 VtnRscEvent.Type.FLOATINGIP_DELETE,
239                                                 new VtnRscEventFeedback(
240                                                                         floatingIp)));
241             }
242         }
243     }
244
245     private class InnerRouterListener implements RouterListener {
246
247         @Override
248         public void event(RouterEvent event) {
249             checkNotNull(event, EVENT_NOT_NULL);
250             Router router = event.subject();
251             if (RouterEvent.Type.ROUTER_PUT == event.type()) {
252                 notifyListeners(new VtnRscEvent(VtnRscEvent.Type.ROUTER_PUT,
253                                                 new VtnRscEventFeedback(router)));
254             }
255             if (RouterEvent.Type.ROUTER_DELETE == event.type()) {
256                 notifyListeners(new VtnRscEvent(VtnRscEvent.Type.ROUTER_DELETE,
257                                                 new VtnRscEventFeedback(router)));
258             }
259         }
260     }
261
262     private class InnerRouterInterfaceListener
263             implements RouterInterfaceListener {
264
265         @Override
266         public void event(RouterInterfaceEvent event) {
267             checkNotNull(event, EVENT_NOT_NULL);
268             RouterInterface routerInterface = event.subject();
269             if (RouterInterfaceEvent.Type.ROUTER_INTERFACE_PUT == event.type()) {
270                 notifyListeners(new VtnRscEvent(
271                                                 VtnRscEvent.Type.ROUTER_INTERFACE_PUT,
272                                                 new VtnRscEventFeedback(
273                                                                         routerInterface)));
274             }
275             if (RouterInterfaceEvent.Type.ROUTER_INTERFACE_DELETE == event
276                     .type()) {
277                 notifyListeners(new VtnRscEvent(
278                                                 VtnRscEvent.Type.ROUTER_INTERFACE_DELETE,
279                                                 new VtnRscEventFeedback(
280                                                                         routerInterface)));
281             }
282         }
283     }
284
285     @Override
286     public Iterator<Device> getClassifierOfTenant(TenantId tenantId) {
287         checkNotNull(tenantId, TENANTID_NOT_NULL);
288         Set<DeviceId> deviceIdSet = classifierOvsMap.get(tenantId);
289         Set<Device> deviceSet = new HashSet<>();
290         if (deviceIdSet != null) {
291             for (DeviceId deviceId : deviceIdSet) {
292                 deviceSet.add(deviceService.getDevice(deviceId));
293             }
294         }
295         return deviceSet.iterator();
296     }
297
298     @Override
299     public Iterator<Device> getSFFOfTenant(TenantId tenantId) {
300         checkNotNull(tenantId, TENANTID_NOT_NULL);
301         Set<DeviceId> deviceIdSet = sffOvsMap.get(tenantId);
302         Set<Device> deviceSet = new HashSet<>();
303         if (deviceIdSet != null) {
304             for (DeviceId deviceId : deviceIdSet) {
305                 deviceSet.add(deviceService.getDevice(deviceId));
306             }
307         }
308         return deviceSet.iterator();
309     }
310
311     @Override
312     public MacAddress getGatewayMac(HostId hostId) {
313         checkNotNull(hostId, "hostId cannot be null");
314         Host host = hostService.getHost(hostId);
315         String ifaceId = host.annotations().value(IFACEID);
316         VirtualPortId hPortId = VirtualPortId.portId(ifaceId);
317         VirtualPort hPort = virtualPortService.getPort(hPortId);
318         SubnetId subnetId = hPort.fixedIps().iterator().next().subnetId();
319         Subnet subnet = subnetService.getSubnet(subnetId);
320         IpAddress gatewayIp = subnet.gatewayIp();
321         Iterable<VirtualPort> virtualPorts = virtualPortService.getPorts();
322         MacAddress macAddress = null;
323         for (VirtualPort port : virtualPorts) {
324             Set<FixedIp> fixedIpSet = port.fixedIps();
325             for (FixedIp fixedIp : fixedIpSet) {
326                 if (fixedIp.ip().equals(gatewayIp)) {
327                     macAddress = port.macAddress();
328                 }
329             }
330         }
331         return macAddress;
332     }
333
334     @Override
335     public boolean isServiceFunction(VirtualPortId portId) {
336         // TODO Auto-generated method stub
337         return false;
338     }
339
340     @Override
341     public DeviceId getSFToSFFMaping(VirtualPortId portId) {
342         checkNotNull(portId, "portId cannot be null");
343         VirtualPort vmPort = virtualPortService.getPort(portId);
344         Set<Host> hostSet = hostService.getHostsByMac(vmPort.macAddress());
345         for (Host host : hostSet) {
346             if (host.annotations().value(IFACEID).equals(vmPort.portId())) {
347                 return host.location().deviceId();
348             }
349         }
350         return null;
351     }
352
353     /**
354      * Checks whether the last Service Function host of a specific tenant in
355      * this device.
356      *
357      * @param host the host on device
358      * @param deviceId the device identifier
359      * @param tenantId the tenant identifier
360      * @return true or false
361      */
362     private boolean isLastSFHostOfTenant(Host host, DeviceId deviceId,
363                                          TenantId tenantId) {
364         checkNotNull(host, "host cannot be null");
365         checkNotNull(deviceId, DEVICEID_NOT_NULL);
366         checkNotNull(tenantId, TENANTID_NOT_NULL);
367         Set<Host> hostSet = hostService.getConnectedHosts(deviceId);
368         for (Host h : hostSet) {
369             String ifaceId = h.annotations().value(IFACEID);
370             VirtualPortId hPortId = VirtualPortId.portId(ifaceId);
371             if (virtualPortService.getPort(hPortId).tenantId() != tenantId) {
372                 hostSet.remove(h);
373             } else {
374                 if (!isServiceFunction(hPortId)) {
375                     hostSet.remove(h);
376                 }
377             }
378         }
379         if (hostSet.size() == 1 && hostSet.contains(host)) {
380             return true;
381         }
382         return false;
383     }
384
385     /**
386      * Checks whether the last Classifier host of a specific tenant in this
387      * device.
388      *
389      * @param host the host on device
390      * @param deviceId the device identifier
391      * @param tenantId the tenant identifier
392      * @return true or false
393      */
394     private boolean isLastClassifierHostOfTenant(Host host, DeviceId deviceId,
395                                                  TenantId tenantId) {
396         checkNotNull(host, "host cannot be null");
397         checkNotNull(deviceId, DEVICEID_NOT_NULL);
398         checkNotNull(tenantId, TENANTID_NOT_NULL);
399         Set<Host> hostSet = hostService.getConnectedHosts(deviceId);
400         for (Host h : hostSet) {
401             String ifaceId = h.annotations().value(IFACEID);
402             VirtualPortId hPortId = VirtualPortId.portId(ifaceId);
403             if (virtualPortService.getPort(hPortId).tenantId() != tenantId) {
404                 hostSet.remove(h);
405             } else {
406                 if (isServiceFunction(hPortId)) {
407                     hostSet.remove(h);
408                 }
409             }
410         }
411         if (hostSet.size() == 1 && hostSet.contains(host)) {
412             return true;
413         }
414         return false;
415     }
416
417     /**
418      * Adds specify Device identifier to OvsMap.
419      *
420      * @param tenantId the tenant identifier
421      * @param deviceId the device identifier
422      * @param ovsMap the instance of map to store device identifier
423      */
424     private void addDeviceIdOfOvsMap(TenantId tenantId,
425                                      DeviceId deviceId,
426                                      EventuallyConsistentMap<TenantId, Set<DeviceId>> ovsMap) {
427         checkNotNull(tenantId, TENANTID_NOT_NULL);
428         checkNotNull(deviceId, DEVICEID_NOT_NULL);
429         checkNotNull(ovsMap, OVSMAP_NOT_NULL);
430         if (ovsMap.containsKey(tenantId)) {
431             Set<DeviceId> deviceIdSet = ovsMap.get(tenantId);
432             deviceIdSet.add(deviceId);
433             ovsMap.put(tenantId, deviceIdSet);
434         } else {
435             Set<DeviceId> deviceIdSet = new HashSet<>();
436             deviceIdSet.add(deviceId);
437             ovsMap.put(tenantId, deviceIdSet);
438         }
439     }
440
441     /**
442      * Removes specify Device identifier from OvsMap.
443      *
444      * @param tenantId the tenant identifier
445      * @param deviceId the device identifier
446      * @param ovsMap the instance of map to store device identifier
447      */
448     private void removeDeviceIdOfOvsMap(TenantId tenantId,
449                                         DeviceId deviceId,
450                                         EventuallyConsistentMap<TenantId, Set<DeviceId>> ovsMap) {
451         checkNotNull(tenantId, TENANTID_NOT_NULL);
452         checkNotNull(deviceId, DEVICEID_NOT_NULL);
453         checkNotNull(ovsMap, OVSMAP_NOT_NULL);
454         Set<DeviceId> deviceIdSet = ovsMap.get(tenantId);
455         if (deviceIdSet.size() > 1) {
456             deviceIdSet.remove(deviceId);
457             ovsMap.put(tenantId, deviceIdSet);
458         } else {
459             ovsMap.remove(tenantId);
460         }
461     }
462
463     /**
464      * Notifies specify event to all listeners.
465      *
466      * @param event VtnRsc event
467      */
468     private void notifyListeners(VtnRscEvent event) {
469         checkNotNull(event, EVENT_NOT_NULL);
470         listeners.forEach(listener -> listener.event(event));
471     }
472 }