blob: 6601cbf500e4f3a43fbaa0da1b3e2d2b34e2d9b6 [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 Vavilapalli717361f2015-03-16 12:06:04 -070018import static org.slf4j.LoggerFactory.getLogger;
19
20import java.util.Arrays;
21import java.util.Collection;
22import java.util.Iterator;
23import java.util.Set;
24
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -080025import 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
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -070057import com.google.common.collect.Sets;
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -080058
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) {
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700107 log.trace("In addGroup API");
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800108 store.storeGroupDescription(groupDesc);
109 }
110
111 /**
112 * Return a group object associated to an application cookie.
113 *
114 * NOTE1: The presence of group object in the system does not
115 * guarantee that the "group" is actually created in device.
116 * GROUP_ADDED notification would confirm the creation of
117 * this group in data plane.
118 *
119 * @param deviceId device identifier
120 * @param appCookie application cookie to be used for lookup
121 * @return group associated with the application cookie or
122 * NULL if Group is not found for the provided cookie
123 */
124 @Override
125 public Group getGroup(DeviceId deviceId, GroupKey appCookie) {
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700126 log.trace("In getGroup API");
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800127 return store.getGroup(deviceId, appCookie);
128 }
129
130 /**
131 * Append buckets to existing group. The caller can optionally
132 * associate a new cookie during this updation. GROUP_UPDATED or
133 * GROUP_UPDATE_FAILED notifications would be provided along with
134 * cookie depending on the result of the operation on the device.
135 *
136 * @param deviceId device identifier
137 * @param oldCookie cookie to be used to retrieve the existing group
138 * @param buckets immutable list of group bucket to be added
139 * @param newCookie immutable cookie to be used post update operation
140 * @param appId Application Id
141 */
142 @Override
143 public void addBucketsToGroup(DeviceId deviceId,
144 GroupKey oldCookie,
145 GroupBuckets buckets,
146 GroupKey newCookie,
147 ApplicationId appId) {
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700148 log.trace("In addBucketsToGroup API");
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800149 store.updateGroupDescription(deviceId,
150 oldCookie,
151 UpdateType.ADD,
152 buckets,
153 newCookie);
154 }
155
156 /**
157 * Remove buckets from existing group. The caller can optionally
158 * associate a new cookie during this updation. GROUP_UPDATED or
159 * GROUP_UPDATE_FAILED notifications would be provided along with
160 * cookie depending on the result of the operation on the device.
161 *
162 * @param deviceId device identifier
163 * @param oldCookie cookie to be used to retrieve the existing group
164 * @param buckets immutable list of group bucket to be removed
165 * @param newCookie immutable cookie to be used post update operation
166 * @param appId Application Id
167 */
168 @Override
169 public void removeBucketsFromGroup(DeviceId deviceId,
170 GroupKey oldCookie,
171 GroupBuckets buckets,
172 GroupKey newCookie,
173 ApplicationId appId) {
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700174 log.trace("In removeBucketsFromGroup API");
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800175 store.updateGroupDescription(deviceId,
176 oldCookie,
177 UpdateType.REMOVE,
178 buckets,
179 newCookie);
180 }
181
182 /**
183 * Delete a group associated to an application cookie.
184 * GROUP_DELETED or GROUP_DELETE_FAILED notifications would be
185 * provided along with cookie depending on the result of the
186 * operation on the device.
187 *
188 * @param deviceId device identifier
189 * @param appCookie application cookie to be used for lookup
190 * @param appId Application Id
191 */
192 @Override
193 public void removeGroup(DeviceId deviceId,
194 GroupKey appCookie,
195 ApplicationId appId) {
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700196 log.trace("In removeGroup API");
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800197 store.deleteGroupDescription(deviceId, appCookie);
198 }
199
200 /**
201 * Retrieve all groups created by an application in the specified device
202 * as seen by current controller instance.
203 *
204 * @param deviceId device identifier
205 * @param appId application id
206 * @return collection of immutable group objects created by the application
207 */
208 @Override
209 public Iterable<Group> getGroups(DeviceId deviceId,
210 ApplicationId appId) {
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700211 log.trace("In getGroups API");
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800212 return store.getGroups(deviceId);
213 }
214
Jonathan Hart32600692015-03-09 10:38:40 -0700215 @Override
216 public Iterable<Group> getGroups(DeviceId deviceId) {
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700217 log.trace("In getGroups API");
Jonathan Hart32600692015-03-09 10:38:40 -0700218 return store.getGroups(deviceId);
219 }
220
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800221 /**
222 * Adds the specified group listener.
223 *
224 * @param listener group listener
225 */
226 @Override
227 public void addListener(GroupListener listener) {
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700228 log.trace("In addListener API");
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800229 listenerRegistry.addListener(listener);
230 }
231
232 /**
233 * Removes the specified group listener.
234 *
235 * @param listener group listener
236 */
237 @Override
238 public void removeListener(GroupListener listener) {
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700239 log.trace("In removeListener API");
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800240 listenerRegistry.removeListener(listener);
241 }
242
243 @Override
244 protected GroupProviderService createProviderService(GroupProvider provider) {
245 return new InternalGroupProviderService(provider);
246 }
247
248 private class InternalGroupStoreDelegate implements GroupStoreDelegate {
249 @Override
250 public void notify(GroupEvent event) {
251 final Group group = event.subject();
252 GroupProvider groupProvider =
253 getProvider(group.deviceId());
254 GroupOperations groupOps = null;
255 switch (event.type()) {
256 case GROUP_ADD_REQUESTED:
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800257 log.debug("GROUP_ADD_REQUESTED for Group {} on device {}",
258 group.id(), group.deviceId());
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800259 GroupOperation groupAddOp = GroupOperation.
260 createAddGroupOperation(group.id(),
261 group.type(),
262 group.buckets());
263 groupOps = new GroupOperations(
264 Arrays.asList(groupAddOp));
265 groupProvider.performGroupOperation(group.deviceId(), groupOps);
266 break;
267
268 case GROUP_UPDATE_REQUESTED:
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800269 log.debug("GROUP_UPDATE_REQUESTED for Group {} on device {}",
270 group.id(), group.deviceId());
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800271 GroupOperation groupModifyOp = GroupOperation.
272 createModifyGroupOperation(group.id(),
273 group.type(),
274 group.buckets());
275 groupOps = new GroupOperations(
276 Arrays.asList(groupModifyOp));
277 groupProvider.performGroupOperation(group.deviceId(), groupOps);
278 break;
279
280 case GROUP_REMOVE_REQUESTED:
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800281 log.debug("GROUP_REMOVE_REQUESTED for Group {} on device {}",
282 group.id(), group.deviceId());
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800283 GroupOperation groupDeleteOp = GroupOperation.
284 createDeleteGroupOperation(group.id(),
285 group.type());
286 groupOps = new GroupOperations(
287 Arrays.asList(groupDeleteOp));
288 groupProvider.performGroupOperation(group.deviceId(), groupOps);
289 break;
290
291 case GROUP_ADDED:
292 case GROUP_UPDATED:
293 case GROUP_REMOVED:
sangho7ff01812015-02-09 16:21:53 -0800294 case GROUP_ADD_FAILED:
295 case GROUP_UPDATE_FAILED:
296 case GROUP_REMOVE_FAILED:
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800297 eventDispatcher.post(event);
298 break;
299
300 default:
301 break;
302 }
303 }
304 }
305
306 private class InternalGroupProviderService
307 extends AbstractProviderService<GroupProvider>
308 implements GroupProviderService {
309
310 protected InternalGroupProviderService(GroupProvider provider) {
311 super(provider);
312 }
313
314 @Override
sangho7ff01812015-02-09 16:21:53 -0800315 public void groupOperationFailed(DeviceId deviceId,
316 GroupOperation operation) {
317 store.groupOperationFailed(deviceId, operation);
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800318 }
319
320 private void groupMissing(Group group) {
321 checkValidity();
322 GroupProvider gp = getProvider(group.deviceId());
323 switch (group.state()) {
324 case PENDING_DELETE:
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800325 log.debug("Group {} delete confirmation from device {}",
326 group, group.deviceId());
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800327 store.removeGroupEntry(group);
328 break;
329 case ADDED:
330 case PENDING_ADD:
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800331 log.debug("Group {} is in store but not on device {}",
332 group, group.deviceId());
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800333 GroupOperation groupAddOp = GroupOperation.
334 createAddGroupOperation(group.id(),
335 group.type(),
336 group.buckets());
337 GroupOperations groupOps = new GroupOperations(
338 Arrays.asList(groupAddOp));
339 gp.performGroupOperation(group.deviceId(), groupOps);
340 break;
341 default:
342 log.debug("Group {} has not been installed.", group);
343 break;
344 }
345 }
346
347
348 private void extraneousGroup(Group group) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800349 log.debug("Group {} is on device {} but not in store.",
350 group, group.deviceId());
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800351 checkValidity();
352 store.addOrUpdateExtraneousGroupEntry(group);
353 }
354
355 private void groupAdded(Group group) {
356 checkValidity();
357
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800358 log.trace("Group {} Added or Updated in device {}",
359 group, group.deviceId());
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800360 store.addOrUpdateGroupEntry(group);
361 }
362
363 @Override
364 public void pushGroupMetrics(DeviceId deviceId,
365 Collection<Group> groupEntries) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800366 log.trace("Received group metrics from device {}",
367 deviceId);
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800368 boolean deviceInitialAuditStatus =
369 store.deviceInitialAuditStatus(deviceId);
370 Set<Group> southboundGroupEntries =
371 Sets.newHashSet(groupEntries);
372 Set<Group> storedGroupEntries =
373 Sets.newHashSet(store.getGroups(deviceId));
374 Set<Group> extraneousStoredEntries =
375 Sets.newHashSet(store.getExtraneousGroups(deviceId));
376
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700377 log.trace("Displaying all ({}) southboundGroupEntries for device {}",
378 southboundGroupEntries.size(),
379 deviceId);
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800380 for (Iterator<Group> it = southboundGroupEntries.iterator(); it.hasNext();) {
381 Group group = it.next();
382 log.trace("Group {} in device {}", group, deviceId);
383 }
384
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700385 log.trace("Displaying all ({}) stored group entries for device {}",
386 storedGroupEntries.size(),
387 deviceId);
388 for (Iterator<Group> it1 = storedGroupEntries.iterator(); it1.hasNext();) {
389 Group group = it1.next();
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800390 log.trace("Stored Group {} for device {}", group, deviceId);
391 }
392
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700393 for (Iterator<Group> it2 = southboundGroupEntries.iterator(); it2.hasNext();) {
394 Group group = it2.next();
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800395 if (storedGroupEntries.remove(group)) {
396 // we both have the group, let's update some info then.
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800397 log.trace("Group AUDIT: group {} exists "
398 + "in both planes for device {}",
399 group.id(), deviceId);
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800400 groupAdded(group);
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700401 it2.remove();
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800402 }
403 }
404 for (Group group : southboundGroupEntries) {
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700405 if (store.getGroup(group.deviceId(), group.id()) != null) {
406 // There is a group existing with the same id
407 // It is possible that group update is
408 // in progress while we got a stale info from switch
409 if (!storedGroupEntries.remove(store.getGroup(
410 group.deviceId(), group.id()))) {
411 log.warn("Group AUDIT: Inconsistent state:"
412 + "Group exists in ID based table while "
413 + "not present in key based table");
414 }
415 } else {
416 // there are groups in the switch that aren't in the store
417 log.trace("Group AUDIT: extraneous group {} exists "
418 + "in data plane for device {}",
419 group.id(), deviceId);
420 extraneousStoredEntries.remove(group);
421 extraneousGroup(group);
422 }
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800423 }
424 for (Group group : storedGroupEntries) {
425 // there are groups in the store that aren't in the switch
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800426 log.trace("Group AUDIT: group {} missing "
427 + "in data plane for device {}",
428 group.id(), deviceId);
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800429 groupMissing(group);
430 }
431 for (Group group : extraneousStoredEntries) {
432 // there are groups in the extraneous store that
433 // aren't in the switch
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800434 log.trace("Group AUDIT: clearing extransoeus group {} "
435 + "from store for device {}",
436 group.id(), deviceId);
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800437 store.removeExtraneousGroupEntry(group);
438 }
439
440 if (!deviceInitialAuditStatus) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800441 log.debug("Group AUDIT: Setting device {} initial "
442 + "AUDIT completed", deviceId);
443 store.deviceInitialAuditCompleted(deviceId, true);
444 }
445 }
446 }
447
448 private class InternalDeviceListener implements DeviceListener {
449
450 @Override
451 public void event(DeviceEvent event) {
452 switch (event.type()) {
453 case DEVICE_REMOVED:
454 log.debug("Clearing device {} initial "
455 + "AUDIT completed status as device is going down",
456 event.subject().id());
457 store.deviceInitialAuditCompleted(event.subject().id(), false);
458 break;
459
460 default:
461 break;
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800462 }
463 }
464 }
465}