Update MRI projects for Aluminium
[openflowplugin.git] / openflowplugin / src / main / java / org / opendaylight / openflowplugin / openflow / md / core / sal / convertor / GroupConvertor.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.openflow.md.core.sal.convertor;
10
11 import java.util.ArrayList;
12 import java.util.Arrays;
13 import java.util.Collection;
14 import java.util.Collections;
15 import java.util.Comparator;
16 import java.util.List;
17 import java.util.Map;
18 import java.util.Optional;
19 import org.opendaylight.openflowjava.protocol.api.util.BinContent;
20 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.action.data.ActionConvertorData;
21 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.common.Convertor;
22 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.data.VersionDatapathIdConvertorData;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.AddGroupInput;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.RemoveGroupInput;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.group.update.UpdatedGroup;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.Group;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.Buckets;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.BucketKey;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev150203.actions.grouping.Action;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.GroupId;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.GroupModCommand;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.GroupType;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.PortNumber;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.GroupModInputBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.buckets.grouping.BucketsList;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.buckets.grouping.BucketsListBuilder;
39 import org.opendaylight.yangtools.yang.common.Uint64;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
42
43 /**
44  * Decodes the SAL - Group Mod Message and encodes into a OF
45  * Library for the OFPT_GROUP_MOD Message. Input:SAL Layer Group command data.
46  *
47  * <p>
48  * Example usage:
49  * <pre>
50  * {@code
51  * VersionDatapathIdConvertorData data = new VersionDatapathIdConvertorData(version);
52  * data.setDatapathId(datapathId);
53  * Optional<GroupModInputBuilder> ofGroup = convertorManager.convert(salGroup, data);
54  * }
55  * </pre>
56  */
57 public class GroupConvertor extends Convertor<Group, GroupModInputBuilder, VersionDatapathIdConvertorData> {
58     private static final List<Class<?>> TYPES = Arrays.asList(Group.class, AddGroupInput.class,
59             RemoveGroupInput.class, UpdatedGroup.class);
60
61     /**
62      * Create default empty group mod input builder
63      * Use this method, if result from convertor is empty.
64      *
65      * @param version Openflow version
66      * @return default empty group mod input builder
67      */
68     public static GroupModInputBuilder defaultResult(final short version) {
69         return new GroupModInputBuilder()
70                 .setVersion(version);
71     }
72
73     private static final Logger LOG = LoggerFactory.getLogger(GroupConvertor.class);
74     private static final Integer DEFAULT_WEIGHT = 0;
75     private static final Long OFPP_ANY = Long.parseLong("ffffffff", 16);
76     private static final Long DEFAULT_WATCH_PORT = OFPP_ANY;
77     private static final Long OFPG_ANY = Long.parseLong("ffffffff", 16);
78     private static final Long DEFAULT_WATCH_GROUP = OFPG_ANY;
79     private static final Comparator<Bucket> COMPARATOR = (bucket1, bucket2) -> {
80         if (bucket1.getBucketId() == null || bucket2.getBucketId() == null) {
81             return 0;
82         }
83         return bucket1.getBucketId().getValue().compareTo(bucket2.getBucketId().getValue());
84     };
85
86     private List<BucketsList> salToOFBucketList(final List<Bucket> buckets, final short version, final int groupType,
87             final Uint64 datapathid) {
88         final List<BucketsList> bucketLists = new ArrayList<>();
89         final ActionConvertorData data = new ActionConvertorData(version);
90         data.setDatapathId(datapathid);
91
92         for (org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket groupBucket :
93                 buckets) {
94             BucketsListBuilder bucketBuilder = new BucketsListBuilder();
95
96             salToOFBucketListWeight(groupBucket, bucketBuilder, groupType);
97             salToOFBucketListWatchGroup(groupBucket, bucketBuilder, groupType);
98             salToOFBucketListWatchPort(groupBucket, bucketBuilder, groupType);
99
100             Optional<List<Action>> bucketActionList = getConvertorExecutor().convert(
101                     groupBucket.getAction(), data);
102
103             bucketBuilder.setAction(bucketActionList.orElse(Collections.emptyList()));
104             BucketsList bucket = bucketBuilder.build();
105             bucketLists.add(bucket);
106         }
107
108         return bucketLists;
109
110     }
111
112     private static void salToOFBucketListWatchPort(final Bucket groupBucket, final BucketsListBuilder bucketBuilder,
113             final int groupType) {
114         if (null != groupBucket.getWatchPort()) {
115             bucketBuilder.setWatchPort(new PortNumber(groupBucket.getWatchPort()));
116         } else {
117             bucketBuilder.setWatchPort(new PortNumber(BinContent.intToUnsignedLong(DEFAULT_WATCH_PORT.intValue())));
118             if (groupType == GroupType.OFPGTFF.getIntValue()) {
119                 LOG.error("WatchPort required for this OFPGT_FF");
120             }
121         }
122     }
123
124     private static void salToOFBucketListWatchGroup(final Bucket groupBucket, final BucketsListBuilder bucketBuilder,
125             final int groupType) {
126         if (null != groupBucket.getWatchGroup()) {
127             bucketBuilder.setWatchGroup(groupBucket.getWatchGroup());
128         } else {
129             bucketBuilder.setWatchGroup(BinContent.intToUnsignedLong(DEFAULT_WATCH_GROUP.intValue()));
130             if (groupType == GroupType.OFPGTFF.getIntValue()) {
131                 LOG.error("WatchGroup required for this OFPGT_FF");
132             }
133         }
134     }
135
136     private static void salToOFBucketListWeight(final Bucket groupBucket, final BucketsListBuilder bucketBuilder,
137             final int groupType) {
138         if (null != groupBucket.getWeight()) {
139             bucketBuilder.setWeight(groupBucket.getWeight());
140         } else {
141             bucketBuilder.setWeight(DEFAULT_WEIGHT);
142             if (groupType == GroupType.OFPGTSELECT.getIntValue()) {
143                 LOG.error("Weight value required for this OFPGT_SELECT");
144             }
145         }
146     }
147
148     @Override
149     public Collection<Class<?>> getTypes() {
150         return  TYPES;
151     }
152
153     @Override
154     public GroupModInputBuilder convert(final Group source, final VersionDatapathIdConvertorData data) {
155         GroupModInputBuilder groupModInputBuilder = new GroupModInputBuilder();
156         if (source instanceof AddGroupInput) {
157             groupModInputBuilder.setCommand(GroupModCommand.OFPGCADD);
158         } else if (source instanceof RemoveGroupInput) {
159             groupModInputBuilder.setCommand(GroupModCommand.OFPGCDELETE);
160         } else if (source instanceof UpdatedGroup) {
161             groupModInputBuilder.setCommand(GroupModCommand.OFPGCMODIFY);
162         }
163
164         if (GroupTypes.GroupAll.equals(source.getGroupType())) {
165             groupModInputBuilder.setType(GroupType.OFPGTALL);
166         }
167
168         if (GroupTypes.GroupSelect.equals(source.getGroupType())) {
169             groupModInputBuilder.setType(GroupType.OFPGTSELECT);
170         }
171
172         if (GroupTypes.GroupIndirect.equals(source.getGroupType())) {
173             groupModInputBuilder.setType(GroupType.OFPGTINDIRECT);
174         }
175
176         if (GroupTypes.GroupFf.equals(source.getGroupType())) {
177             groupModInputBuilder.setType(GroupType.OFPGTFF);
178         }
179
180         groupModInputBuilder.setGroupId(new GroupId(source.getGroupId().getValue()));
181
182         // Only if the bucket is configured for the group then add it
183         // During group deletion do not push the buckets
184         if (groupModInputBuilder.getCommand() != GroupModCommand.OFPGCDELETE) {
185             final Buckets buckets = source.getBuckets();
186             if (buckets != null) {
187                 final Map<BucketKey, Bucket> bucket = buckets.nonnullBucket();
188                 if (!bucket.isEmpty()) {
189                     // TODO: we should be able to just sort the resulting the resulting list and not go through
190                     //       two copies
191                     List<Bucket> bucketList = new ArrayList<>(bucket.values());
192                     Collections.sort(bucketList, COMPARATOR);
193                     List<BucketsList> bucketLists = salToOFBucketList(bucketList, data.getVersion(),
194                         source.getGroupType().getIntValue(), data.getDatapathId());
195                     groupModInputBuilder.setBucketsList(bucketLists);
196                 }
197             }
198         }
199
200         groupModInputBuilder.setVersion(data.getVersion());
201         return groupModInputBuilder;
202     }
203 }