blob: 8355aa875f61c141c102cd8864867b4592058654 [file] [log] [blame]
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -08001/*
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 */
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() {
Charles Chan0c7c43b2016-01-14 17:39:20 -0800105 cfgService.unregisterProperties(getClass(), false);
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800106 store.unsetDelegate(delegate);
107 eventDispatcher.removeSink(GroupEvent.class);
108 log.info("Stopped");
109 }
110
Charles Chan0c7c43b2016-01-14 17:39:20 -0800111 @Modified
112 public void modified(ComponentContext context) {
113 if (context != null) {
114 readComponentConfiguration(context);
115 }
Andrea Campanella6ee73922016-02-03 18:00:00 -0800116 defaultProvider.init(deviceService);
117 }
118
119 @Override
120 protected GroupProvider defaultProvider() {
121 return defaultProvider;
Charles Chan0c7c43b2016-01-14 17:39:20 -0800122 }
123
124 /**
125 * Extracts properties from the component configuration context.
126 *
127 * @param context the component context
128 */
129 private void readComponentConfiguration(ComponentContext context) {
130 Dictionary<?, ?> properties = context.getProperties();
131 Boolean flag;
132
Jian Lid9b5f552016-03-11 18:15:31 -0800133 flag = Tools.isPropertyEnabled(properties, "purgeOnDisconnection");
Charles Chan0c7c43b2016-01-14 17:39:20 -0800134 if (flag == null) {
135 log.info("PurgeOnDisconnection is not configured, " +
136 "using current value of {}", purgeOnDisconnection);
137 } else {
138 purgeOnDisconnection = flag;
139 log.info("Configured. PurgeOnDisconnection is {}",
140 purgeOnDisconnection ? "enabled" : "disabled");
141 }
142 }
143
144 /**
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800145 * Create a group in the specified device with the provided parameters.
146 *
147 * @param groupDesc group creation parameters
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800148 */
149 @Override
150 public void addGroup(GroupDescription groupDesc) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900151 checkPermission(GROUP_WRITE);
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800152 store.storeGroupDescription(groupDesc);
153 }
154
155 /**
156 * Return a group object associated to an application cookie.
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700157 * <p>
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800158 * NOTE1: The presence of group object in the system does not
159 * guarantee that the "group" is actually created in device.
160 * GROUP_ADDED notification would confirm the creation of
161 * this group in data plane.
162 *
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700163 * @param deviceId device identifier
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800164 * @param appCookie application cookie to be used for lookup
165 * @return group associated with the application cookie or
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700166 * NULL if Group is not found for the provided cookie
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800167 */
168 @Override
169 public Group getGroup(DeviceId deviceId, GroupKey appCookie) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900170 checkPermission(GROUP_READ);
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800171 return store.getGroup(deviceId, appCookie);
172 }
173
174 /**
175 * Append buckets to existing group. The caller can optionally
176 * associate a new cookie during this updation. GROUP_UPDATED or
177 * GROUP_UPDATE_FAILED notifications would be provided along with
178 * cookie depending on the result of the operation on the device.
179 *
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700180 * @param deviceId device identifier
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800181 * @param oldCookie cookie to be used to retrieve the existing group
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700182 * @param buckets immutable list of group bucket to be added
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800183 * @param newCookie immutable cookie to be used post update operation
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700184 * @param appId Application Id
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800185 */
186 @Override
187 public void addBucketsToGroup(DeviceId deviceId,
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700188 GroupKey oldCookie,
189 GroupBuckets buckets,
190 GroupKey newCookie,
191 ApplicationId appId) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900192 checkPermission(GROUP_WRITE);
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800193 store.updateGroupDescription(deviceId,
194 oldCookie,
195 UpdateType.ADD,
196 buckets,
197 newCookie);
198 }
199
200 /**
201 * Remove buckets from existing group. The caller can optionally
202 * associate a new cookie during this updation. GROUP_UPDATED or
203 * GROUP_UPDATE_FAILED notifications would be provided along with
204 * cookie depending on the result of the operation on the device.
205 *
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700206 * @param deviceId device identifier
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800207 * @param oldCookie cookie to be used to retrieve the existing group
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700208 * @param buckets immutable list of group bucket to be removed
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800209 * @param newCookie immutable cookie to be used post update operation
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700210 * @param appId Application Id
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800211 */
212 @Override
213 public void removeBucketsFromGroup(DeviceId deviceId,
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700214 GroupKey oldCookie,
215 GroupBuckets buckets,
216 GroupKey newCookie,
217 ApplicationId appId) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900218 checkPermission(GROUP_WRITE);
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800219 store.updateGroupDescription(deviceId,
220 oldCookie,
221 UpdateType.REMOVE,
222 buckets,
223 newCookie);
224 }
225
226 /**
227 * Delete a group associated to an application cookie.
228 * GROUP_DELETED or GROUP_DELETE_FAILED notifications would be
229 * provided along with cookie depending on the result of the
230 * operation on the device.
231 *
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700232 * @param deviceId device identifier
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800233 * @param appCookie application cookie to be used for lookup
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700234 * @param appId Application Id
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800235 */
236 @Override
237 public void removeGroup(DeviceId deviceId,
238 GroupKey appCookie,
239 ApplicationId appId) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900240 checkPermission(GROUP_WRITE);
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800241 store.deleteGroupDescription(deviceId, appCookie);
242 }
243
244 /**
245 * Retrieve all groups created by an application in the specified device
246 * as seen by current controller instance.
247 *
248 * @param deviceId device identifier
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700249 * @param appId application id
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800250 * @return collection of immutable group objects created by the application
251 */
252 @Override
253 public Iterable<Group> getGroups(DeviceId deviceId,
254 ApplicationId appId) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900255 checkPermission(GROUP_READ);
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800256 return store.getGroups(deviceId);
257 }
258
Jonathan Hart32600692015-03-09 10:38:40 -0700259 @Override
260 public Iterable<Group> getGroups(DeviceId deviceId) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900261 checkPermission(GROUP_READ);
Jonathan Hart32600692015-03-09 10:38:40 -0700262 return store.getGroups(deviceId);
263 }
264
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800265 @Override
266 protected GroupProviderService createProviderService(GroupProvider provider) {
267 return new InternalGroupProviderService(provider);
268 }
269
270 private class InternalGroupStoreDelegate implements GroupStoreDelegate {
271 @Override
272 public void notify(GroupEvent event) {
273 final Group group = event.subject();
274 GroupProvider groupProvider =
275 getProvider(group.deviceId());
276 GroupOperations groupOps = null;
277 switch (event.type()) {
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700278 case GROUP_ADD_REQUESTED:
279 log.debug("GROUP_ADD_REQUESTED for Group {} on device {}",
280 group.id(), group.deviceId());
281 GroupOperation groupAddOp = GroupOperation.
282 createAddGroupOperation(group.id(),
283 group.type(),
284 group.buckets());
285 groupOps = new GroupOperations(
286 Collections.singletonList(groupAddOp));
287 groupProvider.performGroupOperation(group.deviceId(), groupOps);
288 break;
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800289
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700290 case GROUP_UPDATE_REQUESTED:
291 log.debug("GROUP_UPDATE_REQUESTED for Group {} on device {}",
292 group.id(), group.deviceId());
293 GroupOperation groupModifyOp = GroupOperation.
294 createModifyGroupOperation(group.id(),
295 group.type(),
296 group.buckets());
297 groupOps = new GroupOperations(
298 Collections.singletonList(groupModifyOp));
299 groupProvider.performGroupOperation(group.deviceId(), groupOps);
300 break;
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800301
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700302 case GROUP_REMOVE_REQUESTED:
303 log.debug("GROUP_REMOVE_REQUESTED for Group {} on device {}",
304 group.id(), group.deviceId());
305 GroupOperation groupDeleteOp = GroupOperation.
306 createDeleteGroupOperation(group.id(),
307 group.type());
308 groupOps = new GroupOperations(
309 Collections.singletonList(groupDeleteOp));
310 groupProvider.performGroupOperation(group.deviceId(), groupOps);
311 break;
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800312
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700313 case GROUP_ADDED:
314 case GROUP_UPDATED:
315 case GROUP_REMOVED:
316 case GROUP_ADD_FAILED:
317 case GROUP_UPDATE_FAILED:
318 case GROUP_REMOVE_FAILED:
319 post(event);
320 break;
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800321
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700322 default:
323 break;
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800324 }
325 }
326 }
327
328 private class InternalGroupProviderService
329 extends AbstractProviderService<GroupProvider>
330 implements GroupProviderService {
331
332 protected InternalGroupProviderService(GroupProvider provider) {
333 super(provider);
334 }
335
336 @Override
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700337 public void groupOperationFailed(DeviceId deviceId, GroupOperation operation) {
sangho7ff01812015-02-09 16:21:53 -0800338 store.groupOperationFailed(deviceId, operation);
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800339 }
340
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800341 @Override
342 public void pushGroupMetrics(DeviceId deviceId,
343 Collection<Group> groupEntries) {
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700344 log.trace("Received group metrics from device {}", deviceId);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700345 checkValidity();
346 store.pushGroupMetrics(deviceId, groupEntries);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800347 }
348 }
349
350 private class InternalDeviceListener implements DeviceListener {
351
352 @Override
353 public void event(DeviceEvent event) {
354 switch (event.type()) {
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700355 case DEVICE_REMOVED:
356 case DEVICE_AVAILABILITY_CHANGED:
Charles Chan0c7c43b2016-01-14 17:39:20 -0800357 DeviceId deviceId = event.subject().id();
358 if (!deviceService.isAvailable(deviceId)) {
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700359 log.debug("Device {} became un available; clearing initial audit status",
360 event.type(), event.subject().id());
361 store.deviceInitialAuditCompleted(event.subject().id(), false);
Charles Chan0c7c43b2016-01-14 17:39:20 -0800362
363 if (purgeOnDisconnection) {
364 store.purgeGroupEntry(deviceId);
365 }
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700366 }
367 break;
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700368 default:
369 break;
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800370 }
371 }
372 }
373}