blob: 31e95a48add7564428927a2174095791ab80413c [file] [log] [blame]
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -08001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -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.net.group.impl;
17
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -080018import org.apache.felix.scr.annotations.Activate;
19import org.apache.felix.scr.annotations.Component;
20import org.apache.felix.scr.annotations.Deactivate;
Charles Chan0c7c43b2016-01-14 17:39:20 -080021import org.apache.felix.scr.annotations.Modified;
22import org.apache.felix.scr.annotations.Property;
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -080023import org.apache.felix.scr.annotations.Reference;
24import org.apache.felix.scr.annotations.ReferenceCardinality;
25import org.apache.felix.scr.annotations.Service;
Jian Lid9b5f552016-03-11 18:15:31 -080026import org.onlab.util.Tools;
Charles Chan0c7c43b2016-01-14 17:39:20 -080027import org.onosproject.cfg.ComponentConfigService;
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -080028import org.onosproject.core.ApplicationId;
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -080029import org.onosproject.net.DeviceId;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080030import org.onosproject.net.device.DeviceEvent;
31import org.onosproject.net.device.DeviceListener;
32import org.onosproject.net.device.DeviceService;
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -080033import org.onosproject.net.group.Group;
34import org.onosproject.net.group.GroupBuckets;
35import org.onosproject.net.group.GroupDescription;
36import org.onosproject.net.group.GroupEvent;
37import org.onosproject.net.group.GroupKey;
38import org.onosproject.net.group.GroupListener;
39import org.onosproject.net.group.GroupOperation;
40import org.onosproject.net.group.GroupOperations;
41import org.onosproject.net.group.GroupProvider;
42import org.onosproject.net.group.GroupProviderRegistry;
43import org.onosproject.net.group.GroupProviderService;
44import org.onosproject.net.group.GroupService;
45import org.onosproject.net.group.GroupStore;
46import org.onosproject.net.group.GroupStore.UpdateType;
47import org.onosproject.net.group.GroupStoreDelegate;
Jian Lid9b5f552016-03-11 18:15:31 -080048import org.onosproject.net.provider.AbstractListenerProviderRegistry;
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -080049import org.onosproject.net.provider.AbstractProviderService;
Charles Chan0c7c43b2016-01-14 17:39:20 -080050import org.osgi.service.component.ComponentContext;
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -080051import org.slf4j.Logger;
52
Thomas Vachuska42e8cce2015-07-29 19:25:18 -070053import java.util.Collection;
54import java.util.Collections;
Charles Chan0c7c43b2016-01-14 17:39:20 -080055import java.util.Dictionary;
Thomas Vachuska42e8cce2015-07-29 19:25:18 -070056
Changhoon Yoon541ef712015-05-23 17:18:34 +090057import static org.onosproject.security.AppGuard.checkPermission;
Jian Lid9b5f552016-03-11 18:15:31 -080058import static org.onosproject.security.AppPermission.Type.GROUP_READ;
59import static org.onosproject.security.AppPermission.Type.GROUP_WRITE;
Thomas Vachuska42e8cce2015-07-29 19:25:18 -070060import static org.slf4j.LoggerFactory.getLogger;
Changhoon Yoonb856b812015-08-10 03:47:19 +090061
Changhoon Yoon541ef712015-05-23 17:18:34 +090062
63
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -080064/**
65 * Provides implementation of the group service APIs.
66 */
67@Component(immediate = true)
68@Service
69public class GroupManager
Thomas Vachuska42e8cce2015-07-29 19:25:18 -070070 extends AbstractListenerProviderRegistry<GroupEvent, GroupListener,
71 GroupProvider, GroupProviderService>
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -080072 implements GroupService, GroupProviderRegistry {
73
74 private final Logger log = getLogger(getClass());
75
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -080076 private final GroupStoreDelegate delegate = new InternalGroupStoreDelegate();
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080077 private final DeviceListener deviceListener = new InternalDeviceListener();
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -080078
79 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
80 protected GroupStore store;
81
82 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080083 protected DeviceService deviceService;
84
Charles Chan0c7c43b2016-01-14 17:39:20 -080085 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
86 protected ComponentConfigService cfgService;
87
88 @Property(name = "purgeOnDisconnection", boolValue = false,
89 label = "Purge entries associated with a device when the device goes offline")
90 private boolean purgeOnDisconnection = false;
Andrea Campanella6ee73922016-02-03 18:00:00 -080091 private final GroupDriverProvider defaultProvider = new GroupDriverProvider();
Charles Chan0c7c43b2016-01-14 17:39:20 -080092
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -080093 @Activate
Charles Chan0c7c43b2016-01-14 17:39:20 -080094 public void activate(ComponentContext context) {
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -080095 store.setDelegate(delegate);
96 eventDispatcher.addSink(GroupEvent.class, listenerRegistry);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080097 deviceService.addListener(deviceListener);
Charles Chan0c7c43b2016-01-14 17:39:20 -080098 cfgService.registerProperties(getClass());
99 modified(context);
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800100 log.info("Started");
101 }
102
103 @Deactivate
104 public void deactivate() {
Andrea Campanella3f1c61e2016-04-01 17:30:12 -0700105 deviceService.removeListener(deviceListener);
Charles Chan0c7c43b2016-01-14 17:39:20 -0800106 cfgService.unregisterProperties(getClass(), false);
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800107 store.unsetDelegate(delegate);
108 eventDispatcher.removeSink(GroupEvent.class);
109 log.info("Stopped");
110 }
111
Charles Chan0c7c43b2016-01-14 17:39:20 -0800112 @Modified
113 public void modified(ComponentContext context) {
114 if (context != null) {
115 readComponentConfiguration(context);
116 }
Andrea Campanella6ee73922016-02-03 18:00:00 -0800117 defaultProvider.init(deviceService);
118 }
119
120 @Override
121 protected GroupProvider defaultProvider() {
122 return defaultProvider;
Charles Chan0c7c43b2016-01-14 17:39:20 -0800123 }
124
125 /**
126 * Extracts properties from the component configuration context.
127 *
128 * @param context the component context
129 */
130 private void readComponentConfiguration(ComponentContext context) {
131 Dictionary<?, ?> properties = context.getProperties();
132 Boolean flag;
133
Jian Lid9b5f552016-03-11 18:15:31 -0800134 flag = Tools.isPropertyEnabled(properties, "purgeOnDisconnection");
Charles Chan0c7c43b2016-01-14 17:39:20 -0800135 if (flag == null) {
136 log.info("PurgeOnDisconnection is not configured, " +
137 "using current value of {}", purgeOnDisconnection);
138 } else {
139 purgeOnDisconnection = flag;
140 log.info("Configured. PurgeOnDisconnection is {}",
141 purgeOnDisconnection ? "enabled" : "disabled");
142 }
143 }
144
145 /**
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800146 * Create a group in the specified device with the provided parameters.
147 *
148 * @param groupDesc group creation parameters
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800149 */
150 @Override
151 public void addGroup(GroupDescription groupDesc) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900152 checkPermission(GROUP_WRITE);
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800153 store.storeGroupDescription(groupDesc);
154 }
155
156 /**
157 * Return a group object associated to an application cookie.
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700158 * <p>
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800159 * NOTE1: The presence of group object in the system does not
160 * guarantee that the "group" is actually created in device.
161 * GROUP_ADDED notification would confirm the creation of
162 * this group in data plane.
163 *
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700164 * @param deviceId device identifier
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800165 * @param appCookie application cookie to be used for lookup
166 * @return group associated with the application cookie or
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700167 * NULL if Group is not found for the provided cookie
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800168 */
169 @Override
170 public Group getGroup(DeviceId deviceId, GroupKey appCookie) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900171 checkPermission(GROUP_READ);
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800172 return store.getGroup(deviceId, appCookie);
173 }
174
175 /**
176 * Append buckets to existing group. The caller can optionally
177 * associate a new cookie during this updation. GROUP_UPDATED or
178 * GROUP_UPDATE_FAILED notifications would be provided along with
179 * cookie depending on the result of the operation on the device.
180 *
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700181 * @param deviceId device identifier
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800182 * @param oldCookie cookie to be used to retrieve the existing group
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700183 * @param buckets immutable list of group bucket to be added
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800184 * @param newCookie immutable cookie to be used post update operation
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700185 * @param appId Application Id
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800186 */
187 @Override
188 public void addBucketsToGroup(DeviceId deviceId,
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700189 GroupKey oldCookie,
190 GroupBuckets buckets,
191 GroupKey newCookie,
192 ApplicationId appId) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900193 checkPermission(GROUP_WRITE);
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800194 store.updateGroupDescription(deviceId,
195 oldCookie,
196 UpdateType.ADD,
197 buckets,
198 newCookie);
199 }
200
201 /**
202 * Remove buckets from existing group. The caller can optionally
203 * associate a new cookie during this updation. GROUP_UPDATED or
204 * GROUP_UPDATE_FAILED notifications would be provided along with
205 * cookie depending on the result of the operation on the device.
206 *
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700207 * @param deviceId device identifier
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800208 * @param oldCookie cookie to be used to retrieve the existing group
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700209 * @param buckets immutable list of group bucket to be removed
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800210 * @param newCookie immutable cookie to be used post update operation
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700211 * @param appId Application Id
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800212 */
213 @Override
214 public void removeBucketsFromGroup(DeviceId deviceId,
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700215 GroupKey oldCookie,
216 GroupBuckets buckets,
217 GroupKey newCookie,
218 ApplicationId appId) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900219 checkPermission(GROUP_WRITE);
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800220 store.updateGroupDescription(deviceId,
221 oldCookie,
222 UpdateType.REMOVE,
223 buckets,
224 newCookie);
225 }
226
Victor Silva0282ab82016-11-15 16:30:27 -0300227 /**
228 * Set buckets for an existing group. The caller can optionally
229 * associate a new cookie during this updation. GROUP_UPDATED or
230 * GROUP_UPDATE_FAILED notifications would be provided along with
231 * cookie depending on the result of the operation on the device.
232 *
233 * This operation overwrites the previous group buckets entirely.
234 *
235 * @param deviceId device identifier
236 * @param oldCookie cookie to be used to retrieve the existing group
237 * @param buckets immutable list of group buckets to be set
238 * @param newCookie immutable cookie to be used post update operation
239 * @param appId Application Id
240 */
241 @Override
242 public void setBucketsForGroup(DeviceId deviceId,
243 GroupKey oldCookie,
244 GroupBuckets buckets,
245 GroupKey newCookie,
246 ApplicationId appId) {
247 checkPermission(GROUP_WRITE);
248 store.updateGroupDescription(deviceId,
249 oldCookie,
250 UpdateType.SET,
251 buckets,
252 newCookie);
253 }
254
Kavitha Alagesanc69c66a2016-06-15 14:26:04 +0530255 @Override
256 public void purgeGroupEntries(DeviceId deviceId) {
257 checkPermission(GROUP_WRITE);
258 store.purgeGroupEntry(deviceId);
259 }
260
Victor Silva4e8b7832016-08-17 17:11:19 -0300261 @Override
262 public void purgeGroupEntries() {
263 checkPermission(GROUP_WRITE);
264 store.purgeGroupEntries();
265 }
Kavitha Alagesanc69c66a2016-06-15 14:26:04 +0530266
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800267 /**
268 * Delete a group associated to an application cookie.
269 * GROUP_DELETED or GROUP_DELETE_FAILED notifications would be
270 * provided along with cookie depending on the result of the
271 * operation on the device.
272 *
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700273 * @param deviceId device identifier
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800274 * @param appCookie application cookie to be used for lookup
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700275 * @param appId Application Id
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800276 */
277 @Override
278 public void removeGroup(DeviceId deviceId,
279 GroupKey appCookie,
280 ApplicationId appId) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900281 checkPermission(GROUP_WRITE);
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800282 store.deleteGroupDescription(deviceId, appCookie);
283 }
284
285 /**
286 * Retrieve all groups created by an application in the specified device
287 * as seen by current controller instance.
288 *
289 * @param deviceId device identifier
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700290 * @param appId application id
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800291 * @return collection of immutable group objects created by the application
292 */
293 @Override
294 public Iterable<Group> getGroups(DeviceId deviceId,
295 ApplicationId appId) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900296 checkPermission(GROUP_READ);
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800297 return store.getGroups(deviceId);
298 }
299
Jonathan Hart32600692015-03-09 10:38:40 -0700300 @Override
301 public Iterable<Group> getGroups(DeviceId deviceId) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900302 checkPermission(GROUP_READ);
Jonathan Hart32600692015-03-09 10:38:40 -0700303 return store.getGroups(deviceId);
304 }
305
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800306 @Override
307 protected GroupProviderService createProviderService(GroupProvider provider) {
308 return new InternalGroupProviderService(provider);
309 }
310
311 private class InternalGroupStoreDelegate implements GroupStoreDelegate {
312 @Override
313 public void notify(GroupEvent event) {
314 final Group group = event.subject();
315 GroupProvider groupProvider =
316 getProvider(group.deviceId());
317 GroupOperations groupOps = null;
318 switch (event.type()) {
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700319 case GROUP_ADD_REQUESTED:
320 log.debug("GROUP_ADD_REQUESTED for Group {} on device {}",
321 group.id(), group.deviceId());
322 GroupOperation groupAddOp = GroupOperation.
323 createAddGroupOperation(group.id(),
324 group.type(),
325 group.buckets());
326 groupOps = new GroupOperations(
327 Collections.singletonList(groupAddOp));
328 groupProvider.performGroupOperation(group.deviceId(), groupOps);
329 break;
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800330
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700331 case GROUP_UPDATE_REQUESTED:
332 log.debug("GROUP_UPDATE_REQUESTED for Group {} on device {}",
333 group.id(), group.deviceId());
334 GroupOperation groupModifyOp = GroupOperation.
335 createModifyGroupOperation(group.id(),
336 group.type(),
337 group.buckets());
338 groupOps = new GroupOperations(
339 Collections.singletonList(groupModifyOp));
340 groupProvider.performGroupOperation(group.deviceId(), groupOps);
341 break;
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800342
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700343 case GROUP_REMOVE_REQUESTED:
344 log.debug("GROUP_REMOVE_REQUESTED for Group {} on device {}",
345 group.id(), group.deviceId());
346 GroupOperation groupDeleteOp = GroupOperation.
347 createDeleteGroupOperation(group.id(),
348 group.type());
349 groupOps = new GroupOperations(
350 Collections.singletonList(groupDeleteOp));
351 groupProvider.performGroupOperation(group.deviceId(), groupOps);
352 break;
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800353
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700354 case GROUP_ADDED:
355 case GROUP_UPDATED:
356 case GROUP_REMOVED:
357 case GROUP_ADD_FAILED:
358 case GROUP_UPDATE_FAILED:
359 case GROUP_REMOVE_FAILED:
helenyrwu89470f12016-08-12 13:18:10 -0700360 case GROUP_BUCKET_FAILOVER:
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700361 post(event);
362 break;
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700363 default:
364 break;
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800365 }
366 }
367 }
368
369 private class InternalGroupProviderService
370 extends AbstractProviderService<GroupProvider>
371 implements GroupProviderService {
372
373 protected InternalGroupProviderService(GroupProvider provider) {
374 super(provider);
375 }
376
377 @Override
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700378 public void groupOperationFailed(DeviceId deviceId, GroupOperation operation) {
sangho7ff01812015-02-09 16:21:53 -0800379 store.groupOperationFailed(deviceId, operation);
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800380 }
381
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800382 @Override
383 public void pushGroupMetrics(DeviceId deviceId,
384 Collection<Group> groupEntries) {
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700385 log.trace("Received group metrics from device {}", deviceId);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700386 checkValidity();
387 store.pushGroupMetrics(deviceId, groupEntries);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800388 }
helenyrwu89470f12016-08-12 13:18:10 -0700389
390 @Override
391 public void notifyOfFailovers(Collection<Group> failoverGroups) {
392 store.notifyOfFailovers(failoverGroups);
393 }
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800394 }
395
396 private class InternalDeviceListener implements DeviceListener {
397
398 @Override
399 public void event(DeviceEvent event) {
400 switch (event.type()) {
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700401 case DEVICE_REMOVED:
402 case DEVICE_AVAILABILITY_CHANGED:
Charles Chan0c7c43b2016-01-14 17:39:20 -0800403 DeviceId deviceId = event.subject().id();
404 if (!deviceService.isAvailable(deviceId)) {
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700405 log.debug("Device {} became un available; clearing initial audit status",
406 event.type(), event.subject().id());
407 store.deviceInitialAuditCompleted(event.subject().id(), false);
Charles Chan0c7c43b2016-01-14 17:39:20 -0800408
409 if (purgeOnDisconnection) {
410 store.purgeGroupEntry(deviceId);
411 }
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700412 }
413 break;
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700414 default:
415 break;
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800416 }
417 }
418 }
helenyrwu89470f12016-08-12 13:18:10 -0700419
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800420}