blob: b2a9ba391ef0d3c9762768533fc0ed39c713d5b8 [file] [log] [blame]
Carmelo Cascone17fc9e42016-05-31 11:29:21 -07001/*
2 * Copyright 2016-present Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.onosproject.bmv2.api.runtime;
18
Carmelo Cascone9e39e312016-06-16 14:47:09 -070019import com.google.common.annotations.Beta;
Carmelo Cascone17fc9e42016-05-31 11:29:21 -070020import com.google.common.base.MoreObjects;
21import com.google.common.base.Objects;
Carmelo Cascone0ec92f12016-06-17 14:41:40 -070022import com.google.common.collect.Maps;
23import org.onlab.util.ImmutableByteSequence;
Carmelo Cascone17fc9e42016-05-31 11:29:21 -070024import org.onlab.util.KryoNamespace;
Carmelo Cascone0ec92f12016-06-17 14:41:40 -070025import org.onosproject.bmv2.api.context.Bmv2ActionModel;
26import org.onosproject.bmv2.api.context.Bmv2Configuration;
27import org.onosproject.bmv2.api.context.Bmv2RuntimeDataModel;
28import org.onosproject.bmv2.api.utils.Bmv2TranslatorUtils;
Carmelo Cascone17fc9e42016-05-31 11:29:21 -070029import org.onosproject.net.flow.AbstractExtension;
30import org.onosproject.net.flow.instructions.ExtensionTreatment;
31import org.onosproject.net.flow.instructions.ExtensionTreatmentType;
32
Carmelo Cascone0ec92f12016-06-17 14:41:40 -070033import java.nio.ByteBuffer;
34import java.util.ArrayList;
35import java.util.List;
36import java.util.Map;
37
38import static com.google.common.base.Preconditions.checkArgument;
39import static com.google.common.base.Preconditions.checkNotNull;
40import static org.onlab.util.ImmutableByteSequence.copyFrom;
41import static org.onosproject.bmv2.api.utils.Bmv2TranslatorUtils.fitByteSequence;
Carmelo Cascone17fc9e42016-05-31 11:29:21 -070042import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.BMV2_ACTION;
43
44/**
45 * Extension treatment for BMv2 used as a wrapper for a {@link Bmv2Action}.
46 */
Carmelo Cascone9e39e312016-06-16 14:47:09 -070047@Beta
Carmelo Cascone17fc9e42016-05-31 11:29:21 -070048public final class Bmv2ExtensionTreatment extends AbstractExtension implements ExtensionTreatment {
49
50 private final KryoNamespace appKryo = new KryoNamespace.Builder().build();
51 private Bmv2Action action;
52
Carmelo Cascone9e39e312016-06-16 14:47:09 -070053 /**
54 * Creates a new extension treatment for the given BMv2 action.
55 *
56 * @param action an action
57 */
Carmelo Cascone0ec92f12016-06-17 14:41:40 -070058 private Bmv2ExtensionTreatment(Bmv2Action action) {
Carmelo Cascone17fc9e42016-05-31 11:29:21 -070059 this.action = action;
60 }
61
Carmelo Cascone9e39e312016-06-16 14:47:09 -070062 /**
63 * Returns the action contained by this extension selector.
64 *
65 * @return an action
66 */
67 public Bmv2Action action() {
Carmelo Cascone17fc9e42016-05-31 11:29:21 -070068 return action;
69 }
70
71 @Override
72 public ExtensionTreatmentType type() {
73 return BMV2_ACTION.type();
74 }
75
76 @Override
77 public byte[] serialize() {
78 return appKryo.serialize(action);
79 }
80
81 @Override
82 public void deserialize(byte[] data) {
83 action = appKryo.deserialize(data);
84 }
85
86 @Override
87 public int hashCode() {
88 return Objects.hashCode(action);
89 }
90
91 @Override
92 public boolean equals(Object obj) {
93 if (this == obj) {
94 return true;
95 }
96 if (obj == null || getClass() != obj.getClass()) {
97 return false;
98 }
99 final Bmv2ExtensionTreatment other = (Bmv2ExtensionTreatment) obj;
100 return Objects.equal(this.action, other.action);
101 }
102
103 @Override
104 public String toString() {
105 return MoreObjects.toStringHelper(this)
106 .add("action", action)
107 .toString();
108 }
Carmelo Cascone0ec92f12016-06-17 14:41:40 -0700109
110 /**
111 * Returns a new, empty BMv2 extension treatment.
112 *
113 * @return a BMv2 extension treatment
114 */
115 public static Bmv2ExtensionTreatment empty() {
116 return new Bmv2ExtensionTreatment(null);
117 }
118
119 /**
120 * Returns a new BMv2 extension treatment builder.
121 *
122 * @return a builder
123 */
124 public static Builder builder() {
125 return new Builder();
126 }
127
128 /**
129 * A builder of BMv2 extension treatments.
130 *
131 * BMv2 action parameters are built from primitive data types ({@code short}, {@code int}, {@code long} or
132 * {@code byte[]}) and automatically casted to fixed-length byte sequences according to the given BMv2
133 * configuration.
134 */
135 public static final class Builder {
136 private Bmv2Configuration configuration;
137 private String actionName;
138 private final Map<String, ImmutableByteSequence> parameters = Maps.newHashMap();
139
140 private Builder() {
141 // Ban constructor.
142 }
143
144 /**
145 * Sets the BMv2 configuration to format the action parameters.
146 *
147 * @param config a BMv2 configuration
148 * @return this
149 */
150 public Builder forConfiguration(Bmv2Configuration config) {
151 this.configuration = config;
152 return this;
153 }
154
155 /**
156 * Sets the action name.
157 *
158 * @param actionName a string value
159 * @return this
160 */
161 public Builder setActionName(String actionName) {
162 this.actionName = actionName;
163 return this;
164 }
165
166 /**
167 * Adds an action parameter.
168 *
169 * @param parameterName a string value
170 * @param value a short value
171 * @return this
172 */
173 public Builder addParameter(String parameterName, short value) {
174 this.parameters.put(parameterName, copyFrom(bb(value)));
175 return this;
176 }
177
178 /**
179 * Adds an action parameter.
180 *
181 * @param parameterName a string value
182 * @param value an integer value
183 * @return this
184 */
185 public Builder addParameter(String parameterName, int value) {
186 this.parameters.put(parameterName, copyFrom(bb(value)));
187 return this;
188 }
189
190 /**
191 * Adds an action parameter.
192 *
193 * @param parameterName a string value
194 * @param value a long value
195 * @return this
196 */
197 public Builder addParameter(String parameterName, long value) {
198 this.parameters.put(parameterName, copyFrom(bb(value)));
199 return this;
200 }
201
202 /**
203 * Adds an action parameter.
204 *
205 * @param parameterName a string value
206 * @param value a byte array
207 * @return this
208 */
209 public Builder addParameter(String parameterName, byte[] value) {
210 this.parameters.put(parameterName, copyFrom(bb(value)));
211 return this;
212 }
213
214 /**
215 * Returns a new BMv2 extension treatment.
216 *
217 * @return a BMv2 extension treatment
218 * @throws NullPointerException if the given action or parameter names are not defined in the given
219 * configuration
220 * @throws IllegalArgumentException if a given parameter cannot be casted for the given configuration, e.g.
221 * when trying to fit an integer value into a smaller, fixed-length parameter
222 * produces overflow.
223 */
224 public Bmv2ExtensionTreatment build() {
225 checkNotNull(configuration, "configuration cannot be null");
226 checkNotNull(actionName, "action name cannot be null");
227
228 Bmv2ActionModel actionModel = configuration.action(actionName);
229
230 checkNotNull(actionModel, "no such an action in configuration", actionName);
231 checkArgument(actionModel.runtimeDatas().size() == parameters.size(),
232 "invalid number of parameters", actionName);
233
234 List<ImmutableByteSequence> newParameters = new ArrayList<>(parameters.size());
235
236 for (String parameterName : parameters.keySet()) {
237 Bmv2RuntimeDataModel runtimeData = actionModel.runtimeData(parameterName);
238 checkNotNull(runtimeData, "no such an action parameter in configuration",
239 actionName + "->" + runtimeData.name());
240 int bitWidth = runtimeData.bitWidth();
241 try {
242 ImmutableByteSequence newSequence = fitByteSequence(parameters.get(parameterName), bitWidth);
243 int idx = actionModel.runtimeDatas().indexOf(runtimeData);
244 newParameters.add(idx, newSequence);
245 } catch (Bmv2TranslatorUtils.ByteSequenceFitException e) {
246 throw new IllegalArgumentException(e.getMessage() +
247 " [" + actionName + "->" + runtimeData.name() + "]");
248 }
249 }
250
251 return new Bmv2ExtensionTreatment(new Bmv2Action(actionName, newParameters));
252 }
253
254
255
256 private static ByteBuffer bb(Object value) {
257 if (value instanceof Short) {
258 return ByteBuffer.allocate(Short.BYTES).putShort((short) value);
259 } else if (value instanceof Integer) {
260 return ByteBuffer.allocate(Integer.BYTES).putInt((int) value);
261 } else if (value instanceof Long) {
262 return ByteBuffer.allocate(Long.BYTES).putLong((long) value);
263 } else if (value instanceof byte[]) {
264 byte[] bytes = (byte[]) value;
265 return ByteBuffer.allocate(bytes.length).put(bytes);
266 } else {
267 // Never here.
268 return null;
269 }
270 }
271 }
Carmelo Cascone17fc9e42016-05-31 11:29:21 -0700272}