Merge "Spec: OFPGC_ADD_OR_MOD support in openflowplugin"
[openflowplugin.git] / openflowplugin-impl / src / main / java / org / opendaylight / openflowplugin / impl / util / GroupUtil.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.openflowplugin.impl.util;
10
11 import com.google.common.annotations.VisibleForTesting;
12 import com.google.common.base.Function;
13 import com.google.common.base.Preconditions;
14 import com.google.common.collect.Iterables;
15 import java.util.ArrayList;
16 import java.util.Collection;
17 import java.util.Collections;
18 import java.util.Iterator;
19 import java.util.List;
20 import javax.annotation.Nullable;
21 import org.apache.commons.lang3.tuple.Pair;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupRef;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.AddGroupsBatchOutput;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.AddGroupsBatchOutputBuilder;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.BatchGroupOutputListGrouping;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.RemoveGroupsBatchOutput;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.RemoveGroupsBatchOutputBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.UpdateGroupsBatchOutput;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.UpdateGroupsBatchOutputBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.batch.group.output.list.grouping.BatchFailedGroupsOutput;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.batch.group.output.list.grouping.BatchFailedGroupsOutputBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.ActionType;
38 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
39 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
40 import org.opendaylight.yangtools.yang.common.RpcError;
41 import org.opendaylight.yangtools.yang.common.RpcResult;
42 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
43
44 /**
45  * Provides group util methods.
46  */
47 public final class GroupUtil {
48
49     private static final RpcResultBuilder<List<BatchFailedGroupsOutput>> SUCCESSFUL_GROUP_OUTPUT_RPC_RESULT =
50             RpcResultBuilder.success(Collections.<BatchFailedGroupsOutput>emptyList());
51
52     public static final Function<RpcResult<List<BatchFailedGroupsOutput>>, RpcResult<AddGroupsBatchOutput>>
53         GROUP_ADD_TRANSFORM =
54         new Function<RpcResult<List<BatchFailedGroupsOutput>>, RpcResult<AddGroupsBatchOutput>>() {
55             @Nullable
56             @Override
57             public RpcResult<AddGroupsBatchOutput> apply(
58                     @Nullable final RpcResult<List<BatchFailedGroupsOutput>> batchGroupsCumulatedResult) {
59                 final AddGroupsBatchOutput batchOutput = new AddGroupsBatchOutputBuilder()
60                         .setBatchFailedGroupsOutput(batchGroupsCumulatedResult.getResult()).build();
61
62                 final RpcResultBuilder<AddGroupsBatchOutput> resultBld =
63                         createCumulativeRpcResult(batchGroupsCumulatedResult, batchOutput);
64                 return resultBld.build();
65             }
66         };
67     public static final Function<Pair<RpcResult<AddGroupsBatchOutput>,
68                                  RpcResult<Void>>,
69                                  RpcResult<AddGroupsBatchOutput>>
70         GROUP_ADD_COMPOSING_TRANSFORM = createComposingFunction();
71
72     public static final Function<RpcResult<List<BatchFailedGroupsOutput>>, RpcResult<RemoveGroupsBatchOutput>>
73         GROUP_REMOVE_TRANSFORM =
74         new Function<RpcResult<List<BatchFailedGroupsOutput>>, RpcResult<RemoveGroupsBatchOutput>>() {
75             @Nullable
76             @Override
77             public RpcResult<RemoveGroupsBatchOutput> apply(
78                     @Nullable final RpcResult<List<BatchFailedGroupsOutput>> batchGroupsCumulatedResult) {
79                 final RemoveGroupsBatchOutput batchOutput = new RemoveGroupsBatchOutputBuilder()
80                         .setBatchFailedGroupsOutput(batchGroupsCumulatedResult.getResult()).build();
81
82                 final RpcResultBuilder<RemoveGroupsBatchOutput> resultBld =
83                         createCumulativeRpcResult(batchGroupsCumulatedResult, batchOutput);
84                 return resultBld.build();
85             }
86         };
87     public static final Function<Pair<RpcResult<RemoveGroupsBatchOutput>,
88                                       RpcResult<Void>>,
89                                       RpcResult<RemoveGroupsBatchOutput>>
90         GROUP_REMOVE_COMPOSING_TRANSFORM = createComposingFunction();
91
92     public static final Function<RpcResult<List<BatchFailedGroupsOutput>>, RpcResult<UpdateGroupsBatchOutput>>
93         GROUP_UPDATE_TRANSFORM =
94         new Function<RpcResult<List<BatchFailedGroupsOutput>>, RpcResult<UpdateGroupsBatchOutput>>() {
95             @Nullable
96             @Override
97             public RpcResult<UpdateGroupsBatchOutput> apply(
98                     @Nullable final RpcResult<List<BatchFailedGroupsOutput>> batchGroupsCumulatedResult) {
99                 final UpdateGroupsBatchOutput batchOutput = new UpdateGroupsBatchOutputBuilder()
100                         .setBatchFailedGroupsOutput(batchGroupsCumulatedResult.getResult()).build();
101
102                 final RpcResultBuilder<UpdateGroupsBatchOutput> resultBld =
103                         createCumulativeRpcResult(batchGroupsCumulatedResult, batchOutput);
104                 return resultBld.build();
105             }
106         };
107     public static final Function<Pair<RpcResult<UpdateGroupsBatchOutput>,
108                                       RpcResult<Void>>,
109                                       RpcResult<UpdateGroupsBatchOutput>>
110             GROUP_UPDATE_COMPOSING_TRANSFORM = createComposingFunction();
111
112     private GroupUtil() {
113         throw new IllegalStateException("This class should not be instantiated.");
114     }
115
116     /**
117      * Method build the group path.
118      * @param nodePath - node path
119      * @param groupId - group Id
120      * @return instance identifier assembled for given node and group
121      */
122     public static GroupRef buildGroupPath(final InstanceIdentifier<Node> nodePath, final GroupId groupId) {
123         final KeyedInstanceIdentifier<Group, GroupKey> groupPath = nodePath
124                 .augmentation(FlowCapableNode.class)
125                 .child(Group.class, new GroupKey(groupId));
126
127         return new GroupRef(groupPath);
128     }
129
130     public static <O> Function<List<RpcResult<O>>, RpcResult<List<BatchFailedGroupsOutput>>> createCumulatingFunction(
131             final Iterable<? extends org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.Group>
132                     inputBatchGroups) {
133         return createCumulatingFunction(inputBatchGroups, Iterables.size(inputBatchGroups));
134     }
135
136     public static <O> Function<List<RpcResult<O>>, RpcResult<List<BatchFailedGroupsOutput>>> createCumulatingFunction(
137             final Iterable<? extends org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.Group>
138                     inputBatchGroups, final int sizeOfInputBatch) {
139         return new CumulatingFunction<O>(inputBatchGroups, sizeOfInputBatch).invoke();
140     }
141
142     /*
143      * Method returns the bitmap of actions supported by each group.
144      *
145      * @param actionsSupported - list of supported actions
146      * @return
147      */
148     public static List<Long> extractGroupActionsSupportBitmap(final List<ActionType> actionsSupported) {
149         List<Long> supportActionByGroups = new ArrayList<>();
150         for (org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.ActionType supportedActions
151                 : actionsSupported) {
152             long supportActionBitmap = 0;
153             supportActionBitmap |= supportedActions.isOFPATOUTPUT() ? 1 : 0;
154             supportActionBitmap |= supportedActions.isOFPATCOPYTTLOUT() ? 1 << 11 : 0;
155             supportActionBitmap |= supportedActions.isOFPATCOPYTTLIN() ? 1 << 12 : 0;
156             supportActionBitmap |= supportedActions.isOFPATSETMPLSTTL() ? 1 << 15 : 0;
157             supportActionBitmap |= supportedActions.isOFPATDECMPLSTTL() ? 1 << 16 : 0;
158             supportActionBitmap |= supportedActions.isOFPATPUSHVLAN() ? 1 << 17 : 0;
159             supportActionBitmap |= supportedActions.isOFPATPOPVLAN() ? 1 << 18 : 0;
160             supportActionBitmap |= supportedActions.isOFPATPUSHMPLS() ? 1 << 19 : 0;
161             supportActionBitmap |= supportedActions.isOFPATPOPMPLS() ? 1 << 20 : 0;
162             supportActionBitmap |= supportedActions.isOFPATSETQUEUE() ? 1 << 21 : 0;
163             supportActionBitmap |= supportedActions.isOFPATGROUP() ? 1 << 22 : 0;
164             supportActionBitmap |= supportedActions.isOFPATSETNWTTL() ? 1 << 23 : 0;
165             supportActionBitmap |= supportedActions.isOFPATDECNWTTL() ? 1 << 24 : 0;
166             supportActionBitmap |= supportedActions.isOFPATSETFIELD() ? 1 << 25 : 0;
167             supportActionBitmap |= supportedActions.isOFPATPUSHPBB() ? 1 << 26 : 0;
168             supportActionBitmap |= supportedActions.isOFPATPOPPBB() ? 1 << 27 : 0;
169             supportActionByGroups.add(supportActionBitmap);
170         }
171         return supportActionByGroups;
172     }
173
174     /**
175      * Factory method: create {@link Function} which attaches barrier response to given {@link RpcResult}&lt;T&gt;
176      * and changes success flag if needed.
177      * <br>
178      * Original rpcResult is the {@link Pair#getLeft()} and barrier result is the {@link Pair#getRight()}.
179      *
180      * @param <T> type of rpcResult value
181      * @return reusable static function
182      */
183     @VisibleForTesting
184     static <T extends BatchGroupOutputListGrouping> Function<Pair<RpcResult<T>, RpcResult<Void>>, RpcResult<T>>
185         createComposingFunction() {
186         return new Function<Pair<RpcResult<T>, RpcResult<Void>>, RpcResult<T>>() {
187             @Nullable
188             @Override
189             public RpcResult<T> apply(@Nullable final Pair<RpcResult<T>, RpcResult<Void>> input) {
190                 final RpcResultBuilder<T> resultBld;
191                 if (input.getLeft().isSuccessful() && input.getRight().isSuccessful()) {
192                     resultBld = RpcResultBuilder.success();
193                 } else {
194                     resultBld = RpcResultBuilder.failed();
195                 }
196
197                 final ArrayList<RpcError> rpcErrors = new ArrayList<>(input.getLeft().getErrors());
198                 rpcErrors.addAll(input.getRight().getErrors());
199                 resultBld.withRpcErrors(rpcErrors);
200
201                 resultBld.withResult(input.getLeft().getResult());
202
203                 return resultBld.build();
204             }
205         };
206     }
207
208     /**
209      * Wrap given list of problematic group-ids into {@link RpcResult} of given type.
210      *
211      * @param batchGroupsCumulativeResult list of ids failed groups
212      * @param batchOutput group operation type
213      * @return batch group operation output of given type containing list of group-ids and corresponding success flag
214      */
215     private static <T extends BatchGroupOutputListGrouping> RpcResultBuilder<T> createCumulativeRpcResult(
216         final RpcResult<List<BatchFailedGroupsOutput>> batchGroupsCumulativeResult, final T batchOutput) {
217         final RpcResultBuilder<T> resultBld;
218         if (batchGroupsCumulativeResult.isSuccessful()) {
219             resultBld = RpcResultBuilder.success(batchOutput);
220         } else {
221             resultBld = RpcResultBuilder.failed();
222             resultBld.withResult(batchOutput)
223                     .withRpcErrors(batchGroupsCumulativeResult.getErrors());
224         }
225         return resultBld;
226     }
227
228     private static class CumulatingFunction<O> {
229         private final Iterable<? extends org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.Group>
230                 inputBatchGroups;
231         private final int sizeOfInputBatch;
232
233         CumulatingFunction(
234                 Iterable<? extends org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.Group>
235                         inputBatchGroups, int sizeOfInputBatch) {
236             this.inputBatchGroups = inputBatchGroups;
237             this.sizeOfInputBatch = sizeOfInputBatch;
238         }
239
240         public Function<List<RpcResult<O>>, RpcResult<List<BatchFailedGroupsOutput>>> invoke() {
241             return new Function<List<RpcResult<O>>, RpcResult<List<BatchFailedGroupsOutput>>>() {
242                 @Nullable
243                 @Override
244                 public RpcResult<List<BatchFailedGroupsOutput>> apply(@Nullable final List<RpcResult<O>> innerInput) {
245                     final int sizeOfFutures = innerInput.size();
246                     Preconditions.checkArgument(sizeOfFutures == sizeOfInputBatch,
247                             "wrong amount of returned futures: {} <> {}", sizeOfFutures, sizeOfInputBatch);
248
249                     final List<BatchFailedGroupsOutput> batchGroups = new ArrayList<>();
250                     final Iterator<? extends org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.Group>
251                             batchGroupIterator = inputBatchGroups.iterator();
252
253                     Collection<RpcError> groupErrors = new ArrayList<>(sizeOfFutures);
254
255                     int batchOrder = 0;
256                     for (RpcResult<O> groupModOutput : innerInput) {
257                         final GroupId groupId = batchGroupIterator.next().getGroupId();
258
259                         if (!groupModOutput.isSuccessful()) {
260                             batchGroups.add(new BatchFailedGroupsOutputBuilder()
261                                     .setGroupId(groupId)
262                                     .setBatchOrder(batchOrder)
263                                     .build());
264                             groupErrors.addAll(groupModOutput.getErrors());
265                         }
266                         batchOrder++;
267                     }
268
269                     final RpcResultBuilder<List<BatchFailedGroupsOutput>> resultBuilder;
270                     if (!groupErrors.isEmpty()) {
271                         resultBuilder = RpcResultBuilder.<List<BatchFailedGroupsOutput>>failed()
272                                 .withRpcErrors(groupErrors).withResult(batchGroups);
273                     } else {
274                         resultBuilder = SUCCESSFUL_GROUP_OUTPUT_RPC_RESULT;
275                     }
276                     return resultBuilder.build();
277                 }
278             };
279         }
280     }
281 }