blob: d403ec17da287603fa2817a8ae72deaf5c78d548 [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 org.apache.commons.lang3.tuple.Pair;
20import org.onlab.util.ImmutableByteSequence;
21import org.onosproject.net.pi.model.PiMatchType;
22
23import java.util.Optional;
24
25import static org.onlab.util.ImmutableByteSequence.ByteSequenceTrimException;
26import static org.onlab.util.ImmutableByteSequence.fit;
27
28/**
29 * Abstract implementation of a criterion translator that opportunistically tries to generate different types of match
30 * based on an initialization method. It throws an exception when a safe translation is not possible, e.g. when trying
31 * to translate a masked criterion to an exact match.
32 */
33abstract class AbstractCriterionTranslator implements CriterionTranslator {
34
35 private PiMatchType initType;
36 private int bitWidth;
37 private ImmutableByteSequence value;
38 private ImmutableByteSequence mask;
39 private Integer prefixLength;
40
41 /**
42 * Initializes the translator as an exact match.
43 *
44 * @param value exact match value
45 * @param bitWidth field bit-width
46 * @throws ByteSequenceTrimException if the match value cannot be trimmed to fit the field match bit-width
47 */
48 void initAsExactMatch(ImmutableByteSequence value, int bitWidth)
49 throws ByteSequenceTrimException {
Yi Tseng088f4ce2017-08-15 10:54:14 -070050 this.initType = PiMatchType.EXACT;
Carmelo Cascone00a59962017-06-16 17:51:49 +090051 this.value = fit(value, bitWidth);
52 this.bitWidth = bitWidth;
Carmelo Cascone00a59962017-06-16 17:51:49 +090053 }
54
55 /**
56 * Initializes the translator as a ternary match.
57 *
58 * @param value match value
59 * @param mask match mask
60 * @param bitWidth field bit-width
61 * @throws ByteSequenceTrimException if the match value or mask cannot be trimmed to fit the field match bit-width
62 */
63 void initAsTernaryMatch(ImmutableByteSequence value, ImmutableByteSequence mask, int bitWidth)
64 throws ByteSequenceTrimException {
Yi Tseng088f4ce2017-08-15 10:54:14 -070065 this.initType = PiMatchType.TERNARY;
Carmelo Cascone00a59962017-06-16 17:51:49 +090066 this.value = fit(value, bitWidth);
67 this.mask = fit(mask, bitWidth);
68 this.bitWidth = bitWidth;
Carmelo Cascone00a59962017-06-16 17:51:49 +090069 }
70
71 /**
72 * Initializes the translator as a longest-prefix match.
73 *
74 * @param value match value
75 * @param prefixLength prefix length
76 * @param bitWidth field bit-width
77 * @throws ByteSequenceTrimException if the match value cannot be trimmed to fit the field match bit-width
78 */
79 void initAsLpm(ImmutableByteSequence value, int prefixLength, int bitWidth)
80 throws ByteSequenceTrimException {
Yi Tseng088f4ce2017-08-15 10:54:14 -070081 this.initType = PiMatchType.LPM;
Carmelo Cascone00a59962017-06-16 17:51:49 +090082 this.value = fit(value, bitWidth);
83 this.prefixLength = prefixLength;
84 this.bitWidth = bitWidth;
Yi Tseng088f4ce2017-08-15 10:54:14 -070085 }
86
87 /**
88 * Computes the prefix padding size (in bits) based on value and bit width.
89 *
90 * @return prefix padding in bits
91 */
92 private int prefixPadding() {
93 return value.size() * Byte.SIZE - this.bitWidth;
Carmelo Cascone00a59962017-06-16 17:51:49 +090094 }
95
96 @Override
97 public ImmutableByteSequence exactMatch() throws CriterionTranslatorException {
98 switch (initType) {
99 case EXACT:
100 break;
101 case TERNARY:
102 ImmutableByteSequence exactMask = ImmutableByteSequence.ofOnes(value.size());
103 if (!mask.equals(exactMask)) {
104 throw new CriterionTranslator.CriterionTranslatorException(
105 "trying to use masked field as an exact match, but mask is not exact");
106 }
107 break;
108 case LPM:
109 if (prefixLength < bitWidth) {
110 throw new CriterionTranslator.CriterionTranslatorException(
111 "trying to use LPM field as an exact match, but prefix is not full");
112 }
113 break;
114 default:
115 throw new RuntimeException("Unrecognized init type " + initType.name());
116 }
117 return value;
118 }
119
120 @Override
121 public Pair<ImmutableByteSequence, ImmutableByteSequence> ternaryMatch() {
122 switch (initType) {
123 case EXACT:
Yi Tseng088f4ce2017-08-15 10:54:14 -0700124 mask = ImmutableByteSequence.prefixZeros(value.size(), prefixPadding());
Carmelo Cascone00a59962017-06-16 17:51:49 +0900125 break;
126 case TERNARY:
127 break;
128 case LPM:
129 mask = getMaskFromPrefixLength(prefixLength, value.size());
130 default:
131 throw new RuntimeException("Unrecognized init type " + initType.name());
132 }
133
134 return Pair.of(value, mask);
135 }
136
137 @Override
138 public Pair<ImmutableByteSequence, Integer> lpmMatch() throws CriterionTranslatorException {
139 switch (initType) {
140 case EXACT:
141 prefixLength = bitWidth;
142 break;
143 case TERNARY:
144 prefixLength = getPrefixLengthFromMask(mask).orElseThrow(
145 () -> new CriterionTranslatorException(
146 "trying to use masked field as a longest-prefix match, " +
147 "but mask is not equivalent to a prefix length"));
148 break;
149 case LPM:
150 break;
151 default:
152 throw new RuntimeException("Unrecognized init type " + initType.name());
153 }
154
155 return Pair.of(value, prefixLength);
156 }
157
158 /**
159 * Returns a bit mask equivalent to the given prefix length.
160 *
161 * @param prefixLength prefix length (in bits)
162 * @param maskSize mask size (in bytes)
163 * @return a byte sequence
164 */
165 private ImmutableByteSequence getMaskFromPrefixLength(int prefixLength, int maskSize) {
166 // TODO: implement.
167 throw new RuntimeException("getMaskFromPrefixLength() not implemented yet.");
168 }
169
170 /**
171 * Checks that the given mask is equivalent to a longest-prefix match and returns the prefix length. If not
172 * possible, the optional value will not be present.
173 *
174 * @param mask byte sequence
175 * @return optional prefix length
176 */
177 private Optional<Integer> getPrefixLengthFromMask(ImmutableByteSequence mask) {
178 // TODO: implement.
179 throw new RuntimeException("getPrefixLengthFromMask() not implemented yet.");
180 }
181}