blob: 0a4ffbbc9ac6159ac230c3a5661d10e986cae20b [file] [log] [blame]
Carmelo Cascone00a59962017-06-16 17:51:49 +09001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2017-present Open Networking Foundation
Carmelo Cascone00a59962017-06-16 17:51:49 +09003 *
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.net.pi.impl;
18
19import com.google.common.collect.Maps;
20import com.google.common.collect.Sets;
21import org.onlab.util.ImmutableByteSequence;
22import org.onosproject.net.Device;
23import org.onosproject.net.flow.FlowRule;
Carmelo Cascone00a59962017-06-16 17:51:49 +090024import org.onosproject.net.flow.TrafficSelector;
25import org.onosproject.net.flow.TrafficTreatment;
26import org.onosproject.net.flow.criteria.Criterion;
27import org.onosproject.net.flow.criteria.PiCriterion;
28import org.onosproject.net.flow.instructions.Instruction;
29import org.onosproject.net.flow.instructions.PiInstruction;
30import org.onosproject.net.pi.model.PiActionModel;
31import org.onosproject.net.pi.model.PiActionParamModel;
32import org.onosproject.net.pi.model.PiPipeconf;
33import org.onosproject.net.pi.model.PiPipelineInterpreter;
34import org.onosproject.net.pi.model.PiPipelineModel;
35import org.onosproject.net.pi.model.PiTableMatchFieldModel;
36import org.onosproject.net.pi.model.PiTableModel;
37import org.onosproject.net.pi.runtime.PiAction;
38import org.onosproject.net.pi.runtime.PiActionParam;
39import org.onosproject.net.pi.runtime.PiExactFieldMatch;
40import org.onosproject.net.pi.runtime.PiFieldMatch;
41import org.onosproject.net.pi.runtime.PiHeaderFieldId;
42import org.onosproject.net.pi.runtime.PiLpmFieldMatch;
Carmelo Cascone0e896a02017-07-31 07:22:27 +020043import org.onosproject.net.pi.runtime.PiMatchKey;
Carmelo Cascone00a59962017-06-16 17:51:49 +090044import org.onosproject.net.pi.runtime.PiRangeFieldMatch;
45import org.onosproject.net.pi.runtime.PiTableAction;
46import org.onosproject.net.pi.runtime.PiTableEntry;
47import org.onosproject.net.pi.runtime.PiTableId;
48import org.onosproject.net.pi.runtime.PiTernaryFieldMatch;
49import org.slf4j.Logger;
50import org.slf4j.LoggerFactory;
51
52import java.util.Collection;
53import java.util.Map;
54import java.util.Optional;
55import java.util.Set;
56import java.util.StringJoiner;
57
58import static java.lang.String.format;
59import static org.onlab.util.ImmutableByteSequence.ByteSequenceTrimException;
60import static org.onlab.util.ImmutableByteSequence.fit;
61import static org.onosproject.net.flow.criteria.Criterion.Type.PROTOCOL_INDEPENDENT;
62import static org.onosproject.net.pi.impl.CriterionTranslatorHelper.translateCriterion;
Carmelo Cascone87b9b392017-10-02 18:33:20 +020063import static org.onosproject.net.pi.impl.PiUtils.getInterpreterOrNull;
64import static org.onosproject.net.pi.impl.PiUtils.translateTableId;
65import static org.onosproject.net.pi.runtime.PiTranslationService.PiTranslationException;
Carmelo Cascone00a59962017-06-16 17:51:49 +090066
67/**
68 * Implementation of flow rule translation logic.
69 */
70final class PiFlowRuleTranslator {
71
Carmelo Casconea3d811c2017-08-22 01:03:45 +020072 public static final int MAX_PI_PRIORITY = (int) Math.pow(2, 24);
Carmelo Cascone87b9b392017-10-02 18:33:20 +020073 private static final Logger log = LoggerFactory.getLogger(PiFlowRuleTranslator.class);
Carmelo Cascone00a59962017-06-16 17:51:49 +090074
75 private PiFlowRuleTranslator() {
76 // Hide constructor.
77 }
78
Carmelo Cascone87b9b392017-10-02 18:33:20 +020079 /**
80 * Returns a PI table entry equivalent to the given flow rule, for the given pipeconf and device.
81 *
82 * @param rule flow rule
83 * @param pipeconf pipeconf
84 * @param device device
85 * @return PI table entry
86 * @throws PiTranslationException if the flow rule cannot be translated
87 */
88 static PiTableEntry translate(FlowRule rule, PiPipeconf pipeconf, Device device)
89 throws PiTranslationException {
Carmelo Cascone00a59962017-06-16 17:51:49 +090090
91 PiPipelineModel pipelineModel = pipeconf.pipelineModel();
92
93 // Retrieve interpreter, if any.
Carmelo Cascone87b9b392017-10-02 18:33:20 +020094 final PiPipelineInterpreter interpreter = getInterpreterOrNull(device, pipeconf);
95 // Get table model.
96 final PiTableId piTableId = translateTableId(rule.table(), interpreter);
97 final PiTableModel tableModel = getTableModel(piTableId, pipelineModel);
98 // Translate selector.
99 final Collection<PiFieldMatch> fieldMatches = translateFieldMatches(interpreter, rule.selector(), tableModel);
100 // Translate treatment.
101 final PiTableAction piTableAction = translateTreatment(rule.treatment(), interpreter, piTableId, pipelineModel);
Carmelo Casconea62ac3d2017-08-30 03:19:00 +0200102
Carmelo Cascone87b9b392017-10-02 18:33:20 +0200103 // Build PI entry.
104 final PiTableEntry.Builder tableEntryBuilder = PiTableEntry.builder();
Carmelo Cascone00a59962017-06-16 17:51:49 +0900105
Carmelo Casconea3d811c2017-08-22 01:03:45 +0200106 // In the P4 world 0 is the highest priority, in ONOS the lowest one.
107 // FIXME: move priority conversion to the driver, where different constraints might apply
108 // e.g. less bits for encoding priority in TCAM-based implementations.
Carmelo Cascone87b9b392017-10-02 18:33:20 +0200109 final int newPriority;
Carmelo Casconea3d811c2017-08-22 01:03:45 +0200110 if (rule.priority() > MAX_PI_PRIORITY) {
111 log.warn("Flow rule priority too big, setting translated priority to max value {}: {}",
112 MAX_PI_PRIORITY, rule);
113 newPriority = 0;
114 } else {
115 newPriority = MAX_PI_PRIORITY - rule.priority();
116 }
Carmelo Cascone00a59962017-06-16 17:51:49 +0900117
118 tableEntryBuilder
119 .forTable(piTableId)
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200120 .withPriority(newPriority)
Carmelo Cascone0e896a02017-07-31 07:22:27 +0200121 .withMatchKey(PiMatchKey.builder()
122 .addFieldMatches(fieldMatches)
123 .build())
Yi Tseng82512da2017-08-16 19:46:36 -0700124 .withAction(piTableAction);
Carmelo Cascone00a59962017-06-16 17:51:49 +0900125
126 if (!rule.isPermanent()) {
Carmelo Cascone87b9b392017-10-02 18:33:20 +0200127 if (tableModel.supportsAging()) {
Carmelo Cascone00a59962017-06-16 17:51:49 +0900128 tableEntryBuilder.withTimeout((double) rule.timeout());
129 } else {
130 log.warn("Flow rule is temporary, but table '{}' doesn't support " +
Carmelo Cascone87b9b392017-10-02 18:33:20 +0200131 "aging, translating to permanent.", tableModel.name());
Carmelo Cascone00a59962017-06-16 17:51:49 +0900132 }
133
134 }
135
136 return tableEntryBuilder.build();
137 }
138
Carmelo Cascone87b9b392017-10-02 18:33:20 +0200139
140 /**
141 * Returns a PI action equivalent to the given treatment, optionally using the given interpreter. This method also
142 * checks that the produced PI table action is suitable for the given table ID and pipeline model. If suitable, the
143 * returned action instance will have parameters well-sized, according to the table model.
144 *
145 * @param treatment traffic treatment
146 * @param interpreter interpreter
147 * @param tableId PI table ID
148 * @param pipelineModel pipeline model
149 * @return PI table action
150 * @throws PiTranslationException if the treatment cannot be translated or if the PI action is not suitable for the
151 * given pipeline model
152 */
153 static PiTableAction translateTreatment(TrafficTreatment treatment, PiPipelineInterpreter interpreter,
154 PiTableId tableId, PiPipelineModel pipelineModel)
155 throws PiTranslationException {
156 PiTableModel tableModel = getTableModel(tableId, pipelineModel);
157 return typeCheckAction(buildAction(treatment, interpreter, tableId), tableModel);
158 }
159
160 private static PiTableModel getTableModel(PiTableId piTableId, PiPipelineModel pipelineModel)
161 throws PiTranslationException {
162 return pipelineModel.table(piTableId.toString())
163 .orElseThrow(() -> new PiTranslationException(format(
164 "Not such a table in pipeline model: %s", piTableId)));
165 }
166
Carmelo Cascone00a59962017-06-16 17:51:49 +0900167 /**
168 * Builds a PI action out of the given treatment, optionally using the given interpreter.
169 */
Yi Tseng82512da2017-08-16 19:46:36 -0700170 private static PiTableAction buildAction(TrafficTreatment treatment, PiPipelineInterpreter interpreter,
Carmelo Cascone87b9b392017-10-02 18:33:20 +0200171 PiTableId tableId)
172 throws PiTranslationException {
Carmelo Cascone00a59962017-06-16 17:51:49 +0900173
174 PiTableAction piTableAction = null;
175
176 // If treatment has only one instruction of type PiInstruction, use that.
177 for (Instruction inst : treatment.allInstructions()) {
178 if (inst.type() == Instruction.Type.PROTOCOL_INDEPENDENT) {
179 if (treatment.allInstructions().size() == 1) {
180 piTableAction = ((PiInstruction) inst).action();
181 } else {
Carmelo Cascone87b9b392017-10-02 18:33:20 +0200182 throw new PiTranslationException(format(
Carmelo Cascone00a59962017-06-16 17:51:49 +0900183 "Unable to translate treatment, found multiple instructions " +
184 "of which one is protocol-independent: %s", treatment));
185 }
186 }
187 }
188
189 if (piTableAction == null && interpreter != null) {
190 // No PiInstruction, use interpreter to build action.
191 try {
Carmelo Casconef3a1a382017-07-27 12:04:39 -0400192 piTableAction = interpreter.mapTreatment(treatment, tableId);
Carmelo Cascone00a59962017-06-16 17:51:49 +0900193 } catch (PiPipelineInterpreter.PiInterpreterException e) {
Carmelo Cascone87b9b392017-10-02 18:33:20 +0200194 throw new PiTranslationException(
Carmelo Cascone00a59962017-06-16 17:51:49 +0900195 "Interpreter was unable to translate treatment. " + e.getMessage());
196 }
197 }
198
199 if (piTableAction == null) {
200 // No PiInstruction, no interpreter. It's time to give up.
Carmelo Cascone87b9b392017-10-02 18:33:20 +0200201 throw new PiTranslationException(
Carmelo Cascone00a59962017-06-16 17:51:49 +0900202 "Unable to translate treatment, neither an interpreter or a "
203 + "protocol-independent instruction were provided.");
204 }
205
Yi Tseng82512da2017-08-16 19:46:36 -0700206 return piTableAction;
Carmelo Cascone00a59962017-06-16 17:51:49 +0900207 }
208
Yi Tseng82512da2017-08-16 19:46:36 -0700209 private static PiTableAction typeCheckAction(PiTableAction piTableAction, PiTableModel table)
Carmelo Cascone87b9b392017-10-02 18:33:20 +0200210 throws PiTranslationException {
Yi Tseng82512da2017-08-16 19:46:36 -0700211 switch (piTableAction.type()) {
212 case ACTION:
213 return checkPiAction((PiAction) piTableAction, table);
214 default:
215 // FIXME: should we check? how?
216 return piTableAction;
Carmelo Cascone00a59962017-06-16 17:51:49 +0900217
Yi Tseng82512da2017-08-16 19:46:36 -0700218 }
219 }
220
221 private static PiTableAction checkPiAction(PiAction piAction, PiTableModel table)
Carmelo Cascone87b9b392017-10-02 18:33:20 +0200222 throws PiTranslationException {
Carmelo Cascone00a59962017-06-16 17:51:49 +0900223 // Table supports this action?
224 PiActionModel actionModel = table.action(piAction.id().name()).orElseThrow(
Carmelo Cascone87b9b392017-10-02 18:33:20 +0200225 () -> new PiTranslationException(format("Not such action '%s' for table '%s'",
226 piAction.id(), table.name())));
Carmelo Cascone00a59962017-06-16 17:51:49 +0900227
228 // Is the number of runtime parameters correct?
229 if (actionModel.params().size() != piAction.parameters().size()) {
Carmelo Cascone87b9b392017-10-02 18:33:20 +0200230 throw new PiTranslationException(format(
Carmelo Cascone00a59962017-06-16 17:51:49 +0900231 "Wrong number of runtime parameters for action '%s', expected %d but found %d",
232 actionModel.name(), actionModel.params().size(), piAction.parameters().size()));
233 }
234
235 // Forge a new action instance with well-sized parameters.
236 // The same comment as in typeCheckFieldMatch() about duplicating field match instances applies here.
237 PiAction.Builder newActionBuilder = PiAction.builder().withId(piAction.id());
238 for (PiActionParam param : piAction.parameters()) {
239 PiActionParamModel paramModel = actionModel.param(param.id().name())
Carmelo Cascone87b9b392017-10-02 18:33:20 +0200240 .orElseThrow(() -> new PiTranslationException(format(
Carmelo Cascone00a59962017-06-16 17:51:49 +0900241 "Not such parameter '%s' for action '%s'", param.id(), actionModel.name())));
242 try {
243 newActionBuilder.withParameter(new PiActionParam(param.id(),
244 fit(param.value(), paramModel.bitWidth())));
245 } catch (ByteSequenceTrimException e) {
Carmelo Cascone87b9b392017-10-02 18:33:20 +0200246 throw new PiTranslationException(format(
Carmelo Cascone00a59962017-06-16 17:51:49 +0900247 "Size mismatch for parameter '%s' of action '%s': %s",
248 param.id(), piAction.id(), e.getMessage()));
249 }
250 }
251
252 return newActionBuilder.build();
253 }
254
255 /**
256 * Builds a collection of PI field matches out of the given selector, optionally using the given interpreter. The
257 * field matches returned are guaranteed to be compatible for the given table model.
258 */
Carmelo Cascone87b9b392017-10-02 18:33:20 +0200259 private static Collection<PiFieldMatch> translateFieldMatches(PiPipelineInterpreter interpreter,
260 TrafficSelector selector, PiTableModel tableModel)
261 throws PiTranslationException {
Carmelo Cascone00a59962017-06-16 17:51:49 +0900262
263 Map<PiHeaderFieldId, PiFieldMatch> fieldMatches = Maps.newHashMap();
264
265 // If present, find a PiCriterion and get its field matches as a map. Otherwise, use an empty map.
266 Map<PiHeaderFieldId, PiFieldMatch> piCriterionFields = selector.criteria().stream()
267 .filter(c -> c.type().equals(PROTOCOL_INDEPENDENT))
268 .map(c -> (PiCriterion) c)
269 .findFirst()
270 .map(PiCriterion::fieldMatches)
271 .map(c -> {
272 Map<PiHeaderFieldId, PiFieldMatch> fieldMap = Maps.newHashMap();
273 c.forEach(fieldMatch -> fieldMap.put(fieldMatch.fieldId(), fieldMatch));
274 return fieldMap;
275 })
276 .orElse(Maps.newHashMap());
277
278 Set<Criterion> translatedCriteria = Sets.newHashSet();
279 Set<Criterion> ignoredCriteria = Sets.newHashSet();
280 Set<PiHeaderFieldId> usedPiCriterionFields = Sets.newHashSet();
281 Set<PiHeaderFieldId> ignoredPiCriterionFields = Sets.newHashSet();
282
283 for (PiTableMatchFieldModel fieldModel : tableModel.matchFields()) {
284
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200285 PiHeaderFieldId fieldId = PiHeaderFieldId.of(fieldModel.field().header().name(),
Carmelo Cascone00a59962017-06-16 17:51:49 +0900286 fieldModel.field().type().name(),
287 fieldModel.field().header().index());
288
Carmelo Casconeca94bcf2017-10-27 14:16:59 -0700289 // FIXME: workaround until ONOS-7066 is resolved
290 if (fieldId.id().startsWith("scalars")) {
291 String newFieldId = fieldId.id()
292 .replace("scalars.", "")
293 .replace("_t.", ".");
294 String[] piecies = newFieldId.split("\\.");
295 fieldId = PiHeaderFieldId.of(piecies[0], piecies[1]);
296 }
297
Carmelo Cascone00a59962017-06-16 17:51:49 +0900298 int bitWidth = fieldModel.field().type().bitWidth();
299 int fieldByteWidth = (int) Math.ceil((double) bitWidth / 8);
300
301 Optional<Criterion.Type> criterionType =
302 interpreter == null
303 ? Optional.empty()
304 : interpreter.mapPiHeaderFieldId(fieldId);
305
306 Criterion criterion = criterionType.map(selector::getCriterion).orElse(null);
307
308 if (!piCriterionFields.containsKey(fieldId) && criterion == null) {
309 // Neither a field in PiCriterion is available nor a Criterion mapping is possible.
310 // Can ignore if the match is ternary or LPM.
311 switch (fieldModel.matchType()) {
312 case TERNARY:
313 // Wildcard the whole field.
314 fieldMatches.put(fieldId, new PiTernaryFieldMatch(
315 fieldId,
316 ImmutableByteSequence.ofZeros(fieldByteWidth),
317 ImmutableByteSequence.ofZeros(fieldByteWidth)));
318 break;
319 case LPM:
320 // LPM with prefix 0
321 fieldMatches.put(fieldId, new PiLpmFieldMatch(fieldId,
322 ImmutableByteSequence.ofZeros(fieldByteWidth),
323 0));
324 break;
325 // FIXME: Can we handle the case of RANGE or VALID match?
326 default:
Carmelo Cascone87b9b392017-10-02 18:33:20 +0200327 throw new PiTranslationException(format(
Carmelo Cascone00a59962017-06-16 17:51:49 +0900328 "No value found for required match field '%s'", fieldId));
329 }
330 // Next field.
331 continue;
332 }
333
334 PiFieldMatch fieldMatch = null;
335
336 if (criterion != null) {
337 // Criterion mapping is possible for this field id.
338 try {
339 fieldMatch = translateCriterion(criterion, fieldId, fieldModel.matchType(), bitWidth);
340 translatedCriteria.add(criterion);
Carmelo Cascone87b9b392017-10-02 18:33:20 +0200341 } catch (PiTranslationException ex) {
Carmelo Cascone00a59962017-06-16 17:51:49 +0900342 // Ignore exception if the same field was found in PiCriterion.
343 if (piCriterionFields.containsKey(fieldId)) {
344 ignoredCriteria.add(criterion);
345 } else {
346 throw ex;
347 }
348 }
349 }
350
351 if (piCriterionFields.containsKey(fieldId)) {
352 // Field was found in PiCriterion.
353 if (fieldMatch != null) {
354 // Field was already translated from other criterion.
355 // Throw exception only if we are trying to match on different values of the same field...
356 if (!fieldMatch.equals(piCriterionFields.get(fieldId))) {
Carmelo Cascone87b9b392017-10-02 18:33:20 +0200357 throw new PiTranslationException(format(
Carmelo Cascone00a59962017-06-16 17:51:49 +0900358 "Duplicate match field '%s': instance translated from criterion '%s' is different to " +
359 "what found in PiCriterion.", fieldId, criterion.type()));
360 }
361 ignoredPiCriterionFields.add(fieldId);
362 } else {
363 fieldMatch = piCriterionFields.get(fieldId);
364 fieldMatch = typeCheckFieldMatch(fieldMatch, fieldModel);
365 usedPiCriterionFields.add(fieldId);
366 }
367 }
368
369 fieldMatches.put(fieldId, fieldMatch);
370 }
371
372 // Check if all criteria have been translated.
373 StringJoiner skippedCriteriaJoiner = new StringJoiner(", ");
374 selector.criteria().stream()
375 .filter(c -> !c.type().equals(PROTOCOL_INDEPENDENT))
376 .filter(c -> !translatedCriteria.contains(c) && !ignoredCriteria.contains(c))
377 .forEach(c -> skippedCriteriaJoiner.add(c.type().name()));
378 if (skippedCriteriaJoiner.length() > 0) {
Carmelo Cascone87b9b392017-10-02 18:33:20 +0200379 throw new PiTranslationException(format(
Carmelo Cascone00a59962017-06-16 17:51:49 +0900380 "The following criteria cannot be translated for table '%s': %s",
381 tableModel.name(), skippedCriteriaJoiner.toString()));
382 }
383
384 // Check if all fields found in PiCriterion have been used.
385 StringJoiner skippedPiFieldsJoiner = new StringJoiner(", ");
386 piCriterionFields.keySet().stream()
387 .filter(k -> !usedPiCriterionFields.contains(k) && !ignoredPiCriterionFields.contains(k))
388 .forEach(k -> skippedPiFieldsJoiner.add(k.id()));
389 if (skippedPiFieldsJoiner.length() > 0) {
Carmelo Cascone87b9b392017-10-02 18:33:20 +0200390 throw new PiTranslationException(format(
Carmelo Cascone00a59962017-06-16 17:51:49 +0900391 "The following PiCriterion field matches are not supported in table '%s': %s",
392 tableModel.name(), skippedPiFieldsJoiner.toString()));
393 }
394
395 return fieldMatches.values();
396 }
397
398 private static PiFieldMatch typeCheckFieldMatch(PiFieldMatch fieldMatch, PiTableMatchFieldModel fieldModel)
Carmelo Cascone87b9b392017-10-02 18:33:20 +0200399 throws PiTranslationException {
Carmelo Cascone00a59962017-06-16 17:51:49 +0900400
401 // Check parameter type and size
402 if (!fieldModel.matchType().equals(fieldMatch.type())) {
Carmelo Cascone87b9b392017-10-02 18:33:20 +0200403 throw new PiTranslationException(format(
Carmelo Cascone00a59962017-06-16 17:51:49 +0900404 "Wrong match type for field '%s', expected %s, but found %s",
405 fieldMatch.fieldId(), fieldModel.matchType().name(), fieldMatch.type().name()));
406 }
407
408 int modelBitWidth = fieldModel.field().type().bitWidth();
409
410 /*
411 Here we try to be robust against wrong size fields with the goal of having PiCriterion independent of the
412 pipeline model. We duplicate the field match, fitting the byte sequences to the bit-width specified in the
413 model. This operation is expensive when performed for each field match of each flow rule, but should be
414 mitigated by the translation cache provided by PiFlowRuleTranslationServiceImpl.
415 */
416
417 try {
418 switch (fieldModel.matchType()) {
419 case EXACT:
420 return new PiExactFieldMatch(fieldMatch.fieldId(),
421 fit(((PiExactFieldMatch) fieldMatch).value(), modelBitWidth));
422 case TERNARY:
423 return new PiTernaryFieldMatch(fieldMatch.fieldId(),
424 fit(((PiTernaryFieldMatch) fieldMatch).value(), modelBitWidth),
425 fit(((PiTernaryFieldMatch) fieldMatch).mask(), modelBitWidth));
426 case LPM:
427 PiLpmFieldMatch lpmfield = (PiLpmFieldMatch) fieldMatch;
428 if (lpmfield.prefixLength() > modelBitWidth) {
Carmelo Cascone87b9b392017-10-02 18:33:20 +0200429 throw new PiTranslationException(format(
Carmelo Cascone00a59962017-06-16 17:51:49 +0900430 "Invalid prefix length for LPM field '%s', found %d but field has bit-width %d",
431 fieldMatch.fieldId(), lpmfield.prefixLength(), modelBitWidth));
432 }
433 return new PiLpmFieldMatch(fieldMatch.fieldId(),
434 fit(lpmfield.value(), modelBitWidth),
435 lpmfield.prefixLength());
436 case RANGE:
437 return new PiRangeFieldMatch(fieldMatch.fieldId(),
438 fit(((PiRangeFieldMatch) fieldMatch).lowValue(), modelBitWidth),
439 fit(((PiRangeFieldMatch) fieldMatch).highValue(), modelBitWidth));
440 case VALID:
441 return fieldMatch;
442 default:
443 // Should never be here.
444 throw new RuntimeException(
445 "Unrecognized match type " + fieldModel.matchType().name());
446 }
447 } catch (ByteSequenceTrimException e) {
Carmelo Cascone87b9b392017-10-02 18:33:20 +0200448 throw new PiTranslationException(format(
Carmelo Cascone00a59962017-06-16 17:51:49 +0900449 "Size mismatch for field %s: %s", fieldMatch.fieldId(), e.getMessage()));
450 }
451 }
452}