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