7060f520f32a8a62b3ae4a7f2ef76b3ef2ee4a63
[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.yang.gen.v1.urn.opendaylight.openflow.augments.rev150225.oxm.container.match.entry.value.ExperimenterIdCase;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev150203.actions.grouping.Action;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entries.grouping.MatchEntry;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.action.container.action.choice.ActionRegLoad2;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.action.container.action.choice.ActionRegLoad2Builder;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.ofj.nx.action.reg.load2.grouping.NxActionRegLoad2;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.ofj.nx.action.reg.load2.grouping.NxActionRegLoad2Builder;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.OfjAugNxExpMatch;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.ofj.nxm.nx.match.nsh.flags.grouping.NshFlagsValues;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.ofj.nxm.nx.match.nsh.ttl.grouping.NshTtlValues;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.oxm.container.match.entry.value.experimenter.id._case.NxExpMatchEntryValue;
33 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;
34 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;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.NxActionRegLoadGrouping;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.DstChoice;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxNshFlagsCase;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxNshFlagsCaseBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxNshTtlCase;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxNshTtlCaseBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.reg.load.grouping.NxRegLoad;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.reg.load.grouping.NxRegLoadBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.reg.load.grouping.nx.reg.load.Dst;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.reg.load.grouping.nx.reg.load.DstBuilder;
45
46 /**
47  * Convert between RegLoad SAL action and RegLoad2 nicira action.
48  */
49 public class RegLoad2Convertor implements
50         ConvertorActionToOFJava<org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action,
51                 Action>,
52         ConvertorActionFromOFJava<Action, ActionPath> {
53
54     @Override
55     public org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action convert(Action input,
56                                                                                                       ActionPath path) {
57         NxActionRegLoad2 actionRegLoad2 = ((ActionRegLoad2) input.getActionChoice()).getNxActionRegLoad2();
58         MatchEntry matchEntry = actionRegLoad2.getMatchEntry().get(0);
59         NxRegLoad nxRegLoad = resolveRegLoad(matchEntry);
60         return RegLoadConvertor.resolveAction(nxRegLoad, path);
61     }
62
63     @Override
64     public Action convert(
65             org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action actionCase) {
66         Preconditions.checkArgument(actionCase instanceof NxActionRegLoadGrouping);
67
68         NxActionRegLoadGrouping nxAction = (NxActionRegLoadGrouping) actionCase;
69         MatchEntry matchEntry = resolveMatchEntry(nxAction.getNxRegLoad());
70         NxActionRegLoad2 nxActionRegLoad2 = new NxActionRegLoad2Builder()
71                 .setMatchEntry(Collections.singletonList(matchEntry))
72                 .build();
73         ActionRegLoad2 actionRegLoad2 = new ActionRegLoad2Builder().setNxActionRegLoad2(nxActionRegLoad2).build();
74         return ActionUtil.createAction(actionRegLoad2);
75     }
76
77     private static MatchEntry resolveMatchEntry(NxRegLoad nxRegLoad) {
78         Dst dst = nxRegLoad.getDst();
79         BigInteger value = nxRegLoad.getValue();
80         int start = dst.getStart();
81         int end = dst.getEnd();
82         BigInteger[] valueMask = resolveValueMask(value, start, end);
83         value = valueMask[0];
84         BigInteger mask = valueMask[1];
85         DstChoice dstChoice = dst.getDstChoice();
86         return resolveMatchEntry(dstChoice, value, mask);
87     }
88
89     private static MatchEntry resolveMatchEntry(DstChoice dstChoice, BigInteger value, BigInteger mask) {
90         if (dstChoice instanceof DstNxNshFlagsCase) {
91             return NshFlagsConvertor.buildMatchEntry(value.shortValue(), mask.shortValue());
92         }
93         if (dstChoice instanceof DstNxNshTtlCase) {
94             return NshTtlConvertor.buildMatchEntry(value.shortValue(), mask.shortValue());
95         }
96
97         throw new CodecPreconditionException("Missing implementation of a case in dst-choice? " + dstChoice.getClass());
98     }
99
100     private static NxRegLoad resolveRegLoad(MatchEntry matchEntry) {
101         ExperimenterIdCase experimenterIdCase = (ExperimenterIdCase) matchEntry.getMatchEntryValue();
102         OfjAugNxExpMatch ofjAugNxExpMatch = experimenterIdCase.augmentation(OfjAugNxExpMatch.class);
103         NxExpMatchEntryValue nxExpMatchEntryValue = ofjAugNxExpMatch.getNxExpMatchEntryValue();
104         DstBuilder dstBuilder = new DstBuilder();
105         return resolveRegLoad(nxExpMatchEntryValue, dstBuilder);
106     }
107
108     private static NxRegLoad resolveRegLoad(NxExpMatchEntryValue value, DstBuilder dstBuilder) {
109         if (value instanceof NshFlagsCaseValue) {
110             int valueLength = NiciraMatchCodecs.NSH_FLAGS_CODEC.getValueLength();
111             dstBuilder.setDstChoice(new DstNxNshFlagsCaseBuilder().setNxNshFlags(true).build());
112             NshFlagsValues nshFlagsValues = ((NshFlagsCaseValue) value).getNshFlagsValues();
113             return resolveRegLoad(nshFlagsValues.getNshFlags(), nshFlagsValues.getMask(), valueLength, dstBuilder);
114         }
115         if (value instanceof NshTtlCaseValue) {
116             int valueLength = NiciraMatchCodecs.NSH_TTL_CODEC.getValueLength();
117             dstBuilder.setDstChoice(new DstNxNshTtlCaseBuilder().setNxNshTtl(true).build());
118             NshTtlValues nshTtlValues = ((NshTtlCaseValue) value).getNshTtlValues();
119             return resolveRegLoad(nshTtlValues.getNshTtl(), nshTtlValues.getMask(), valueLength, dstBuilder);
120         }
121
122         throw new CodecPreconditionException("Missing codec for " + value.getImplementedInterface());
123     }
124
125     private static NxRegLoad resolveRegLoad(Short value, Short mask, int valueLength, DstBuilder dstBuilder) {
126         return resolveRegLoad(
127                 BigInteger.valueOf(value),
128                 mask == null ? null : BigInteger.valueOf(mask),
129                 valueLength,
130                 dstBuilder);
131     }
132
133     private static NxRegLoad resolveRegLoad(BigInteger value,
134                                             @Nullable BigInteger mask,
135                                             int length,
136                                             DstBuilder dstBuilder) {
137         final int start;
138         final int end;
139         if (mask == null) {
140             start = 0;
141             end = length * 8;
142         } else {
143             start = mask.getLowestSetBit();
144             end = start + mask.shiftRight(start).not().getLowestSetBit();
145             value = value.and(mask).shiftRight(start);
146
147             if (value.bitLength() > end - start) {
148                 // We cannot map a REG_LOAD2 to a single REG_LOAD if the mask
149                 // has multiple 1-bit segments (i.e. 0xFF00FF)
150                 throw new IllegalArgumentException("Value does not fit in the first 1-bit segment of the mask");
151             }
152         }
153
154         dstBuilder.setStart(start);
155         dstBuilder.setEnd(end - 1);
156         NxRegLoadBuilder nxRegLoadBuilder = new NxRegLoadBuilder();
157         nxRegLoadBuilder.setDst(dstBuilder.build());
158         nxRegLoadBuilder.setValue(value);
159         return nxRegLoadBuilder.build();
160     }
161
162     private static BigInteger[] resolveValueMask(BigInteger value, int start, int end) {
163         int bits = end - start + 1;
164         if (value.bitLength() > bits) {
165             throw new IllegalArgumentException("Value does not fit the bit range");
166         }
167
168         BigInteger mask = BigInteger.ONE.shiftLeft(bits).subtract(BigInteger.ONE).shiftLeft(start);
169         value = value.shiftLeft(start);
170
171         return new BigInteger[] {value, mask};
172     }
173
174 }