blob: 4cb21e5900fe0df18d0d178da834d683df0c5203 [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
18import static org.slf4j.LoggerFactory.getLogger;
19
20import java.util.Arrays;
21import java.util.Collection;
22import java.util.Iterator;
23import java.util.Set;
24
25import org.apache.felix.scr.annotations.Activate;
26import org.apache.felix.scr.annotations.Component;
27import org.apache.felix.scr.annotations.Deactivate;
28import org.apache.felix.scr.annotations.Reference;
29import org.apache.felix.scr.annotations.ReferenceCardinality;
30import org.apache.felix.scr.annotations.Service;
31import org.onosproject.core.ApplicationId;
32import org.onosproject.event.AbstractListenerRegistry;
33import org.onosproject.event.EventDeliveryService;
34import org.onosproject.net.DeviceId;
35import org.onosproject.net.group.Group;
36import org.onosproject.net.group.GroupBuckets;
37import org.onosproject.net.group.GroupDescription;
38import org.onosproject.net.group.GroupEvent;
39import org.onosproject.net.group.GroupKey;
40import org.onosproject.net.group.GroupListener;
41import org.onosproject.net.group.GroupOperation;
42import org.onosproject.net.group.GroupOperations;
43import org.onosproject.net.group.GroupProvider;
44import org.onosproject.net.group.GroupProviderRegistry;
45import org.onosproject.net.group.GroupProviderService;
46import org.onosproject.net.group.GroupService;
47import org.onosproject.net.group.GroupStore;
48import org.onosproject.net.group.GroupStore.UpdateType;
49import org.onosproject.net.group.GroupStoreDelegate;
50import org.onosproject.net.provider.AbstractProviderRegistry;
51import org.onosproject.net.provider.AbstractProviderService;
52import org.slf4j.Logger;
53
54import com.google.common.collect.Sets;
55
56/**
57 * Provides implementation of the group service APIs.
58 */
59@Component(immediate = true)
60@Service
61public class GroupManager
62 extends AbstractProviderRegistry<GroupProvider, GroupProviderService>
63 implements GroupService, GroupProviderRegistry {
64
65 private final Logger log = getLogger(getClass());
66
67 private final AbstractListenerRegistry<GroupEvent, GroupListener>
68 listenerRegistry = new AbstractListenerRegistry<>();
69 private final GroupStoreDelegate delegate = new InternalGroupStoreDelegate();
70
71 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
72 protected GroupStore store;
73
74 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
75 protected EventDeliveryService eventDispatcher;
76
77 @Activate
78 public void activate() {
79 store.setDelegate(delegate);
80 eventDispatcher.addSink(GroupEvent.class, listenerRegistry);
81 log.info("Started");
82 }
83
84 @Deactivate
85 public void deactivate() {
86 store.unsetDelegate(delegate);
87 eventDispatcher.removeSink(GroupEvent.class);
88 log.info("Stopped");
89 }
90
91 /**
92 * Create a group in the specified device with the provided parameters.
93 *
94 * @param groupDesc group creation parameters
95 *
96 */
97 @Override
98 public void addGroup(GroupDescription groupDesc) {
99 store.storeGroupDescription(groupDesc);
100 }
101
102 /**
103 * Return a group object associated to an application cookie.
104 *
105 * NOTE1: The presence of group object in the system does not
106 * guarantee that the "group" is actually created in device.
107 * GROUP_ADDED notification would confirm the creation of
108 * this group in data plane.
109 *
110 * @param deviceId device identifier
111 * @param appCookie application cookie to be used for lookup
112 * @return group associated with the application cookie or
113 * NULL if Group is not found for the provided cookie
114 */
115 @Override
116 public Group getGroup(DeviceId deviceId, GroupKey appCookie) {
117 return store.getGroup(deviceId, appCookie);
118 }
119
120 /**
121 * Append buckets to existing group. The caller can optionally
122 * associate a new cookie during this updation. GROUP_UPDATED or
123 * GROUP_UPDATE_FAILED notifications would be provided along with
124 * cookie depending on the result of the operation on the device.
125 *
126 * @param deviceId device identifier
127 * @param oldCookie cookie to be used to retrieve the existing group
128 * @param buckets immutable list of group bucket to be added
129 * @param newCookie immutable cookie to be used post update operation
130 * @param appId Application Id
131 */
132 @Override
133 public void addBucketsToGroup(DeviceId deviceId,
134 GroupKey oldCookie,
135 GroupBuckets buckets,
136 GroupKey newCookie,
137 ApplicationId appId) {
138 store.updateGroupDescription(deviceId,
139 oldCookie,
140 UpdateType.ADD,
141 buckets,
142 newCookie);
143 }
144
145 /**
146 * Remove buckets from existing group. The caller can optionally
147 * associate a new cookie during this updation. GROUP_UPDATED or
148 * GROUP_UPDATE_FAILED notifications would be provided along with
149 * cookie depending on the result of the operation on the device.
150 *
151 * @param deviceId device identifier
152 * @param oldCookie cookie to be used to retrieve the existing group
153 * @param buckets immutable list of group bucket to be removed
154 * @param newCookie immutable cookie to be used post update operation
155 * @param appId Application Id
156 */
157 @Override
158 public void removeBucketsFromGroup(DeviceId deviceId,
159 GroupKey oldCookie,
160 GroupBuckets buckets,
161 GroupKey newCookie,
162 ApplicationId appId) {
163 store.updateGroupDescription(deviceId,
164 oldCookie,
165 UpdateType.REMOVE,
166 buckets,
167 newCookie);
168 }
169
170 /**
171 * Delete a group associated to an application cookie.
172 * GROUP_DELETED or GROUP_DELETE_FAILED notifications would be
173 * provided along with cookie depending on the result of the
174 * operation on the device.
175 *
176 * @param deviceId device identifier
177 * @param appCookie application cookie to be used for lookup
178 * @param appId Application Id
179 */
180 @Override
181 public void removeGroup(DeviceId deviceId,
182 GroupKey appCookie,
183 ApplicationId appId) {
184 store.deleteGroupDescription(deviceId, appCookie);
185 }
186
187 /**
188 * Retrieve all groups created by an application in the specified device
189 * as seen by current controller instance.
190 *
191 * @param deviceId device identifier
192 * @param appId application id
193 * @return collection of immutable group objects created by the application
194 */
195 @Override
196 public Iterable<Group> getGroups(DeviceId deviceId,
197 ApplicationId appId) {
198 return store.getGroups(deviceId);
199 }
200
201 /**
202 * Adds the specified group listener.
203 *
204 * @param listener group listener
205 */
206 @Override
207 public void addListener(GroupListener listener) {
208 listenerRegistry.addListener(listener);
209 }
210
211 /**
212 * Removes the specified group listener.
213 *
214 * @param listener group listener
215 */
216 @Override
217 public void removeListener(GroupListener listener) {
218 listenerRegistry.removeListener(listener);
219 }
220
221 @Override
222 protected GroupProviderService createProviderService(GroupProvider provider) {
223 return new InternalGroupProviderService(provider);
224 }
225
226 private class InternalGroupStoreDelegate implements GroupStoreDelegate {
227 @Override
228 public void notify(GroupEvent event) {
229 final Group group = event.subject();
230 GroupProvider groupProvider =
231 getProvider(group.deviceId());
232 GroupOperations groupOps = null;
233 switch (event.type()) {
234 case GROUP_ADD_REQUESTED:
235 GroupOperation groupAddOp = GroupOperation.
236 createAddGroupOperation(group.id(),
237 group.type(),
238 group.buckets());
239 groupOps = new GroupOperations(
240 Arrays.asList(groupAddOp));
241 groupProvider.performGroupOperation(group.deviceId(), groupOps);
242 break;
243
244 case GROUP_UPDATE_REQUESTED:
245 GroupOperation groupModifyOp = GroupOperation.
246 createModifyGroupOperation(group.id(),
247 group.type(),
248 group.buckets());
249 groupOps = new GroupOperations(
250 Arrays.asList(groupModifyOp));
251 groupProvider.performGroupOperation(group.deviceId(), groupOps);
252 break;
253
254 case GROUP_REMOVE_REQUESTED:
255 GroupOperation groupDeleteOp = GroupOperation.
256 createDeleteGroupOperation(group.id(),
257 group.type());
258 groupOps = new GroupOperations(
259 Arrays.asList(groupDeleteOp));
260 groupProvider.performGroupOperation(group.deviceId(), groupOps);
261 break;
262
263 case GROUP_ADDED:
264 case GROUP_UPDATED:
265 case GROUP_REMOVED:
sangho7ff01812015-02-09 16:21:53 -0800266 case GROUP_ADD_FAILED:
267 case GROUP_UPDATE_FAILED:
268 case GROUP_REMOVE_FAILED:
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800269 eventDispatcher.post(event);
270 break;
271
272 default:
273 break;
274 }
275 }
276 }
277
278 private class InternalGroupProviderService
279 extends AbstractProviderService<GroupProvider>
280 implements GroupProviderService {
281
282 protected InternalGroupProviderService(GroupProvider provider) {
283 super(provider);
284 }
285
286 @Override
sangho7ff01812015-02-09 16:21:53 -0800287 public void groupOperationFailed(DeviceId deviceId,
288 GroupOperation operation) {
289 store.groupOperationFailed(deviceId, operation);
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800290 }
291
292 private void groupMissing(Group group) {
293 checkValidity();
294 GroupProvider gp = getProvider(group.deviceId());
295 switch (group.state()) {
296 case PENDING_DELETE:
297 store.removeGroupEntry(group);
298 break;
299 case ADDED:
300 case PENDING_ADD:
301 GroupOperation groupAddOp = GroupOperation.
302 createAddGroupOperation(group.id(),
303 group.type(),
304 group.buckets());
305 GroupOperations groupOps = new GroupOperations(
306 Arrays.asList(groupAddOp));
307 gp.performGroupOperation(group.deviceId(), groupOps);
308 break;
309 default:
310 log.debug("Group {} has not been installed.", group);
311 break;
312 }
313 }
314
315
316 private void extraneousGroup(Group group) {
317 log.debug("Group {} is on switch but not in store.", group);
318 checkValidity();
319 store.addOrUpdateExtraneousGroupEntry(group);
320 }
321
322 private void groupAdded(Group group) {
323 checkValidity();
324
325 log.trace("Group {}", group);
326 store.addOrUpdateGroupEntry(group);
327 }
328
329 @Override
330 public void pushGroupMetrics(DeviceId deviceId,
331 Collection<Group> groupEntries) {
332 boolean deviceInitialAuditStatus =
333 store.deviceInitialAuditStatus(deviceId);
334 Set<Group> southboundGroupEntries =
335 Sets.newHashSet(groupEntries);
336 Set<Group> storedGroupEntries =
337 Sets.newHashSet(store.getGroups(deviceId));
338 Set<Group> extraneousStoredEntries =
339 Sets.newHashSet(store.getExtraneousGroups(deviceId));
340
341 for (Iterator<Group> it = southboundGroupEntries.iterator(); it.hasNext();) {
342 Group group = it.next();
343 if (storedGroupEntries.remove(group)) {
344 // we both have the group, let's update some info then.
345 groupAdded(group);
346 it.remove();
347 }
348 }
349 for (Group group : southboundGroupEntries) {
350 // there are groups in the switch that aren't in the store
351 extraneousStoredEntries.remove(group);
352 extraneousGroup(group);
353 }
354 for (Group group : storedGroupEntries) {
355 // there are groups in the store that aren't in the switch
356 groupMissing(group);
357 }
358 for (Group group : extraneousStoredEntries) {
359 // there are groups in the extraneous store that
360 // aren't in the switch
361 store.removeExtraneousGroupEntry(group);
362 }
363
364 if (!deviceInitialAuditStatus) {
365 store.deviceInitialAuditCompleted(deviceId);
366 }
367 }
368 }
369}