Merge "OPNFLWPLUG-1062 Include additional LLDP fields in liblldp"
[openflowplugin.git] / extension / openflowplugin-extension-nicira / src / main / java / org / opendaylight / openflowplugin / extension / vendor / nicira / convertor / action / RegLoad2Convertor.java
1 /*
2  * Copyright (c) 2018 SUSE LINUX GmbH.  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.extension.vendor.nicira.convertor.action;
10
11 import com.google.common.base.Preconditions;
12 import java.math.BigInteger;
13 import java.util.Collections;
14 import javax.annotation.Nullable;
15 import org.opendaylight.openflowjava.nx.codec.match.NiciraMatchCodecs;
16 import org.opendaylight.openflowplugin.extension.api.ConvertorActionFromOFJava;
17 import org.opendaylight.openflowplugin.extension.api.ConvertorActionToOFJava;
18 import org.opendaylight.openflowplugin.extension.api.path.ActionPath;
19 import org.opendaylight.openflowplugin.extension.vendor.nicira.convertor.CodecPreconditionException;
20 import org.opendaylight.openflowplugin.extension.vendor.nicira.convertor.match.NshFlagsConvertor;
21 import org.opendaylight.openflowplugin.extension.vendor.nicira.convertor.match.NshTtlConvertor;
22 import org.opendaylight.openflowplugin.extension.vendor.nicira.convertor.match.Nshc1Convertor;
23 import org.opendaylight.openflowplugin.extension.vendor.nicira.convertor.match.Nshc2Convertor;
24 import org.opendaylight.openflowplugin.extension.vendor.nicira.convertor.match.Nshc3Convertor;
25 import org.opendaylight.openflowplugin.extension.vendor.nicira.convertor.match.Nshc4Convertor;
26 import org.opendaylight.openflowplugin.extension.vendor.nicira.convertor.match.NsiConvertor;
27 import org.opendaylight.openflowplugin.extension.vendor.nicira.convertor.match.NspConvertor;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev150225.oxm.container.match.entry.value.ExperimenterIdCase;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev150203.actions.grouping.Action;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.MatchField;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entries.grouping.MatchEntry;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.action.container.action.choice.ActionRegLoad2;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.action.container.action.choice.ActionRegLoad2Builder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.ofj.nx.action.reg.load2.grouping.NxActionRegLoad2;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.ofj.nx.action.reg.load2.grouping.NxActionRegLoad2Builder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxNshFlags;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxNshTtl;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxNshc1;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxNshc2;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxNshc3;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxNshc4;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxNsi;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxNsp;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.OfjAugNxExpMatch;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.ofj.nxm.nx.match.nsh.flags.grouping.NshFlagsValues;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.ofj.nxm.nx.match.nsh.ttl.grouping.NshTtlValues;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.ofj.nxm.nx.match.nsi.grouping.NsiValues;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.ofj.nxm.nx.match.nsp.grouping.NspValues;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.oxm.container.match.entry.value.experimenter.id._case.NxExpMatchEntryValue;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.oxm.container.match.entry.value.experimenter.id._case.nx.exp.match.entry.value.NshFlagsCaseValue;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.oxm.container.match.entry.value.experimenter.id._case.nx.exp.match.entry.value.NshTtlCaseValue;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.oxm.container.match.entry.value.experimenter.id._case.nx.exp.match.entry.value.NshcCaseValue;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.oxm.container.match.entry.value.experimenter.id._case.nx.exp.match.entry.value.NsiCaseValue;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.oxm.container.match.entry.value.experimenter.id._case.nx.exp.match.entry.value.NspCaseValue;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.NxActionRegLoadGrouping;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.DstChoice;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxNshFlagsCase;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxNshFlagsCaseBuilder;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxNshTtlCase;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxNshTtlCaseBuilder;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxNshc1Case;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxNshc1CaseBuilder;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxNshc2Case;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxNshc2CaseBuilder;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxNshc3Case;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxNshc3CaseBuilder;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxNshc4Case;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxNshc4CaseBuilder;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxNsiCase;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxNsiCaseBuilder;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxNspCase;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxNspCaseBuilder;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.reg.load.grouping.NxRegLoad;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.reg.load.grouping.NxRegLoadBuilder;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.reg.load.grouping.nx.reg.load.Dst;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.reg.load.grouping.nx.reg.load.DstBuilder;
77 import org.opendaylight.yangtools.yang.common.Empty;
78
79 /**
80  * Convert between RegLoad SAL action and RegLoad2 nicira action.
81  */
82 public class RegLoad2Convertor implements
83         ConvertorActionToOFJava<org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action,
84                 Action>,
85         ConvertorActionFromOFJava<Action, ActionPath> {
86
87     @Override
88     public org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action convert(Action input,
89                                                                                                       ActionPath path) {
90         NxActionRegLoad2 actionRegLoad2 = ((ActionRegLoad2) input.getActionChoice()).getNxActionRegLoad2();
91         MatchEntry matchEntry = actionRegLoad2.getMatchEntry().get(0);
92         NxRegLoad nxRegLoad = resolveRegLoad(matchEntry);
93         return RegLoadConvertor.resolveAction(nxRegLoad, path);
94     }
95
96     @Override
97     public Action convert(
98             org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action actionCase) {
99         Preconditions.checkArgument(actionCase instanceof NxActionRegLoadGrouping);
100
101         NxActionRegLoadGrouping nxAction = (NxActionRegLoadGrouping) actionCase;
102         MatchEntry matchEntry = resolveMatchEntry(nxAction.getNxRegLoad());
103         NxActionRegLoad2 nxActionRegLoad2 = new NxActionRegLoad2Builder()
104                 .setMatchEntry(Collections.singletonList(matchEntry))
105                 .build();
106         ActionRegLoad2 actionRegLoad2 = new ActionRegLoad2Builder().setNxActionRegLoad2(nxActionRegLoad2).build();
107         return ActionUtil.createAction(actionRegLoad2);
108     }
109
110     private static MatchEntry resolveMatchEntry(NxRegLoad nxRegLoad) {
111         Dst dst = nxRegLoad.getDst();
112         BigInteger value = nxRegLoad.getValue();
113         int start = dst.getStart();
114         int end = dst.getEnd();
115         BigInteger[] valueMask = resolveValueMask(value, start, end);
116         value = valueMask[0];
117         BigInteger mask = valueMask[1];
118         DstChoice dstChoice = dst.getDstChoice();
119         return resolveMatchEntry(dstChoice, value, mask);
120     }
121
122     private static MatchEntry resolveMatchEntry(DstChoice dstChoice, BigInteger value, BigInteger mask) {
123         try {
124             if (dstChoice instanceof DstNxNshFlagsCase) {
125                 return NshFlagsConvertor.buildMatchEntry(value.shortValueExact(), mask.shortValueExact());
126             }
127             if (dstChoice instanceof DstNxNspCase) {
128                 return NspConvertor.buildMatchEntry(value.longValueExact(), mask.longValueExact());
129             }
130             if (dstChoice instanceof DstNxNsiCase) {
131                 return NsiConvertor.buildMatchEntry(value.shortValueExact(), mask.shortValueExact());
132             }
133             if (dstChoice instanceof DstNxNshc1Case) {
134                 return Nshc1Convertor.buildMatchEntry(value.longValueExact(), mask.longValueExact());
135             }
136             if (dstChoice instanceof DstNxNshc2Case) {
137                 return Nshc2Convertor.buildMatchEntry(value.longValueExact(), mask.longValueExact());
138             }
139             if (dstChoice instanceof DstNxNshc3Case) {
140                 return Nshc3Convertor.buildMatchEntry(value.longValueExact(), mask.longValueExact());
141             }
142             if (dstChoice instanceof DstNxNshc4Case) {
143                 return Nshc4Convertor.buildMatchEntry(value.longValueExact(), mask.longValueExact());
144             }
145             if (dstChoice instanceof DstNxNshTtlCase) {
146                 return NshTtlConvertor.buildMatchEntry(value.shortValueExact(), mask.shortValueExact());
147             }
148         } catch (ArithmeticException e) {
149             throw new IllegalArgumentException("Value or bit range too big for destination choice", e);
150         }
151
152         throw new CodecPreconditionException("Missing implementation of a case in dst-choice? " + dstChoice.getClass());
153     }
154
155     private static NxRegLoad resolveRegLoad(MatchEntry matchEntry) {
156         Class<? extends MatchField> oxmMatchField = matchEntry.getOxmMatchField();
157         ExperimenterIdCase experimenterIdCase = (ExperimenterIdCase) matchEntry.getMatchEntryValue();
158         OfjAugNxExpMatch ofjAugNxExpMatch = experimenterIdCase.augmentation(OfjAugNxExpMatch.class);
159         NxExpMatchEntryValue nxExpMatchEntryValue = ofjAugNxExpMatch.getNxExpMatchEntryValue();
160         DstBuilder dstBuilder = new DstBuilder();
161         return resolveRegLoad(oxmMatchField, nxExpMatchEntryValue, dstBuilder);
162     }
163
164     private static NxRegLoad resolveRegLoad(
165             Class<? extends MatchField> oxmMatchField,
166             NxExpMatchEntryValue value,
167             DstBuilder dstBuilder) {
168
169         if (NxmNxNshFlags.class.equals(oxmMatchField)) {
170             int valueLength = NiciraMatchCodecs.NSH_FLAGS_CODEC.getValueLength();
171             dstBuilder.setDstChoice(new DstNxNshFlagsCaseBuilder().setNxNshFlags(Empty.getInstance()).build());
172             NshFlagsValues nshFlagsValues = ((NshFlagsCaseValue) value).getNshFlagsValues();
173             return resolveRegLoad(nshFlagsValues.getNshFlags(), nshFlagsValues.getMask(), valueLength, dstBuilder);
174         }
175         if (NxmNxNsp.class.equals(oxmMatchField)) {
176             int valueLength = NiciraMatchCodecs.NSP_CODEC.getValueLength();
177             dstBuilder.setDstChoice(new DstNxNspCaseBuilder().setNxNspDst(Empty.getInstance()).build());
178             NspValues nspValues = ((NspCaseValue) value).getNspValues();
179             return resolveRegLoad(nspValues.getNsp(), nspValues.getMask(), valueLength, dstBuilder);
180         }
181         if (NxmNxNsi.class.equals(oxmMatchField)) {
182             int valueLength = NiciraMatchCodecs.NSI_CODEC.getValueLength();
183             dstBuilder.setDstChoice(new DstNxNsiCaseBuilder().setNxNsiDst(Empty.getInstance()).build());
184             NsiValues nsiValues = ((NsiCaseValue) value).getNsiValues();
185             return resolveRegLoad(nsiValues.getNsi(), nsiValues.getMask(), valueLength, dstBuilder);
186         }
187         if (NxmNxNshc1.class.equals(oxmMatchField)) {
188             int valueLength = NiciraMatchCodecs.NSC1_CODEC.getValueLength();
189             dstBuilder.setDstChoice(new DstNxNshc1CaseBuilder().setNxNshc1Dst(Empty.getInstance()).build());
190             NshcCaseValue nshcCaseValue = ((NshcCaseValue) value);
191             return resolveRegLoad(nshcCaseValue.getNshc(), nshcCaseValue.getMask(), valueLength, dstBuilder);
192         }
193         if (NxmNxNshc2.class.equals(oxmMatchField)) {
194             int valueLength = NiciraMatchCodecs.NSC2_CODEC.getValueLength();
195             dstBuilder.setDstChoice(new DstNxNshc2CaseBuilder().setNxNshc2Dst(Empty.getInstance()).build());
196             NshcCaseValue nshcCaseValue = ((NshcCaseValue) value);
197             return resolveRegLoad(nshcCaseValue.getNshc(), nshcCaseValue.getMask(), valueLength, dstBuilder);
198         }
199         if (NxmNxNshc3.class.equals(oxmMatchField)) {
200             int valueLength = NiciraMatchCodecs.NSC3_CODEC.getValueLength();
201             dstBuilder.setDstChoice(new DstNxNshc3CaseBuilder().setNxNshc3Dst(Empty.getInstance()).build());
202             NshcCaseValue nshcCaseValue = ((NshcCaseValue) value);
203             return resolveRegLoad(nshcCaseValue.getNshc(), nshcCaseValue.getMask(), valueLength, dstBuilder);
204         }
205         if (NxmNxNshc4.class.equals(oxmMatchField)) {
206             int valueLength = NiciraMatchCodecs.NSC4_CODEC.getValueLength();
207             dstBuilder.setDstChoice(new DstNxNshc4CaseBuilder().setNxNshc4Dst(Empty.getInstance()).build());
208             NshcCaseValue nshcCaseValue = ((NshcCaseValue) value);
209             return resolveRegLoad(nshcCaseValue.getNshc(), nshcCaseValue.getMask(), valueLength, dstBuilder);
210         }
211         if (NxmNxNshTtl.class.equals(oxmMatchField)) {
212             int valueLength = NiciraMatchCodecs.NSH_TTL_CODEC.getValueLength();
213             dstBuilder.setDstChoice(new DstNxNshTtlCaseBuilder().setNxNshTtl(Empty.getInstance()).build());
214             NshTtlValues nshTtlValues = ((NshTtlCaseValue) value).getNshTtlValues();
215             return resolveRegLoad(nshTtlValues.getNshTtl(), nshTtlValues.getMask(), valueLength, dstBuilder);
216         }
217
218         throw new CodecPreconditionException("Missing codec for " + value.implementedInterface());
219     }
220
221     private static NxRegLoad resolveRegLoad(Short value, @Nullable Short mask, int valueLength, DstBuilder dstBuilder) {
222         return resolveRegLoad(
223                 BigInteger.valueOf(value),
224                 mask == null ? null : BigInteger.valueOf(mask),
225                 valueLength,
226                 dstBuilder);
227     }
228
229     private static NxRegLoad resolveRegLoad(Long value, @Nullable Long mask, int valueLength, DstBuilder dstBuilder) {
230         return resolveRegLoad(
231                 BigInteger.valueOf(value),
232                 mask == null ? null : BigInteger.valueOf(mask),
233                 valueLength,
234                 dstBuilder);
235     }
236
237     // Convert the value/mask pair of the openflowjava reg_load2 action to the
238     // value/bit range pair of the openfloplugin reg_load action.
239     private static NxRegLoad resolveRegLoad(BigInteger value,
240                                             @Nullable BigInteger mask,
241                                             int length,
242                                             DstBuilder dstBuilder) {
243         final int start;
244         final int end;
245         if (mask == null) {
246             start = 0;
247             end = length * 8;
248         } else {
249             start = mask.getLowestSetBit();
250             end = start + mask.shiftRight(start).not().getLowestSetBit();
251             value = value.and(mask).shiftRight(start);
252
253             if (value.bitLength() > end - start) {
254                 // We cannot map a REG_LOAD2 to a single REG_LOAD if the mask
255                 // has multiple 1-bit segments (i.e. 0xFF00FF)
256                 throw new IllegalArgumentException("Value does not fit in the first 1-bit segment of the mask");
257             }
258         }
259
260         dstBuilder.setStart(start);
261         dstBuilder.setEnd(end - 1);
262         NxRegLoadBuilder nxRegLoadBuilder = new NxRegLoadBuilder();
263         nxRegLoadBuilder.setDst(dstBuilder.build());
264         nxRegLoadBuilder.setValue(value);
265         return nxRegLoadBuilder.build();
266     }
267
268     // Convert value/bit range pair of the openfloplugin reg_load action to the
269     // value/mask pair of the openflowjava reg_load2 action.
270     private static BigInteger[] resolveValueMask(BigInteger value, int start, int end) {
271         int bits = end - start + 1;
272         if (value.bitLength() > bits) {
273             throw new IllegalArgumentException("Value does not fit the bit range");
274         }
275
276         BigInteger mask = BigInteger.ONE.shiftLeft(bits).subtract(BigInteger.ONE).shiftLeft(start);
277         value = value.shiftLeft(start);
278
279         return new BigInteger[] {value, mask};
280     }
281
282 }