blob: 1490b0b4178286ca90ce078459787cca1b63be08 [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;
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080035import org.onosproject.net.device.DeviceEvent;
36import org.onosproject.net.device.DeviceListener;
37import org.onosproject.net.device.DeviceService;
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -080038import org.onosproject.net.group.Group;
39import org.onosproject.net.group.GroupBuckets;
40import org.onosproject.net.group.GroupDescription;
41import org.onosproject.net.group.GroupEvent;
42import org.onosproject.net.group.GroupKey;
43import org.onosproject.net.group.GroupListener;
44import org.onosproject.net.group.GroupOperation;
45import org.onosproject.net.group.GroupOperations;
46import org.onosproject.net.group.GroupProvider;
47import org.onosproject.net.group.GroupProviderRegistry;
48import org.onosproject.net.group.GroupProviderService;
49import org.onosproject.net.group.GroupService;
50import org.onosproject.net.group.GroupStore;
51import org.onosproject.net.group.GroupStore.UpdateType;
52import org.onosproject.net.group.GroupStoreDelegate;
53import org.onosproject.net.provider.AbstractProviderRegistry;
54import org.onosproject.net.provider.AbstractProviderService;
55import org.slf4j.Logger;
56
57import com.google.common.collect.Sets;
58
59/**
60 * Provides implementation of the group service APIs.
61 */
62@Component(immediate = true)
63@Service
64public class GroupManager
65 extends AbstractProviderRegistry<GroupProvider, GroupProviderService>
66 implements GroupService, GroupProviderRegistry {
67
68 private final Logger log = getLogger(getClass());
69
70 private final AbstractListenerRegistry<GroupEvent, GroupListener>
71 listenerRegistry = new AbstractListenerRegistry<>();
72 private final GroupStoreDelegate delegate = new InternalGroupStoreDelegate();
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080073 private final DeviceListener deviceListener = new InternalDeviceListener();
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -080074
75 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
76 protected GroupStore store;
77
78 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080079 protected DeviceService deviceService;
80
81 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -080082 protected EventDeliveryService eventDispatcher;
83
84 @Activate
85 public void activate() {
86 store.setDelegate(delegate);
87 eventDispatcher.addSink(GroupEvent.class, listenerRegistry);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -080088 deviceService.addListener(deviceListener);
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -080089 log.info("Started");
90 }
91
92 @Deactivate
93 public void deactivate() {
94 store.unsetDelegate(delegate);
95 eventDispatcher.removeSink(GroupEvent.class);
96 log.info("Stopped");
97 }
98
99 /**
100 * Create a group in the specified device with the provided parameters.
101 *
102 * @param groupDesc group creation parameters
103 *
104 */
105 @Override
106 public void addGroup(GroupDescription groupDesc) {
107 store.storeGroupDescription(groupDesc);
108 }
109
110 /**
111 * Return a group object associated to an application cookie.
112 *
113 * NOTE1: The presence of group object in the system does not
114 * guarantee that the "group" is actually created in device.
115 * GROUP_ADDED notification would confirm the creation of
116 * this group in data plane.
117 *
118 * @param deviceId device identifier
119 * @param appCookie application cookie to be used for lookup
120 * @return group associated with the application cookie or
121 * NULL if Group is not found for the provided cookie
122 */
123 @Override
124 public Group getGroup(DeviceId deviceId, GroupKey appCookie) {
125 return store.getGroup(deviceId, appCookie);
126 }
127
128 /**
129 * Append buckets to existing group. The caller can optionally
130 * associate a new cookie during this updation. GROUP_UPDATED or
131 * GROUP_UPDATE_FAILED notifications would be provided along with
132 * cookie depending on the result of the operation on the device.
133 *
134 * @param deviceId device identifier
135 * @param oldCookie cookie to be used to retrieve the existing group
136 * @param buckets immutable list of group bucket to be added
137 * @param newCookie immutable cookie to be used post update operation
138 * @param appId Application Id
139 */
140 @Override
141 public void addBucketsToGroup(DeviceId deviceId,
142 GroupKey oldCookie,
143 GroupBuckets buckets,
144 GroupKey newCookie,
145 ApplicationId appId) {
146 store.updateGroupDescription(deviceId,
147 oldCookie,
148 UpdateType.ADD,
149 buckets,
150 newCookie);
151 }
152
153 /**
154 * Remove buckets from existing group. The caller can optionally
155 * associate a new cookie during this updation. GROUP_UPDATED or
156 * GROUP_UPDATE_FAILED notifications would be provided along with
157 * cookie depending on the result of the operation on the device.
158 *
159 * @param deviceId device identifier
160 * @param oldCookie cookie to be used to retrieve the existing group
161 * @param buckets immutable list of group bucket to be removed
162 * @param newCookie immutable cookie to be used post update operation
163 * @param appId Application Id
164 */
165 @Override
166 public void removeBucketsFromGroup(DeviceId deviceId,
167 GroupKey oldCookie,
168 GroupBuckets buckets,
169 GroupKey newCookie,
170 ApplicationId appId) {
171 store.updateGroupDescription(deviceId,
172 oldCookie,
173 UpdateType.REMOVE,
174 buckets,
175 newCookie);
176 }
177
178 /**
179 * Delete a group associated to an application cookie.
180 * GROUP_DELETED or GROUP_DELETE_FAILED notifications would be
181 * provided along with cookie depending on the result of the
182 * operation on the device.
183 *
184 * @param deviceId device identifier
185 * @param appCookie application cookie to be used for lookup
186 * @param appId Application Id
187 */
188 @Override
189 public void removeGroup(DeviceId deviceId,
190 GroupKey appCookie,
191 ApplicationId appId) {
192 store.deleteGroupDescription(deviceId, appCookie);
193 }
194
195 /**
196 * Retrieve all groups created by an application in the specified device
197 * as seen by current controller instance.
198 *
199 * @param deviceId device identifier
200 * @param appId application id
201 * @return collection of immutable group objects created by the application
202 */
203 @Override
204 public Iterable<Group> getGroups(DeviceId deviceId,
205 ApplicationId appId) {
206 return store.getGroups(deviceId);
207 }
208
209 /**
210 * Adds the specified group listener.
211 *
212 * @param listener group listener
213 */
214 @Override
215 public void addListener(GroupListener listener) {
216 listenerRegistry.addListener(listener);
217 }
218
219 /**
220 * Removes the specified group listener.
221 *
222 * @param listener group listener
223 */
224 @Override
225 public void removeListener(GroupListener listener) {
226 listenerRegistry.removeListener(listener);
227 }
228
229 @Override
230 protected GroupProviderService createProviderService(GroupProvider provider) {
231 return new InternalGroupProviderService(provider);
232 }
233
234 private class InternalGroupStoreDelegate implements GroupStoreDelegate {
235 @Override
236 public void notify(GroupEvent event) {
237 final Group group = event.subject();
238 GroupProvider groupProvider =
239 getProvider(group.deviceId());
240 GroupOperations groupOps = null;
241 switch (event.type()) {
242 case GROUP_ADD_REQUESTED:
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800243 log.debug("GROUP_ADD_REQUESTED for Group {} on device {}",
244 group.id(), group.deviceId());
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800245 GroupOperation groupAddOp = GroupOperation.
246 createAddGroupOperation(group.id(),
247 group.type(),
248 group.buckets());
249 groupOps = new GroupOperations(
250 Arrays.asList(groupAddOp));
251 groupProvider.performGroupOperation(group.deviceId(), groupOps);
252 break;
253
254 case GROUP_UPDATE_REQUESTED:
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800255 log.debug("GROUP_UPDATE_REQUESTED for Group {} on device {}",
256 group.id(), group.deviceId());
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800257 GroupOperation groupModifyOp = GroupOperation.
258 createModifyGroupOperation(group.id(),
259 group.type(),
260 group.buckets());
261 groupOps = new GroupOperations(
262 Arrays.asList(groupModifyOp));
263 groupProvider.performGroupOperation(group.deviceId(), groupOps);
264 break;
265
266 case GROUP_REMOVE_REQUESTED:
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800267 log.debug("GROUP_REMOVE_REQUESTED for Group {} on device {}",
268 group.id(), group.deviceId());
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800269 GroupOperation groupDeleteOp = GroupOperation.
270 createDeleteGroupOperation(group.id(),
271 group.type());
272 groupOps = new GroupOperations(
273 Arrays.asList(groupDeleteOp));
274 groupProvider.performGroupOperation(group.deviceId(), groupOps);
275 break;
276
277 case GROUP_ADDED:
278 case GROUP_UPDATED:
279 case GROUP_REMOVED:
sangho7ff01812015-02-09 16:21:53 -0800280 case GROUP_ADD_FAILED:
281 case GROUP_UPDATE_FAILED:
282 case GROUP_REMOVE_FAILED:
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800283 eventDispatcher.post(event);
284 break;
285
286 default:
287 break;
288 }
289 }
290 }
291
292 private class InternalGroupProviderService
293 extends AbstractProviderService<GroupProvider>
294 implements GroupProviderService {
295
296 protected InternalGroupProviderService(GroupProvider provider) {
297 super(provider);
298 }
299
300 @Override
sangho7ff01812015-02-09 16:21:53 -0800301 public void groupOperationFailed(DeviceId deviceId,
302 GroupOperation operation) {
303 store.groupOperationFailed(deviceId, operation);
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800304 }
305
306 private void groupMissing(Group group) {
307 checkValidity();
308 GroupProvider gp = getProvider(group.deviceId());
309 switch (group.state()) {
310 case PENDING_DELETE:
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800311 log.debug("Group {} delete confirmation from device {}",
312 group, group.deviceId());
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800313 store.removeGroupEntry(group);
314 break;
315 case ADDED:
316 case PENDING_ADD:
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800317 log.debug("Group {} is in store but not on device {}",
318 group, group.deviceId());
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800319 GroupOperation groupAddOp = GroupOperation.
320 createAddGroupOperation(group.id(),
321 group.type(),
322 group.buckets());
323 GroupOperations groupOps = new GroupOperations(
324 Arrays.asList(groupAddOp));
325 gp.performGroupOperation(group.deviceId(), groupOps);
326 break;
327 default:
328 log.debug("Group {} has not been installed.", group);
329 break;
330 }
331 }
332
333
334 private void extraneousGroup(Group group) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800335 log.debug("Group {} is on device {} but not in store.",
336 group, group.deviceId());
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800337 checkValidity();
338 store.addOrUpdateExtraneousGroupEntry(group);
339 }
340
341 private void groupAdded(Group group) {
342 checkValidity();
343
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800344 log.trace("Group {} Added or Updated in device {}",
345 group, group.deviceId());
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800346 store.addOrUpdateGroupEntry(group);
347 }
348
349 @Override
350 public void pushGroupMetrics(DeviceId deviceId,
351 Collection<Group> groupEntries) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800352 log.trace("Received group metrics from device {}",
353 deviceId);
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800354 boolean deviceInitialAuditStatus =
355 store.deviceInitialAuditStatus(deviceId);
356 Set<Group> southboundGroupEntries =
357 Sets.newHashSet(groupEntries);
358 Set<Group> storedGroupEntries =
359 Sets.newHashSet(store.getGroups(deviceId));
360 Set<Group> extraneousStoredEntries =
361 Sets.newHashSet(store.getExtraneousGroups(deviceId));
362
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800363 log.trace("Displaying all southboundGroupEntries for device {}", deviceId);
364 for (Iterator<Group> it = southboundGroupEntries.iterator(); it.hasNext();) {
365 Group group = it.next();
366 log.trace("Group {} in device {}", group, deviceId);
367 }
368
369 log.trace("Displaying all stored group entries for device {}", deviceId);
370 for (Iterator<Group> it = storedGroupEntries.iterator(); it.hasNext();) {
371 Group group = it.next();
372 log.trace("Stored Group {} for device {}", group, deviceId);
373 }
374
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800375 for (Iterator<Group> it = southboundGroupEntries.iterator(); it.hasNext();) {
376 Group group = it.next();
377 if (storedGroupEntries.remove(group)) {
378 // we both have the group, let's update some info then.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800379 log.trace("Group AUDIT: group {} exists "
380 + "in both planes for device {}",
381 group.id(), deviceId);
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800382 groupAdded(group);
383 it.remove();
384 }
385 }
386 for (Group group : southboundGroupEntries) {
387 // there are groups in the switch that aren't in the store
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800388 log.trace("Group AUDIT: extraneous group {} exists "
389 + "in data plane for device {}",
390 group.id(), deviceId);
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800391 extraneousStoredEntries.remove(group);
392 extraneousGroup(group);
393 }
394 for (Group group : storedGroupEntries) {
395 // there are groups in the store that aren't in the switch
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800396 log.trace("Group AUDIT: group {} missing "
397 + "in data plane for device {}",
398 group.id(), deviceId);
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800399 groupMissing(group);
400 }
401 for (Group group : extraneousStoredEntries) {
402 // there are groups in the extraneous store that
403 // aren't in the switch
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800404 log.trace("Group AUDIT: clearing extransoeus group {} "
405 + "from store for device {}",
406 group.id(), deviceId);
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800407 store.removeExtraneousGroupEntry(group);
408 }
409
410 if (!deviceInitialAuditStatus) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800411 log.debug("Group AUDIT: Setting device {} initial "
412 + "AUDIT completed", deviceId);
413 store.deviceInitialAuditCompleted(deviceId, true);
414 }
415 }
416 }
417
418 private class InternalDeviceListener implements DeviceListener {
419
420 @Override
421 public void event(DeviceEvent event) {
422 switch (event.type()) {
423 case DEVICE_REMOVED:
424 log.debug("Clearing device {} initial "
425 + "AUDIT completed status as device is going down",
426 event.subject().id());
427 store.deviceInitialAuditCompleted(event.subject().id(), false);
428 break;
429
430 default:
431 break;
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800432 }
433 }
434 }
435}