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