blob: 352059af5ea36e1f36b9564d545422cfd04fd520 [file] [log] [blame]
/*
* Copyright 2015 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.net.group.impl;
import static org.slf4j.LoggerFactory.getLogger;
import java.util.Collection;
import java.util.Collections;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.Service;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.Permission;
import org.onosproject.event.EventDeliveryService;
import org.onosproject.event.ListenerRegistry;
import org.onosproject.net.DeviceId;
import org.onosproject.net.device.DeviceEvent;
import org.onosproject.net.device.DeviceListener;
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.group.Group;
import org.onosproject.net.group.GroupBuckets;
import org.onosproject.net.group.GroupDescription;
import org.onosproject.net.group.GroupEvent;
import org.onosproject.net.group.GroupKey;
import org.onosproject.net.group.GroupListener;
import org.onosproject.net.group.GroupOperation;
import org.onosproject.net.group.GroupOperations;
import org.onosproject.net.group.GroupProvider;
import org.onosproject.net.group.GroupProviderRegistry;
import org.onosproject.net.group.GroupProviderService;
import org.onosproject.net.group.GroupService;
import org.onosproject.net.group.GroupStore;
import org.onosproject.net.group.GroupStore.UpdateType;
import org.onosproject.net.group.GroupStoreDelegate;
import org.onosproject.net.provider.AbstractProviderRegistry;
import org.onosproject.net.provider.AbstractProviderService;
import org.slf4j.Logger;
import static org.onosproject.security.AppGuard.checkPermission;
/**
* Provides implementation of the group service APIs.
*/
@Component(immediate = true)
@Service
public class GroupManager
extends AbstractProviderRegistry<GroupProvider, GroupProviderService>
implements GroupService, GroupProviderRegistry {
private final Logger log = getLogger(getClass());
private final ListenerRegistry<GroupEvent, GroupListener>
listenerRegistry = new ListenerRegistry<>();
private final GroupStoreDelegate delegate = new InternalGroupStoreDelegate();
private final DeviceListener deviceListener = new InternalDeviceListener();
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected GroupStore store;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected DeviceService deviceService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected EventDeliveryService eventDispatcher;
@Activate
public void activate() {
store.setDelegate(delegate);
eventDispatcher.addSink(GroupEvent.class, listenerRegistry);
deviceService.addListener(deviceListener);
log.info("Started");
}
@Deactivate
public void deactivate() {
store.unsetDelegate(delegate);
eventDispatcher.removeSink(GroupEvent.class);
log.info("Stopped");
}
/**
* Create a group in the specified device with the provided parameters.
*
* @param groupDesc group creation parameters
*
*/
@Override
public void addGroup(GroupDescription groupDesc) {
checkPermission(Permission.GROUP_WRITE);
log.trace("In addGroup API");
store.storeGroupDescription(groupDesc);
}
/**
* Return a group object associated to an application cookie.
*
* NOTE1: The presence of group object in the system does not
* guarantee that the "group" is actually created in device.
* GROUP_ADDED notification would confirm the creation of
* this group in data plane.
*
* @param deviceId device identifier
* @param appCookie application cookie to be used for lookup
* @return group associated with the application cookie or
* NULL if Group is not found for the provided cookie
*/
@Override
public Group getGroup(DeviceId deviceId, GroupKey appCookie) {
checkPermission(Permission.GROUP_READ);
log.trace("In getGroup API");
return store.getGroup(deviceId, appCookie);
}
/**
* Append buckets to existing group. The caller can optionally
* associate a new cookie during this updation. GROUP_UPDATED or
* GROUP_UPDATE_FAILED notifications would be provided along with
* cookie depending on the result of the operation on the device.
*
* @param deviceId device identifier
* @param oldCookie cookie to be used to retrieve the existing group
* @param buckets immutable list of group bucket to be added
* @param newCookie immutable cookie to be used post update operation
* @param appId Application Id
*/
@Override
public void addBucketsToGroup(DeviceId deviceId,
GroupKey oldCookie,
GroupBuckets buckets,
GroupKey newCookie,
ApplicationId appId) {
checkPermission(Permission.GROUP_WRITE);
log.trace("In addBucketsToGroup API");
store.updateGroupDescription(deviceId,
oldCookie,
UpdateType.ADD,
buckets,
newCookie);
}
/**
* Remove buckets from existing group. The caller can optionally
* associate a new cookie during this updation. GROUP_UPDATED or
* GROUP_UPDATE_FAILED notifications would be provided along with
* cookie depending on the result of the operation on the device.
*
* @param deviceId device identifier
* @param oldCookie cookie to be used to retrieve the existing group
* @param buckets immutable list of group bucket to be removed
* @param newCookie immutable cookie to be used post update operation
* @param appId Application Id
*/
@Override
public void removeBucketsFromGroup(DeviceId deviceId,
GroupKey oldCookie,
GroupBuckets buckets,
GroupKey newCookie,
ApplicationId appId) {
checkPermission(Permission.GROUP_WRITE);
log.trace("In removeBucketsFromGroup API");
store.updateGroupDescription(deviceId,
oldCookie,
UpdateType.REMOVE,
buckets,
newCookie);
}
/**
* Delete a group associated to an application cookie.
* GROUP_DELETED or GROUP_DELETE_FAILED notifications would be
* provided along with cookie depending on the result of the
* operation on the device.
*
* @param deviceId device identifier
* @param appCookie application cookie to be used for lookup
* @param appId Application Id
*/
@Override
public void removeGroup(DeviceId deviceId,
GroupKey appCookie,
ApplicationId appId) {
checkPermission(Permission.GROUP_WRITE);
log.trace("In removeGroup API");
store.deleteGroupDescription(deviceId, appCookie);
}
/**
* Retrieve all groups created by an application in the specified device
* as seen by current controller instance.
*
* @param deviceId device identifier
* @param appId application id
* @return collection of immutable group objects created by the application
*/
@Override
public Iterable<Group> getGroups(DeviceId deviceId,
ApplicationId appId) {
checkPermission(Permission.GROUP_READ);
log.trace("In getGroups API");
return store.getGroups(deviceId);
}
@Override
public Iterable<Group> getGroups(DeviceId deviceId) {
checkPermission(Permission.GROUP_READ);
log.trace("In getGroups API");
return store.getGroups(deviceId);
}
/**
* Adds the specified group listener.
*
* @param listener group listener
*/
@Override
public void addListener(GroupListener listener) {
checkPermission(Permission.GROUP_EVENT);
log.trace("In addListener API");
listenerRegistry.addListener(listener);
}
/**
* Removes the specified group listener.
*
* @param listener group listener
*/
@Override
public void removeListener(GroupListener listener) {
checkPermission(Permission.GROUP_EVENT);
log.trace("In removeListener API");
listenerRegistry.removeListener(listener);
}
@Override
protected GroupProviderService createProviderService(GroupProvider provider) {
return new InternalGroupProviderService(provider);
}
private class InternalGroupStoreDelegate implements GroupStoreDelegate {
@Override
public void notify(GroupEvent event) {
final Group group = event.subject();
GroupProvider groupProvider =
getProvider(group.deviceId());
GroupOperations groupOps = null;
switch (event.type()) {
case GROUP_ADD_REQUESTED:
log.debug("GROUP_ADD_REQUESTED for Group {} on device {}",
group.id(), group.deviceId());
GroupOperation groupAddOp = GroupOperation.
createAddGroupOperation(group.id(),
group.type(),
group.buckets());
groupOps = new GroupOperations(
Collections.singletonList(groupAddOp));
groupProvider.performGroupOperation(group.deviceId(), groupOps);
break;
case GROUP_UPDATE_REQUESTED:
log.debug("GROUP_UPDATE_REQUESTED for Group {} on device {}",
group.id(), group.deviceId());
GroupOperation groupModifyOp = GroupOperation.
createModifyGroupOperation(group.id(),
group.type(),
group.buckets());
groupOps = new GroupOperations(
Collections.singletonList(groupModifyOp));
groupProvider.performGroupOperation(group.deviceId(), groupOps);
break;
case GROUP_REMOVE_REQUESTED:
log.debug("GROUP_REMOVE_REQUESTED for Group {} on device {}",
group.id(), group.deviceId());
GroupOperation groupDeleteOp = GroupOperation.
createDeleteGroupOperation(group.id(),
group.type());
groupOps = new GroupOperations(
Collections.singletonList(groupDeleteOp));
groupProvider.performGroupOperation(group.deviceId(), groupOps);
break;
case GROUP_ADDED:
case GROUP_UPDATED:
case GROUP_REMOVED:
case GROUP_ADD_FAILED:
case GROUP_UPDATE_FAILED:
case GROUP_REMOVE_FAILED:
eventDispatcher.post(event);
break;
default:
break;
}
}
}
private class InternalGroupProviderService
extends AbstractProviderService<GroupProvider>
implements GroupProviderService {
protected InternalGroupProviderService(GroupProvider provider) {
super(provider);
}
@Override
public void groupOperationFailed(DeviceId deviceId,
GroupOperation operation) {
store.groupOperationFailed(deviceId, operation);
}
@Override
public void pushGroupMetrics(DeviceId deviceId,
Collection<Group> groupEntries) {
log.trace("Received group metrics from device {}",
deviceId);
checkValidity();
store.pushGroupMetrics(deviceId, groupEntries);
}
}
private class InternalDeviceListener implements DeviceListener {
@Override
public void event(DeviceEvent event) {
switch (event.type()) {
case DEVICE_REMOVED:
case DEVICE_AVAILABILITY_CHANGED:
if (!deviceService.isAvailable(event.subject().id())) {
log.debug("GroupService DeviceListener: Received event {}."
+ "Device is no more available."
+ "Clearing device {} initial "
+ "AUDIT completed status",
event.type(),
event.subject().id());
store.deviceInitialAuditCompleted(event.subject().id(), false);
}
break;
default:
break;
}
}
}
}