blob: 19e4c3a77bf0605844c87bca5c1ed11e2b8778fb [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 {
50 this.value = fit(value, bitWidth);
51 this.bitWidth = bitWidth;
52 this.initType = PiMatchType.EXACT;
53 }
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 {
65 this.value = fit(value, bitWidth);
66 this.mask = fit(mask, bitWidth);
67 this.bitWidth = bitWidth;
68 this.initType = PiMatchType.TERNARY;
69 }
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 {
81 this.value = fit(value, bitWidth);
82 this.prefixLength = prefixLength;
83 this.bitWidth = bitWidth;
84 this.initType = PiMatchType.LPM;
85 }
86
87 @Override
88 public ImmutableByteSequence exactMatch() throws CriterionTranslatorException {
89 switch (initType) {
90 case EXACT:
91 break;
92 case TERNARY:
93 ImmutableByteSequence exactMask = ImmutableByteSequence.ofOnes(value.size());
94 if (!mask.equals(exactMask)) {
95 throw new CriterionTranslator.CriterionTranslatorException(
96 "trying to use masked field as an exact match, but mask is not exact");
97 }
98 break;
99 case LPM:
100 if (prefixLength < bitWidth) {
101 throw new CriterionTranslator.CriterionTranslatorException(
102 "trying to use LPM field as an exact match, but prefix is not full");
103 }
104 break;
105 default:
106 throw new RuntimeException("Unrecognized init type " + initType.name());
107 }
108 return value;
109 }
110
111 @Override
112 public Pair<ImmutableByteSequence, ImmutableByteSequence> ternaryMatch() {
113 switch (initType) {
114 case EXACT:
115 mask = ImmutableByteSequence.ofOnes(value.size());
116 break;
117 case TERNARY:
118 break;
119 case LPM:
120 mask = getMaskFromPrefixLength(prefixLength, value.size());
121 default:
122 throw new RuntimeException("Unrecognized init type " + initType.name());
123 }
124
125 return Pair.of(value, mask);
126 }
127
128 @Override
129 public Pair<ImmutableByteSequence, Integer> lpmMatch() throws CriterionTranslatorException {
130 switch (initType) {
131 case EXACT:
132 prefixLength = bitWidth;
133 break;
134 case TERNARY:
135 prefixLength = getPrefixLengthFromMask(mask).orElseThrow(
136 () -> new CriterionTranslatorException(
137 "trying to use masked field as a longest-prefix match, " +
138 "but mask is not equivalent to a prefix length"));
139 break;
140 case LPM:
141 break;
142 default:
143 throw new RuntimeException("Unrecognized init type " + initType.name());
144 }
145
146 return Pair.of(value, prefixLength);
147 }
148
149 /**
150 * Returns a bit mask equivalent to the given prefix length.
151 *
152 * @param prefixLength prefix length (in bits)
153 * @param maskSize mask size (in bytes)
154 * @return a byte sequence
155 */
156 private ImmutableByteSequence getMaskFromPrefixLength(int prefixLength, int maskSize) {
157 // TODO: implement.
158 throw new RuntimeException("getMaskFromPrefixLength() not implemented yet.");
159 }
160
161 /**
162 * Checks that the given mask is equivalent to a longest-prefix match and returns the prefix length. If not
163 * possible, the optional value will not be present.
164 *
165 * @param mask byte sequence
166 * @return optional prefix length
167 */
168 private Optional<Integer> getPrefixLengthFromMask(ImmutableByteSequence mask) {
169 // TODO: implement.
170 throw new RuntimeException("getPrefixLengthFromMask() not implemented yet.");
171 }
172}