9f944da1bd695605281f7a559067c39d331d0b60
[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.floatingip.impl;
17
18 import static com.google.common.base.Preconditions.checkNotNull;
19 import static org.slf4j.LoggerFactory.getLogger;
20
21 import java.util.Collection;
22 import java.util.Collections;
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.util.KryoNamespace;
33 import org.onosproject.core.ApplicationId;
34 import org.onosproject.core.CoreService;
35 import org.onosproject.store.serializers.KryoNamespaces;
36 import org.onosproject.store.service.EventuallyConsistentMap;
37 import org.onosproject.store.service.EventuallyConsistentMapEvent;
38 import org.onosproject.store.service.EventuallyConsistentMapListener;
39 import org.onosproject.store.service.StorageService;
40 import org.onosproject.store.service.WallClockTimestamp;
41 import org.onosproject.vtnrsc.DefaultFloatingIp;
42 import org.onosproject.vtnrsc.FloatingIp;
43 import org.onosproject.vtnrsc.FloatingIpId;
44 import org.onosproject.vtnrsc.TenantId;
45 import org.onosproject.vtnrsc.TenantNetworkId;
46 import org.onosproject.vtnrsc.VirtualPortId;
47 import org.onosproject.vtnrsc.RouterId;
48 import org.onosproject.vtnrsc.floatingip.FloatingIpEvent;
49 import org.onosproject.vtnrsc.floatingip.FloatingIpListener;
50 import org.onosproject.vtnrsc.floatingip.FloatingIpService;
51 import org.onosproject.vtnrsc.router.RouterService;
52 import org.onosproject.vtnrsc.tenantnetwork.TenantNetworkService;
53 import org.onosproject.vtnrsc.virtualport.VirtualPortService;
54 import org.slf4j.Logger;
55
56 import com.google.common.collect.Sets;
57
58 /**
59  * Provides implementation of the FloatingIp service.
60  */
61 @Component(immediate = true)
62 @Service
63 public class FloatingIpManager implements FloatingIpService {
64     private static final String FLOATINGIP_ID_NOT_NULL = "Floatingip ID cannot be null";
65     private static final String FLOATINGIP_NOT_NULL = "Floatingip cannot be null";
66     private static final String FLOATINGIP = "vtn-floatingip-store";
67     private static final String VTNRSC_APP = "org.onosproject.vtnrsc";
68     private static final String LISTENER_NOT_NULL = "Listener cannot be null";
69     private static final String EVENT_NOT_NULL = "event cannot be null";
70
71     private final Logger log = getLogger(getClass());
72     private final Set<FloatingIpListener> listeners = Sets
73             .newCopyOnWriteArraySet();
74     private EventuallyConsistentMapListener<FloatingIpId, FloatingIp> floatingIpListener =
75             new InnerFloatingIpStoreListener();
76     protected EventuallyConsistentMap<FloatingIpId, FloatingIp> floatingIpStore;
77     protected ApplicationId appId;
78
79     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
80     protected StorageService storageService;
81
82     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
83     protected CoreService coreService;
84
85     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
86     protected TenantNetworkService tenantNetworkService;
87
88     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
89     protected VirtualPortService virtualPortService;
90
91     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
92     protected RouterService routerService;
93
94     @Activate
95     public void activate() {
96         appId = coreService.registerApplication(VTNRSC_APP);
97         KryoNamespace.Builder serializer = KryoNamespace
98                 .newBuilder()
99                 .register(KryoNamespaces.API)
100                 .register(FloatingIp.class, FloatingIpId.class,
101                           TenantNetworkId.class, TenantId.class,
102                           FloatingIp.Status.class, RouterId.class,
103                           VirtualPortId.class, DefaultFloatingIp.class);
104         floatingIpStore = storageService
105                 .<FloatingIpId, FloatingIp>eventuallyConsistentMapBuilder()
106                 .withName(FLOATINGIP).withSerializer(serializer)
107                 .withTimestampProvider((k, v) -> new WallClockTimestamp())
108                 .build();
109         floatingIpStore.addListener(floatingIpListener);
110         log.info("Started");
111     }
112
113     @Deactivate
114     public void deactivate() {
115         floatingIpStore.removeListener(floatingIpListener);
116         floatingIpStore.destroy();
117         listeners.clear();
118         log.info("Stopped");
119     }
120
121     @Override
122     public Collection<FloatingIp> getFloatingIps() {
123         return Collections.unmodifiableCollection(floatingIpStore.values());
124     }
125
126     @Override
127     public FloatingIp getFloatingIp(FloatingIpId floatingIpId) {
128         checkNotNull(floatingIpId, FLOATINGIP_ID_NOT_NULL);
129         return floatingIpStore.get(floatingIpId);
130     }
131
132     @Override
133     public boolean exists(FloatingIpId floatingIpId) {
134         checkNotNull(floatingIpId, FLOATINGIP_ID_NOT_NULL);
135         return floatingIpStore.containsKey(floatingIpId);
136     }
137
138     @Override
139     public boolean floatingIpIsUsed(IpAddress floatingIpAddr,
140                                     FloatingIpId floatingIpId) {
141         checkNotNull(floatingIpAddr, "Floating IP address cannot be null");
142         checkNotNull(floatingIpId, "Floating IP Id cannot be null");
143         Collection<FloatingIp> floatingIps = getFloatingIps();
144         for (FloatingIp floatingIp : floatingIps) {
145             if (floatingIp.floatingIp().equals(floatingIpAddr)
146                     && !floatingIp.id().equals(floatingIpId)) {
147                 return true;
148             }
149         }
150         return false;
151     }
152
153     @Override
154     public boolean fixedIpIsUsed(IpAddress fixedIpAddr, TenantId tenantId,
155                                  FloatingIpId floatingIpId) {
156         checkNotNull(fixedIpAddr, "Fixed IP address cannot be null");
157         checkNotNull(tenantId, "Tenant Id cannot be null");
158         checkNotNull(floatingIpId, "Floating IP Id cannot be null");
159         Collection<FloatingIp> floatingIps = getFloatingIps();
160         for (FloatingIp floatingIp : floatingIps) {
161             IpAddress fixedIp = floatingIp.fixedIp();
162             if (fixedIp != null) {
163                 if (fixedIp.equals(fixedIpAddr)
164                         && floatingIp.tenantId().equals(tenantId)
165                         && !floatingIp.id().equals(floatingIpId)) {
166                     return true;
167                 }
168             }
169         }
170         return false;
171     }
172
173     @Override
174     public boolean createFloatingIps(Collection<FloatingIp> floatingIps) {
175         checkNotNull(floatingIps, FLOATINGIP_NOT_NULL);
176         boolean result = true;
177         for (FloatingIp floatingIp : floatingIps) {
178             verifyFloatingIpData(floatingIp);
179             if (floatingIp.portId() != null) {
180                 floatingIpStore.put(floatingIp.id(), floatingIp);
181                 if (!floatingIpStore.containsKey(floatingIp.id())) {
182                     log.debug("The floating Ip is created failed whose identifier is {}",
183                               floatingIp.id().toString());
184                     result = false;
185                 }
186             } else {
187                 FloatingIp oldFloatingIp = floatingIpStore.get(floatingIp.id());
188                 if (oldFloatingIp != null) {
189                     floatingIpStore.remove(floatingIp.id(), oldFloatingIp);
190                     if (floatingIpStore.containsKey(floatingIp.id())) {
191                         log.debug("The floating Ip is created failed whose identifier is {}",
192                                   floatingIp.id().toString());
193                         result = false;
194                     }
195                 }
196             }
197         }
198         return result;
199     }
200
201     @Override
202     public boolean updateFloatingIps(Collection<FloatingIp> floatingIps) {
203         checkNotNull(floatingIps, FLOATINGIP_NOT_NULL);
204         boolean result = true;
205         if (floatingIps != null) {
206             for (FloatingIp floatingIp : floatingIps) {
207                 verifyFloatingIpData(floatingIp);
208                 if (floatingIp.portId() != null) {
209                     floatingIpStore.put(floatingIp.id(), floatingIp);
210                     if (!floatingIpStore.containsKey(floatingIp.id())) {
211                         log.debug("The floating Ip is updated failed whose identifier is {}",
212                                   floatingIp.id().toString());
213                         result = false;
214                     }
215                 } else {
216                     FloatingIp oldFloatingIp = floatingIpStore.get(floatingIp
217                             .id());
218                     if (oldFloatingIp != null) {
219                         floatingIpStore.remove(floatingIp.id(), oldFloatingIp);
220                         if (floatingIpStore.containsKey(floatingIp.id())) {
221                             log.debug("The floating Ip is updated failed whose identifier is {}",
222                                       floatingIp.id().toString());
223                             result = false;
224                         }
225                     }
226                 }
227             }
228         }
229         return result;
230     }
231
232     @Override
233     public boolean removeFloatingIps(Collection<FloatingIpId> floatingIpIds) {
234         checkNotNull(floatingIpIds, FLOATINGIP_ID_NOT_NULL);
235         boolean result = true;
236         if (floatingIpIds != null) {
237             for (FloatingIpId floatingIpId : floatingIpIds) {
238                 if (!floatingIpStore.containsKey(floatingIpId)) {
239                     log.debug("The floatingIp is not exist whose identifier is {}",
240                               floatingIpId.toString());
241                     throw new IllegalArgumentException(
242                                                        "FloatingIP ID doesn't exist");
243                 }
244                 FloatingIp floatingIp = floatingIpStore.get(floatingIpId);
245                 floatingIpStore.remove(floatingIpId, floatingIp);
246                 if (floatingIpStore.containsKey(floatingIpId)) {
247                     log.debug("The floating Ip is deleted failed whose identifier is {}",
248                               floatingIpId.toString());
249                     result = false;
250                 }
251             }
252         }
253         return result;
254     }
255
256     @Override
257     public void addListener(FloatingIpListener listener) {
258         checkNotNull(listener, LISTENER_NOT_NULL);
259         listeners.add(listener);
260     }
261
262     @Override
263     public void removeListener(FloatingIpListener listener) {
264         checkNotNull(listener, LISTENER_NOT_NULL);
265         listeners.add(listener);
266     }
267
268     /**
269      * Verifies validity of FloatingIp data.
270      *
271      * @param floatingIps floatingIp instance
272      */
273     private void verifyFloatingIpData(FloatingIp floatingIps) {
274         checkNotNull(floatingIps, FLOATINGIP_NOT_NULL);
275         if (!tenantNetworkService.exists(floatingIps.networkId())) {
276             log.debug("The network identifier {} that the floating Ip {} create for is not exist",
277                       floatingIps.networkId().toString(), floatingIps.id()
278                               .toString());
279             throw new IllegalArgumentException(
280                                                "Floating network ID doesn't exist");
281         }
282
283         VirtualPortId portId = floatingIps.portId();
284         if (portId != null && !virtualPortService.exists(portId)) {
285             log.debug("The port identifier {} that the floating Ip {} create for is not exist",
286                       floatingIps.portId().toString(), floatingIps.id()
287                               .toString());
288             throw new IllegalArgumentException("Port ID doesn't exist");
289         }
290
291         RouterId routerId = floatingIps.routerId();
292         if (routerId != null && !routerService.exists(routerId)) {
293             log.debug("The router identifier {} that the floating Ip {} create for is not exist",
294                       floatingIps.routerId().toString(), floatingIps.id()
295                               .toString());
296             throw new IllegalArgumentException("Router ID doesn't exist");
297         }
298
299         if (floatingIpIsUsed(floatingIps.floatingIp(), floatingIps.id())) {
300             log.debug("The floaing Ip {} that the floating Ip {} create for is used",
301                       floatingIps.floatingIp().toString(), floatingIps.id()
302                               .toString());
303             throw new IllegalArgumentException(
304                                                "The floating IP address is used");
305         }
306
307         IpAddress fixedIp = floatingIps.fixedIp();
308         if (fixedIp != null
309                 && fixedIpIsUsed(fixedIp, floatingIps.tenantId(),
310                                  floatingIps.id())) {
311             log.debug("The fixed Ip {} that the floating Ip {} create for is used",
312                       floatingIps.fixedIp().toString(), floatingIps.id()
313                               .toString());
314             throw new IllegalArgumentException("The fixed IP address is used");
315         }
316     }
317
318     private class InnerFloatingIpStoreListener
319             implements
320             EventuallyConsistentMapListener<FloatingIpId, FloatingIp> {
321
322         @Override
323         public void event(EventuallyConsistentMapEvent<FloatingIpId, FloatingIp> event) {
324             checkNotNull(event, EVENT_NOT_NULL);
325             FloatingIp floatingIp = event.value();
326             if (EventuallyConsistentMapEvent.Type.PUT == event.type()) {
327                 notifyListeners(new FloatingIpEvent(
328                                                     FloatingIpEvent.Type.FLOATINGIP_PUT,
329                                                     floatingIp));
330             }
331             if (EventuallyConsistentMapEvent.Type.REMOVE == event.type()) {
332                 notifyListeners(new FloatingIpEvent(
333                                                     FloatingIpEvent.Type.FLOATINGIP_DELETE,
334                                                     floatingIp));
335             }
336         }
337     }
338
339     /**
340      * Notifies specify event to all listeners.
341      *
342      * @param event Floating IP event
343      */
344     private void notifyListeners(FloatingIpEvent event) {
345         checkNotNull(event, EVENT_NOT_NULL);
346         listeners.forEach(listener -> listener.event(event));
347     }
348 }