/* * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.openflowplugin.impl.util; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Function; import com.google.common.base.Preconditions; import com.google.common.collect.Iterables; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; import javax.annotation.Nullable; import org.apache.commons.lang3.tuple.Pair; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupRef; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.AddGroupsBatchOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.AddGroupsBatchOutputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.BatchGroupOutputListGrouping; import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.RemoveGroupsBatchOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.RemoveGroupsBatchOutputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.UpdateGroupsBatchOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.UpdateGroupsBatchOutputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.batch.group.output.list.grouping.BatchFailedGroupsOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.batch.group.output.list.grouping.BatchFailedGroupsOutputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; import org.opendaylight.yangtools.yang.common.RpcError; import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.common.RpcResultBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.ActionType; /** * provides group util methods */ public final class GroupUtil { private static final RpcResultBuilder<List<BatchFailedGroupsOutput>> SUCCESSFUL_GROUP_OUTPUT_RPC_RESULT = RpcResultBuilder.success(Collections.<BatchFailedGroupsOutput>emptyList()); public static final Function<RpcResult<List<BatchFailedGroupsOutput>>, RpcResult<AddGroupsBatchOutput>> GROUP_ADD_TRANSFORM = new Function<RpcResult<List<BatchFailedGroupsOutput>>, RpcResult<AddGroupsBatchOutput>>() { @Nullable @Override public RpcResult<AddGroupsBatchOutput> apply(@Nullable final RpcResult<List<BatchFailedGroupsOutput>> batchGroupsCumulatedResult) { final AddGroupsBatchOutput batchOutput = new AddGroupsBatchOutputBuilder() .setBatchFailedGroupsOutput(batchGroupsCumulatedResult.getResult()).build(); final RpcResultBuilder<AddGroupsBatchOutput> resultBld = createCumulativeRpcResult(batchGroupsCumulatedResult, batchOutput); return resultBld.build(); } }; public static final Function<Pair<RpcResult<AddGroupsBatchOutput>, RpcResult<Void>>, RpcResult<AddGroupsBatchOutput>> GROUP_ADD_COMPOSING_TRANSFORM = createComposingFunction(); public static final Function<RpcResult<List<BatchFailedGroupsOutput>>, RpcResult<RemoveGroupsBatchOutput>> GROUP_REMOVE_TRANSFORM = new Function<RpcResult<List<BatchFailedGroupsOutput>>, RpcResult<RemoveGroupsBatchOutput>>() { @Nullable @Override public RpcResult<RemoveGroupsBatchOutput> apply(@Nullable final RpcResult<List<BatchFailedGroupsOutput>> batchGroupsCumulatedResult) { final RemoveGroupsBatchOutput batchOutput = new RemoveGroupsBatchOutputBuilder() .setBatchFailedGroupsOutput(batchGroupsCumulatedResult.getResult()).build(); final RpcResultBuilder<RemoveGroupsBatchOutput> resultBld = createCumulativeRpcResult(batchGroupsCumulatedResult, batchOutput); return resultBld.build(); } }; public static final Function<Pair<RpcResult<RemoveGroupsBatchOutput>, RpcResult<Void>>, RpcResult<RemoveGroupsBatchOutput>> GROUP_REMOVE_COMPOSING_TRANSFORM = createComposingFunction(); public static final Function<RpcResult<List<BatchFailedGroupsOutput>>, RpcResult<UpdateGroupsBatchOutput>> GROUP_UPDATE_TRANSFORM = new Function<RpcResult<List<BatchFailedGroupsOutput>>, RpcResult<UpdateGroupsBatchOutput>>() { @Nullable @Override public RpcResult<UpdateGroupsBatchOutput> apply(@Nullable final RpcResult<List<BatchFailedGroupsOutput>> batchGroupsCumulatedResult) { final UpdateGroupsBatchOutput batchOutput = new UpdateGroupsBatchOutputBuilder() .setBatchFailedGroupsOutput(batchGroupsCumulatedResult.getResult()).build(); final RpcResultBuilder<UpdateGroupsBatchOutput> resultBld = createCumulativeRpcResult(batchGroupsCumulatedResult, batchOutput); return resultBld.build(); } }; public static final Function<Pair<RpcResult<UpdateGroupsBatchOutput>, RpcResult<Void>>, RpcResult<UpdateGroupsBatchOutput>> GROUP_UPDATE_COMPOSING_TRANSFORM = createComposingFunction(); private GroupUtil() { throw new IllegalStateException("This class should not be instantiated."); } /** * @param nodePath * @param groupId * @return instance identifier assembled for given node and group */ public static GroupRef buildGroupPath(final InstanceIdentifier<Node> nodePath, final GroupId groupId) { final KeyedInstanceIdentifier<Group, GroupKey> groupPath = nodePath .augmentation(FlowCapableNode.class) .child(Group.class, new GroupKey(groupId)); return new GroupRef(groupPath); } public static <O> Function<List<RpcResult<O>>, RpcResult<List<BatchFailedGroupsOutput>>> createCumulatingFunction( final Iterable<? extends org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.Group> inputBatchGroups) { return createCumulatingFunction(inputBatchGroups, Iterables.size(inputBatchGroups)); } public static <O> Function<List<RpcResult<O>>, RpcResult<List<BatchFailedGroupsOutput>>> createCumulatingFunction( final Iterable<? extends org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.Group> inputBatchGroups, final int sizeOfInputBatch) { return new CumulatingFunction<O>(inputBatchGroups, sizeOfInputBatch).invoke(); } /* * Method returns the bitmap of actions supported by each group. * * @param actionsSupported * @return */ public static List<Long> extractGroupActionsSupportBitmap(final List<ActionType> actionsSupported) { List<Long> supportActionByGroups = new ArrayList<>(); for (org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.ActionType supportedActions : actionsSupported) { long supportActionBitmap = 0; supportActionBitmap |= supportedActions.isOFPATOUTPUT() ? (1) : 0; supportActionBitmap |= supportedActions.isOFPATCOPYTTLOUT() ? (1 << 11) : 0; supportActionBitmap |= supportedActions.isOFPATCOPYTTLIN() ? (1 << 12) : 0; supportActionBitmap |= supportedActions.isOFPATSETMPLSTTL() ? (1 << 15) : 0; supportActionBitmap |= supportedActions.isOFPATDECMPLSTTL() ? (1 << 16) : 0; supportActionBitmap |= supportedActions.isOFPATPUSHVLAN() ? (1 << 17) : 0; supportActionBitmap |= supportedActions.isOFPATPOPVLAN() ? (1 << 18) : 0; supportActionBitmap |= supportedActions.isOFPATPUSHMPLS() ? (1 << 19) : 0; supportActionBitmap |= supportedActions.isOFPATPOPMPLS() ? (1 << 20) : 0; supportActionBitmap |= supportedActions.isOFPATSETQUEUE() ? (1 << 21) : 0; supportActionBitmap |= supportedActions.isOFPATGROUP() ? (1 << 22) : 0; supportActionBitmap |= supportedActions.isOFPATSETNWTTL() ? (1 << 23) : 0; supportActionBitmap |= supportedActions.isOFPATDECNWTTL() ? (1 << 24) : 0; supportActionBitmap |= supportedActions.isOFPATSETFIELD() ? (1 << 25) : 0; supportActionBitmap |= supportedActions.isOFPATPUSHPBB() ? (1 << 26) : 0; supportActionBitmap |= supportedActions.isOFPATPOPPBB() ? (1 << 27) : 0; supportActionByGroups.add(supportActionBitmap); } return supportActionByGroups; } /** * Factory method: create {@link Function} which attaches barrier response to given {@link RpcResult}<T> * and changes success flag if needed. * <br> * Original rpcResult is the {@link Pair#getLeft()} and barrier result is the {@link Pair#getRight()}. * * @param <T> type of rpcResult value * @return reusable static function */ @VisibleForTesting static <T extends BatchGroupOutputListGrouping> Function<Pair<RpcResult<T>, RpcResult<Void>>, RpcResult<T>> createComposingFunction() { return new Function<Pair<RpcResult<T>, RpcResult<Void>>, RpcResult<T>>() { @Nullable @Override public RpcResult<T> apply(@Nullable final Pair<RpcResult<T>, RpcResult<Void>> input) { final RpcResultBuilder<T> resultBld; if (input.getLeft().isSuccessful() && input.getRight().isSuccessful()) { resultBld = RpcResultBuilder.success(); } else { resultBld = RpcResultBuilder.failed(); } final ArrayList<RpcError> rpcErrors = new ArrayList<>(input.getLeft().getErrors()); rpcErrors.addAll(input.getRight().getErrors()); resultBld.withRpcErrors(rpcErrors); resultBld.withResult(input.getLeft().getResult()); return resultBld.build(); } }; } /** * Wrap given list of problematic group-ids into {@link RpcResult} of given type. * * @param batchGroupsCumulativeResult list of ids failed groups * @param batchOutput * @param <T> group operation type * @return batch group operation output of given type containing list of group-ids and corresponding success flag */ private static <T extends BatchGroupOutputListGrouping> RpcResultBuilder<T> createCumulativeRpcResult(@Nullable final RpcResult<List<BatchFailedGroupsOutput>> batchGroupsCumulativeResult, final T batchOutput) { final RpcResultBuilder<T> resultBld; if (batchGroupsCumulativeResult.isSuccessful()) { resultBld = RpcResultBuilder.success(batchOutput); } else { resultBld = RpcResultBuilder.failed(); resultBld.withResult(batchOutput) .withRpcErrors(batchGroupsCumulativeResult.getErrors()); } return resultBld; } private static class CumulatingFunction<O> { private final Iterable<? extends org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.Group> inputBatchGroups; private final int sizeOfInputBatch; public CumulatingFunction(Iterable<? extends org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.Group> inputBatchGroups, int sizeOfInputBatch) { this.inputBatchGroups = inputBatchGroups; this.sizeOfInputBatch = sizeOfInputBatch; } public Function<List<RpcResult<O>>, RpcResult<List<BatchFailedGroupsOutput>>> invoke() { return new Function<List<RpcResult<O>>, RpcResult<List<BatchFailedGroupsOutput>>>() { @Nullable @Override public RpcResult<List<BatchFailedGroupsOutput>> apply(@Nullable final List<RpcResult<O>> innerInput) { final int sizeOfFutures = innerInput.size(); Preconditions.checkArgument(sizeOfFutures == sizeOfInputBatch, "wrong amount of returned futures: {} <> {}", sizeOfFutures, sizeOfInputBatch); final List<BatchFailedGroupsOutput> batchGroups = new ArrayList<>(); final Iterator<? extends org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.Group> batchGroupIterator = inputBatchGroups.iterator(); Collection<RpcError> groupErrors = new ArrayList<>(sizeOfFutures); int batchOrder = 0; for (RpcResult<O> groupModOutput : innerInput) { final GroupId groupId = batchGroupIterator.next().getGroupId(); if (!groupModOutput.isSuccessful()) { batchGroups.add(new BatchFailedGroupsOutputBuilder() .setGroupId(groupId) .setBatchOrder(batchOrder) .build()); groupErrors.addAll(groupModOutput.getErrors()); } batchOrder++; } final RpcResultBuilder<List<BatchFailedGroupsOutput>> resultBuilder; if (!groupErrors.isEmpty()) { resultBuilder = RpcResultBuilder.<List<BatchFailedGroupsOutput>>failed() .withRpcErrors(groupErrors).withResult(batchGroups); } else { resultBuilder = SUCCESSFUL_GROUP_OUTPUT_RPC_RESULT; } return resultBuilder.build(); } }; } } }