Carmelo Cascone

ONOS-4044 Implemented ONOS-to-Bmv2 flow rule translator

In Bmv2, tables, header fields and actions all depend on the packet
processing model configuration (Bmv2Model) currently deployed on the
device. For this reason, translation is needed from protocol-aware ONOS
FlowRule objects into properly formatted, protocol-independent
Bmv2TableEntry objects. Translation is based on a TranslatorConfig that
provides a mapping between ONOS types and Bmv2 model-dependent types.

Change-Id: I620802c2024b5250867dc6b1b988b739177f582a
1 +/*
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 +
17 +package org.onosproject.drivers.bmv2.translators;
18 +
19 +import com.google.common.annotations.Beta;
20 +import org.onlab.util.ImmutableByteSequence;
21 +import org.onosproject.bmv2.api.model.Bmv2Model;
22 +import org.onosproject.bmv2.api.model.Bmv2ModelField;
23 +import org.onosproject.bmv2.api.model.Bmv2ModelTable;
24 +import org.onosproject.bmv2.api.model.Bmv2ModelTableKey;
25 +import org.onosproject.bmv2.api.runtime.Bmv2Action;
26 +import org.onosproject.bmv2.api.runtime.Bmv2ExtensionSelector;
27 +import org.onosproject.bmv2.api.runtime.Bmv2ExtensionTreatment;
28 +import org.onosproject.bmv2.api.runtime.Bmv2LpmMatchParam;
29 +import org.onosproject.bmv2.api.runtime.Bmv2MatchKey;
30 +import org.onosproject.bmv2.api.runtime.Bmv2TableEntry;
31 +import org.onosproject.bmv2.api.runtime.Bmv2TernaryMatchParam;
32 +import org.onosproject.net.flow.FlowRule;
33 +import org.onosproject.net.flow.TrafficSelector;
34 +import org.onosproject.net.flow.TrafficTreatment;
35 +import org.onosproject.net.flow.criteria.Criterion;
36 +import org.onosproject.net.flow.criteria.EthCriterion;
37 +import org.onosproject.net.flow.criteria.EthTypeCriterion;
38 +import org.onosproject.net.flow.criteria.ExtensionCriterion;
39 +import org.onosproject.net.flow.criteria.ExtensionSelector;
40 +import org.onosproject.net.flow.criteria.ExtensionSelectorType.ExtensionSelectorTypes;
41 +import org.onosproject.net.flow.criteria.PortCriterion;
42 +import org.onosproject.net.flow.instructions.ExtensionTreatment;
43 +import org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes;
44 +import org.onosproject.net.flow.instructions.Instruction;
45 +import org.onosproject.net.flow.instructions.Instructions;
46 +import org.onosproject.net.flow.instructions.Instructions.ExtensionInstructionWrapper;
47 +
48 +/**
49 + * Default Bmv2 flow rule translator implementation.
50 + * <p>
51 + * Flow rules are translated into {@link Bmv2TableEntry BMv2 table entries} according to the following logic:
52 + * <ul>
53 + * <li> table name: obtained from the Bmv2 model using the flow rule table ID;
54 + * <li> match key: if the flow rule selector defines only a criterion of type {@link Criterion.Type#EXTENSION EXTENSION}
55 + * , then the latter is expected to contain a {@link Bmv2ExtensionSelector Bmv2ExtensionSelector}, which should provide
56 + * a match key already formatted for the given table; otherwise a match key is built using the
57 + * {@link TranslatorConfig#fieldToCriterionTypeMap() mapping} defined by this translator configuration.
58 + * <li> action: if the flow rule treatment contains only one instruction of type
59 + * {@link Instruction.Type#EXTENSION EXTENSION}, then the latter is expected to contain a {@link Bmv2ExtensionTreatment}
60 + * , which should provide a {@link Bmv2Action} already formatted for the given table; otherwise, an action is
61 + * {@link TranslatorConfig#buildAction(TrafficTreatment) built} using this translator configuration.
62 + * <li> priority: the same as the flow rule.
63 + * <li> timeout: if the table supports timeout, use the same as the flow rule, otherwise none (i.e. permanent entry).
64 + * </ul>
65 + */
66 +@Beta
67 +public class Bmv2DefaultFlowRuleTranslator implements Bmv2FlowRuleTranslator {
68 +
69 + // TODO: config is harcoded now, instead it should be selected based on device model
70 + private final TranslatorConfig config = new Bmv2SimplePipelineTranslatorConfig();
71 + private final Bmv2Model model = config.model();
72 +
73 + private static Bmv2TernaryMatchParam buildTernaryParam(Bmv2ModelField field, Criterion criterion, int byteWidth)
74 + throws Bmv2FlowRuleTranslatorException {
75 +
76 + // Value and mask will be filled according to criterion type
77 + ImmutableByteSequence value;
78 + ImmutableByteSequence mask = null;
79 +
80 + switch (criterion.type()) {
81 + case IN_PORT:
82 + // FIXME: allow port numbers of variable bit length (based on model), truncating when necessary
83 + short port = (short) ((PortCriterion) criterion).port().toLong();
84 + value = ImmutableByteSequence.copyFrom(port);
85 + break;
86 + case ETH_DST:
87 + EthCriterion c = (EthCriterion) criterion;
88 + value = ImmutableByteSequence.copyFrom(c.mac().toBytes());
89 + if (c.mask() != null) {
90 + mask = ImmutableByteSequence.copyFrom(c.mask().toBytes());
91 + }
92 + break;
93 + case ETH_SRC:
94 + EthCriterion c2 = (EthCriterion) criterion;
95 + value = ImmutableByteSequence.copyFrom(c2.mac().toBytes());
96 + if (c2.mask() != null) {
97 + mask = ImmutableByteSequence.copyFrom(c2.mask().toBytes());
98 + }
99 + break;
100 + case ETH_TYPE:
101 + short ethType = ((EthTypeCriterion) criterion).ethType().toShort();
102 + value = ImmutableByteSequence.copyFrom(ethType);
103 + break;
104 + // TODO: implement building for other criterion types (easy with DefaultCriterion of ONOS-4034)
105 + default:
106 + throw new Bmv2FlowRuleTranslatorException("Feature not implemented, ternary builder for criterion" +
107 + "type: " + criterion.type().name());
108 + }
109 +
110 + if (mask == null) {
111 + // no mask, all ones
112 + mask = ImmutableByteSequence.ofOnes(byteWidth);
113 + }
114 +
115 + return new Bmv2TernaryMatchParam(value, mask);
116 + }
117 +
118 + private static Bmv2MatchKey getMatchKeyFromExtension(ExtensionCriterion criterion)
119 + throws Bmv2FlowRuleTranslatorException {
120 +
121 + ExtensionSelector extSelector = criterion.extensionSelector();
122 +
123 + if (extSelector.type() == ExtensionSelectorTypes.P4_BMV2_MATCH_KEY.type()) {
124 + if (extSelector instanceof Bmv2ExtensionSelector) {
125 + return ((Bmv2ExtensionSelector) extSelector).matchKey();
126 + } else {
127 + throw new Bmv2FlowRuleTranslatorException("Unable to decode extension selector " + extSelector);
128 + }
129 + } else {
130 + throw new Bmv2FlowRuleTranslatorException("Unsupported extension selector type " + extSelector.type());
131 + }
132 + }
133 +
134 + private static Bmv2Action getActionFromExtension(Instructions.ExtensionInstructionWrapper inst)
135 + throws Bmv2FlowRuleTranslatorException {
136 +
137 + ExtensionTreatment extTreatment = inst.extensionInstruction();
138 +
139 + if (extTreatment.type() == ExtensionTreatmentTypes.P4_BMV2_ACTION.type()) {
140 + if (extTreatment instanceof Bmv2ExtensionTreatment) {
141 + return ((Bmv2ExtensionTreatment) extTreatment).getAction();
142 + } else {
143 + throw new Bmv2FlowRuleTranslatorException("Unable to decode treatment extension: " + extTreatment);
144 + }
145 + } else {
146 + throw new Bmv2FlowRuleTranslatorException("Unsupported treatment extension type: " + extTreatment.type());
147 + }
148 + }
149 +
150 + private static Bmv2MatchKey buildMatchKey(TranslatorConfig config, TrafficSelector selector, Bmv2ModelTable table)
151 + throws Bmv2FlowRuleTranslatorException {
152 +
153 + Bmv2MatchKey.Builder matchKeyBuilder = Bmv2MatchKey.builder();
154 +
155 + for (Bmv2ModelTableKey key : table.keys()) {
156 +
157 + String fieldName = key.field().header().name() + "." + key.field().type().name();
158 + int byteWidth = (int) Math.ceil((double) key.field().type().bitWidth() / 8.0);
159 + Criterion.Type criterionType = config.fieldToCriterionTypeMap().get(fieldName);
160 +
161 + if (criterionType == null || selector.getCriterion(criterionType) == null) {
162 + // A mapping is not available or the selector doesn't have such a type
163 + switch (key.matchType()) {
164 + case TERNARY:
165 + // Wildcard field
166 + matchKeyBuilder.withWildcard(byteWidth);
167 + break;
168 + case LPM:
169 + // LPM with prefix 0
170 + matchKeyBuilder.add(new Bmv2LpmMatchParam(ImmutableByteSequence.ofZeros(byteWidth), 0));
171 + break;
172 + default:
173 + throw new Bmv2FlowRuleTranslatorException("Match field not supported: " + fieldName);
174 + }
175 + // Next key
176 + continue;
177 + }
178 +
179 + Criterion criterion = selector.getCriterion(criterionType);
180 + Bmv2TernaryMatchParam matchParam = null;
181 +
182 + switch (key.matchType()) {
183 + case TERNARY:
184 + matchParam = buildTernaryParam(key.field(), criterion, byteWidth);
185 + break;
186 + default:
187 + // TODO: implement other match param builders (exact, LPM, etc.)
188 + throw new Bmv2FlowRuleTranslatorException("Feature not implemented, match param builder: "
189 + + key.matchType().name());
190 + }
191 +
192 + matchKeyBuilder.add(matchParam);
193 + }
194 +
195 + return matchKeyBuilder.build();
196 + }
197 +
198 + @Override
199 + public Bmv2TableEntry translate(FlowRule rule)
200 + throws Bmv2FlowRuleTranslatorException {
201 +
202 + int tableId = rule.tableId();
203 +
204 + Bmv2ModelTable table = model.table(tableId);
205 +
206 + if (table == null) {
207 + throw new Bmv2FlowRuleTranslatorException("Unknown table ID: " + tableId);
208 + }
209 +
210 + /* Translate selector */
211 +
212 + TrafficSelector selector = rule.selector();
213 + Bmv2MatchKey bmv2MatchKey = null;
214 +
215 + // If selector has only 1 criterion of type extension, use that
216 + Criterion criterion = selector.getCriterion(Criterion.Type.EXTENSION);
217 + if (criterion != null) {
218 + if (selector.criteria().size() == 1) {
219 + bmv2MatchKey = getMatchKeyFromExtension((ExtensionCriterion) criterion);
220 + } else {
221 + throw new Bmv2FlowRuleTranslatorException("Unable to translate traffic selector, found multiple " +
222 + "criteria of which one is an extension: " +
223 + selector.toString());
224 + }
225 + }
226 +
227 + if (bmv2MatchKey == null) {
228 + // not an extension
229 + bmv2MatchKey = buildMatchKey(config, selector, table);
230 + }
231 +
232 + /* Translate treatment */
233 +
234 + TrafficTreatment treatment = rule.treatment();
235 + Bmv2Action bmv2Action = null;
236 +
237 + // If treatment has only 1 instruction of type extension, use that
238 + for (Instruction inst : treatment.allInstructions()) {
239 + if (inst.type() == Instruction.Type.EXTENSION) {
240 + if (treatment.allInstructions().size() == 1) {
241 + bmv2Action = getActionFromExtension((ExtensionInstructionWrapper) inst);
242 + } else {
243 + throw new Bmv2FlowRuleTranslatorException("Unable to translate traffic treatment, found multiple " +
244 + "instructions of which one is an extension: " +
245 + selector.toString());
246 + }
247 + }
248 + }
249 +
250 + if (bmv2Action == null) {
251 + // No extension, use config to build action
252 + bmv2Action = config.buildAction(treatment);
253 + }
254 +
255 + if (bmv2Action == null) {
256 + // Config returned null
257 + throw new Bmv2FlowRuleTranslatorException("Unable to translate treatment: " + treatment);
258 + }
259 +
260 + Bmv2TableEntry.Builder tableEntryBuilder = Bmv2TableEntry.builder();
261 +
262 + tableEntryBuilder
263 + .withTableName(table.name())
264 + .withPriority(rule.priority())
265 + .withMatchKey(bmv2MatchKey)
266 + .withAction(bmv2Action);
267 +
268 + if (!rule.isPermanent()) {
269 + if (table.hasTimeouts()) {
270 + tableEntryBuilder.withTimeout((double) rule.timeout());
271 + }
272 + //FIXME: add warn log or exception?
273 + }
274 +
275 + return tableEntryBuilder.build();
276 + }
277 +
278 + @Override
279 + public TranslatorConfig config() {
280 + return this.config;
281 + }
282 +}
1 +/*
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 +
17 +package org.onosproject.drivers.bmv2.translators;
18 +
19 +import com.google.common.annotations.Beta;
20 +import org.onosproject.bmv2.api.model.Bmv2Model;
21 +import org.onosproject.bmv2.api.runtime.Bmv2Action;
22 +import org.onosproject.bmv2.api.runtime.Bmv2TableEntry;
23 +import org.onosproject.net.flow.FlowRule;
24 +import org.onosproject.net.flow.TrafficTreatment;
25 +import org.onosproject.net.flow.criteria.Criterion;
26 +
27 +import java.util.Map;
28 +
29 +/**
30 + * Translator of ONOS flow rules to BMv2 table entries. Translation depends on a
31 + * {@link TranslatorConfig translator configuration}.
32 + */
33 +@Beta
34 +public interface Bmv2FlowRuleTranslator {
35 +
36 + /**
37 + * Returns a new BMv2 table entry equivalent to the given flow rule.
38 + *
39 + * @param rule a flow rule
40 + * @return a BMv2 table entry
41 + * @throws Bmv2FlowRuleTranslatorException if the flow rule cannot be
42 + * translated
43 + */
44 + Bmv2TableEntry translate(FlowRule rule) throws Bmv2FlowRuleTranslatorException;
45 +
46 + /**
47 + * Returns the configuration of this translator.
48 + *
49 + * @return a translator configuration
50 + */
51 + TranslatorConfig config();
52 +
53 + /**
54 + * BMv2 flow rules translator configuration. Such a configuration is used to
55 + * generate table entries that are compatible with a given {@link Bmv2Model}.
56 + */
57 + @Beta
58 + interface TranslatorConfig {
59 + /**
60 + * Return the {@link Bmv2Model} associated with this configuration.
61 + *
62 + * @return a BMv2 model
63 + */
64 + Bmv2Model model();
65 +
66 + /**
67 + * Returns a map describing a one-to-one relationship between BMv2
68 + * header field names and ONOS criterion types. Header field names are
69 + * formatted using the notation {@code header_name.field_name}
70 + * representing a specific header field instance extracted by the BMv2
71 + * parser (e.g. {@code ethernet.dstAddr}).
72 + *
73 + * @return a map where the keys represent BMv2 header field names and
74 + * values are criterion types
75 + */
76 + Map<String, Criterion.Type> fieldToCriterionTypeMap();
77 +
78 + /**
79 + * Return a BMv2 action that is equivalent to the given ONOS traffic
80 + * treatment.
81 + *
82 + * @param treatment a traffic treatment
83 + * @return a BMv2 action object
84 + * @throws Bmv2FlowRuleTranslatorException if the treatment cannot be
85 + * translated to a BMv2 action
86 + */
87 + Bmv2Action buildAction(TrafficTreatment treatment)
88 + throws Bmv2FlowRuleTranslatorException;
89 + }
90 +}
1 +/*
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 +
17 +package org.onosproject.drivers.bmv2.translators;
18 +
19 +/**
20 + * BMv2 flow rule translator exception.
21 + */
22 +public class Bmv2FlowRuleTranslatorException extends Exception {
23 +
24 + Bmv2FlowRuleTranslatorException(String msg) {
25 + super(msg);
26 + }
27 +}
1 +/*
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 +
17 +package org.onosproject.drivers.bmv2.translators;
18 +
19 +import com.eclipsesource.json.Json;
20 +import com.eclipsesource.json.JsonObject;
21 +import com.google.common.annotations.Beta;
22 +import com.google.common.collect.Maps;
23 +import org.onlab.util.ImmutableByteSequence;
24 +import org.onosproject.bmv2.api.model.Bmv2Model;
25 +import org.onosproject.bmv2.api.runtime.Bmv2Action;
26 +import org.onosproject.net.flow.TrafficTreatment;
27 +import org.onosproject.net.flow.criteria.Criterion;
28 +import org.onosproject.net.flow.instructions.Instruction;
29 +import org.onosproject.net.flow.instructions.Instructions;
30 +
31 +import java.io.BufferedReader;
32 +import java.io.IOException;
33 +import java.io.InputStream;
34 +import java.io.InputStreamReader;
35 +import java.util.Map;
36 +
37 +/**
38 + * Implementation of a Bmv2 flow rule translator configuration for the
39 + * simple_pipeline.p4 model.
40 + */
41 +@Beta
42 +public class Bmv2SimplePipelineTranslatorConfig implements Bmv2FlowRuleTranslator.TranslatorConfig {
43 +
44 + private static final String JSON_CONFIG_PATH = "/simple_pipeline.json";
45 + private final Map<String, Criterion.Type> fieldMap = Maps.newHashMap();
46 + private final Bmv2Model model;
47 +
48 + /**
49 + * Creates a new simple pipeline translator configuration.
50 + */
51 + public Bmv2SimplePipelineTranslatorConfig() {
52 +
53 + this.model = getModel();
54 +
55 + // populate fieldMap
56 + fieldMap.put("standard_metadata.ingress_port", Criterion.Type.IN_PORT);
57 + fieldMap.put("ethernet.dstAddr", Criterion.Type.ETH_DST);
58 + fieldMap.put("ethernet.srcAddr", Criterion.Type.ETH_SRC);
59 + fieldMap.put("ethernet.etherType", Criterion.Type.ETH_TYPE);
60 + }
61 +
62 + private static Bmv2Action buildDropAction() {
63 + return Bmv2Action.builder()
64 + .withName("_drop")
65 + .build();
66 + }
67 +
68 + private static Bmv2Action buildFwdAction(Instructions.OutputInstruction inst)
69 + throws Bmv2FlowRuleTranslatorException {
70 +
71 + Bmv2Action.Builder actionBuilder = Bmv2Action.builder();
72 +
73 + actionBuilder.withName("fwd");
74 +
75 + if (inst.port().isLogical()) {
76 + throw new Bmv2FlowRuleTranslatorException(
77 + "Output logic port numbers not supported: " + inst);
78 + }
79 +
80 + actionBuilder.addParameter(
81 + ImmutableByteSequence.copyFrom((short) inst.port().toLong()));
82 +
83 + return actionBuilder.build();
84 + }
85 +
86 + private static Bmv2Model getModel() {
87 + InputStream inputStream = Bmv2SimplePipelineTranslatorConfig.class
88 + .getResourceAsStream(JSON_CONFIG_PATH);
89 + InputStreamReader reader = new InputStreamReader(inputStream);
90 + BufferedReader bufReader = new BufferedReader(reader);
91 + JsonObject json = null;
92 + try {
93 + json = Json.parse(bufReader).asObject();
94 + } catch (IOException e) {
95 + throw new RuntimeException("Unable to parse JSON file: " + e.getMessage());
96 + }
97 +
98 + return Bmv2Model.parse(json);
99 + }
100 +
101 + @Override
102 + public Bmv2Model model() {
103 + return this.model;
104 + }
105 +
106 + @Override
107 + public Map<String, Criterion.Type> fieldToCriterionTypeMap() {
108 + return fieldMap;
109 + }
110 +
111 + @Override
112 + public Bmv2Action buildAction(TrafficTreatment treatment)
113 + throws Bmv2FlowRuleTranslatorException {
114 +
115 +
116 + if (treatment.allInstructions().size() == 0) {
117 + // no instructions means drop
118 + return buildDropAction();
119 + } else if (treatment.allInstructions().size() > 1) {
120 + // otherwise, we understand treatments with only 1 instruction
121 + throw new Bmv2FlowRuleTranslatorException(
122 + "Treatment not supported, more than 1 instructions found: "
123 + + treatment.toString());
124 + }
125 +
126 + Instruction instruction = treatment.allInstructions().get(0);
127 +
128 + switch (instruction.type()) {
129 + case OUTPUT:
130 + return buildFwdAction((Instructions.OutputInstruction) instruction);
131 + case NOACTION:
132 + return buildDropAction();
133 + default:
134 + throw new Bmv2FlowRuleTranslatorException(
135 + "Instruction type not supported: "
136 + + instruction.type().name());
137 + }
138 + }
139 +}
1 +/*
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 +
17 +/**
18 + * Translators of ONOS abstractions to BMv2 model-dependent abstractions.
19 + */
20 +package org.onosproject.drivers.bmv2.translators;
...\ No newline at end of file ...\ No newline at end of file
1 +{
2 + "header_types": [
3 + {
4 + "name": "standard_metadata_t",
5 + "id": 0,
6 + "fields": [
7 + [
8 + "ingress_port",
9 + 9
10 + ],
11 + [
12 + "packet_length",
13 + 32
14 + ],
15 + [
16 + "egress_spec",
17 + 9
18 + ],
19 + [
20 + "egress_port",
21 + 9
22 + ],
23 + [
24 + "egress_instance",
25 + 32
26 + ],
27 + [
28 + "instance_type",
29 + 32
30 + ],
31 + [
32 + "clone_spec",
33 + 32
34 + ],
35 + [
36 + "_padding",
37 + 5
38 + ]
39 + ],
40 + "length_exp": null,
41 + "max_length": null
42 + },
43 + {
44 + "name": "ethernet_t",
45 + "id": 1,
46 + "fields": [
47 + [
48 + "dstAddr",
49 + 48
50 + ],
51 + [
52 + "srcAddr",
53 + 48
54 + ],
55 + [
56 + "etherType",
57 + 16
58 + ]
59 + ],
60 + "length_exp": null,
61 + "max_length": null
62 + },
63 + {
64 + "name": "intrinsic_metadata_t",
65 + "id": 2,
66 + "fields": [
67 + [
68 + "ingress_global_timestamp",
69 + 32
70 + ],
71 + [
72 + "lf_field_list",
73 + 32
74 + ],
75 + [
76 + "mcast_grp",
77 + 16
78 + ],
79 + [
80 + "egress_rid",
81 + 16
82 + ]
83 + ],
84 + "length_exp": null,
85 + "max_length": null
86 + },
87 + {
88 + "name": "cpu_header_t",
89 + "id": 3,
90 + "fields": [
91 + [
92 + "device",
93 + 8
94 + ],
95 + [
96 + "reason",
97 + 8
98 + ]
99 + ],
100 + "length_exp": null,
101 + "max_length": null
102 + }
103 + ],
104 + "headers": [
105 + {
106 + "name": "standard_metadata",
107 + "id": 0,
108 + "header_type": "standard_metadata_t",
109 + "metadata": true
110 + },
111 + {
112 + "name": "ethernet",
113 + "id": 1,
114 + "header_type": "ethernet_t",
115 + "metadata": false
116 + },
117 + {
118 + "name": "intrinsic_metadata",
119 + "id": 2,
120 + "header_type": "intrinsic_metadata_t",
121 + "metadata": true
122 + },
123 + {
124 + "name": "cpu_header",
125 + "id": 3,
126 + "header_type": "cpu_header_t",
127 + "metadata": false
128 + }
129 + ],
130 + "header_stacks": [],
131 + "parsers": [
132 + {
133 + "name": "parser",
134 + "id": 0,
135 + "init_state": "start",
136 + "parse_states": [
137 + {
138 + "name": "start",
139 + "id": 0,
140 + "parser_ops": [],
141 + "transition_key": [
142 + {
143 + "type": "lookahead",
144 + "value": [
145 + 0,
146 + 64
147 + ]
148 + }
149 + ],
150 + "transitions": [
151 + {
152 + "value": "0x0000000000000000",
153 + "mask": null,
154 + "next_state": "parse_cpu_header"
155 + },
156 + {
157 + "value": "default",
158 + "mask": null,
159 + "next_state": "parse_ethernet"
160 + }
161 + ]
162 + },
163 + {
164 + "name": "parse_cpu_header",
165 + "id": 1,
166 + "parser_ops": [
167 + {
168 + "op": "extract",
169 + "parameters": [
170 + {
171 + "type": "regular",
172 + "value": "cpu_header"
173 + }
174 + ]
175 + }
176 + ],
177 + "transition_key": [],
178 + "transitions": [
179 + {
180 + "value": "default",
181 + "mask": null,
182 + "next_state": "parse_ethernet"
183 + }
184 + ]
185 + },
186 + {
187 + "name": "parse_ethernet",
188 + "id": 2,
189 + "parser_ops": [
190 + {
191 + "op": "extract",
192 + "parameters": [
193 + {
194 + "type": "regular",
195 + "value": "ethernet"
196 + }
197 + ]
198 + }
199 + ],
200 + "transition_key": [],
201 + "transitions": [
202 + {
203 + "value": "default",
204 + "mask": null,
205 + "next_state": null
206 + }
207 + ]
208 + }
209 + ]
210 + }
211 + ],
212 + "deparsers": [
213 + {
214 + "name": "deparser",
215 + "id": 0,
216 + "order": [
217 + "cpu_header",
218 + "ethernet"
219 + ]
220 + }
221 + ],
222 + "meter_arrays": [],
223 + "actions": [
224 + {
225 + "name": "flood",
226 + "id": 0,
227 + "runtime_data": [],
228 + "primitives": [
229 + {
230 + "op": "modify_field",
231 + "parameters": [
232 + {
233 + "type": "field",
234 + "value": [
235 + "intrinsic_metadata",
236 + "mcast_grp"
237 + ]
238 + },
239 + {
240 + "type": "field",
241 + "value": [
242 + "standard_metadata",
243 + "ingress_port"
244 + ]
245 + }
246 + ]
247 + }
248 + ]
249 + },
250 + {
251 + "name": "_drop",
252 + "id": 1,
253 + "runtime_data": [],
254 + "primitives": [
255 + {
256 + "op": "modify_field",
257 + "parameters": [
258 + {
259 + "type": "field",
260 + "value": [
261 + "standard_metadata",
262 + "egress_spec"
263 + ]
264 + },
265 + {
266 + "type": "hexstr",
267 + "value": "0x1ff"
268 + }
269 + ]
270 + }
271 + ]
272 + },
273 + {
274 + "name": "fwd",
275 + "id": 2,
276 + "runtime_data": [
277 + {
278 + "name": "port",
279 + "bitwidth": 9
280 + }
281 + ],
282 + "primitives": [
283 + {
284 + "op": "modify_field",
285 + "parameters": [
286 + {
287 + "type": "field",
288 + "value": [
289 + "standard_metadata",
290 + "egress_spec"
291 + ]
292 + },
293 + {
294 + "type": "runtime_data",
295 + "value": 0
296 + }
297 + ]
298 + }
299 + ]
300 + },
301 + {
302 + "name": "send_to_cpu",
303 + "id": 3,
304 + "runtime_data": [
305 + {
306 + "name": "device",
307 + "bitwidth": 8
308 + },
309 + {
310 + "name": "reason",
311 + "bitwidth": 8
312 + }
313 + ],
314 + "primitives": [
315 + {
316 + "op": "add_header",
317 + "parameters": [
318 + {
319 + "type": "header",
320 + "value": "cpu_header"
321 + }
322 + ]
323 + },
324 + {
325 + "op": "modify_field",
326 + "parameters": [
327 + {
328 + "type": "field",
329 + "value": [
330 + "cpu_header",
331 + "device"
332 + ]
333 + },
334 + {
335 + "type": "runtime_data",
336 + "value": 0
337 + }
338 + ]
339 + },
340 + {
341 + "op": "modify_field",
342 + "parameters": [
343 + {
344 + "type": "field",
345 + "value": [
346 + "cpu_header",
347 + "reason"
348 + ]
349 + },
350 + {
351 + "type": "runtime_data",
352 + "value": 1
353 + }
354 + ]
355 + },
356 + {
357 + "op": "modify_field",
358 + "parameters": [
359 + {
360 + "type": "field",
361 + "value": [
362 + "standard_metadata",
363 + "egress_spec"
364 + ]
365 + },
366 + {
367 + "type": "hexstr",
368 + "value": "0xfa"
369 + }
370 + ]
371 + }
372 + ]
373 + }
374 + ],
375 + "pipelines": [
376 + {
377 + "name": "ingress",
378 + "id": 0,
379 + "init_table": "table0",
380 + "tables": [
381 + {
382 + "name": "table0",
383 + "id": 0,
384 + "match_type": "ternary",
385 + "type": "simple",
386 + "max_size": 16384,
387 + "with_counters": false,
388 + "direct_meters": null,
389 + "support_timeout": false,
390 + "key": [
391 + {
392 + "match_type": "ternary",
393 + "target": [
394 + "standard_metadata",
395 + "ingress_port"
396 + ],
397 + "mask": null
398 + },
399 + {
400 + "match_type": "ternary",
401 + "target": [
402 + "ethernet",
403 + "dstAddr"
404 + ],
405 + "mask": null
406 + },
407 + {
408 + "match_type": "ternary",
409 + "target": [
410 + "ethernet",
411 + "srcAddr"
412 + ],
413 + "mask": null
414 + },
415 + {
416 + "match_type": "ternary",
417 + "target": [
418 + "ethernet",
419 + "etherType"
420 + ],
421 + "mask": null
422 + }
423 + ],
424 + "actions": [
425 + "fwd",
426 + "flood",
427 + "send_to_cpu",
428 + "_drop"
429 + ],
430 + "next_tables": {
431 + "fwd": null,
432 + "flood": null,
433 + "send_to_cpu": null,
434 + "_drop": null
435 + },
436 + "default_action": null
437 + }
438 + ],
439 + "conditionals": []
440 + },
441 + {
442 + "name": "egress",
443 + "id": 1,
444 + "init_table": null,
445 + "tables": [],
446 + "conditionals": []
447 + }
448 + ],
449 + "calculations": [],
450 + "checksums": [],
451 + "learn_lists": [],
452 + "field_lists": [],
453 + "counter_arrays": [],
454 + "register_arrays": [],
455 + "force_arith": [
456 + [
457 + "standard_metadata",
458 + "ingress_port"
459 + ],
460 + [
461 + "standard_metadata",
462 + "packet_length"
463 + ],
464 + [
465 + "standard_metadata",
466 + "egress_spec"
467 + ],
468 + [
469 + "standard_metadata",
470 + "egress_port"
471 + ],
472 + [
473 + "standard_metadata",
474 + "egress_instance"
475 + ],
476 + [
477 + "standard_metadata",
478 + "instance_type"
479 + ],
480 + [
481 + "standard_metadata",
482 + "clone_spec"
483 + ],
484 + [
485 + "standard_metadata",
486 + "_padding"
487 + ],
488 + [
489 + "intrinsic_metadata",
490 + "ingress_global_timestamp"
491 + ],
492 + [
493 + "intrinsic_metadata",
494 + "lf_field_list"
495 + ],
496 + [
497 + "intrinsic_metadata",
498 + "mcast_grp"
499 + ],
500 + [
501 + "intrinsic_metadata",
502 + "egress_rid"
503 + ]
504 + ]
505 +}
...\ No newline at end of file ...\ No newline at end of file
1 +/*
2 + * Copyright 2014-2016 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 +
17 +package org.onosproject.drivers.bmv2;
18 +
19 +import com.google.common.testing.EqualsTester;
20 +import org.junit.Test;
21 +import org.onlab.packet.MacAddress;
22 +import org.onosproject.bmv2.api.model.Bmv2Model;
23 +import org.onosproject.bmv2.api.runtime.Bmv2TableEntry;
24 +import org.onosproject.bmv2.api.runtime.Bmv2TernaryMatchParam;
25 +import org.onosproject.core.ApplicationId;
26 +import org.onosproject.core.DefaultApplicationId;
27 +import org.onosproject.drivers.bmv2.translators.Bmv2DefaultFlowRuleTranslator;
28 +import org.onosproject.drivers.bmv2.translators.Bmv2FlowRuleTranslator;
29 +import org.onosproject.net.DeviceId;
30 +import org.onosproject.net.PortNumber;
31 +import org.onosproject.net.flow.DefaultFlowRule;
32 +import org.onosproject.net.flow.DefaultTrafficSelector;
33 +import org.onosproject.net.flow.DefaultTrafficTreatment;
34 +import org.onosproject.net.flow.FlowRule;
35 +import org.onosproject.net.flow.TrafficSelector;
36 +import org.onosproject.net.flow.TrafficTreatment;
37 +
38 +import java.util.Random;
39 +
40 +import static org.hamcrest.CoreMatchers.equalTo;
41 +import static org.hamcrest.CoreMatchers.is;
42 +import static org.hamcrest.MatcherAssert.assertThat;
43 +
44 +/**
45 + * Tests for {@link Bmv2DefaultFlowRuleTranslator}.
46 + */
47 +public class Bmv2DefaultFlowRuleTranslatorTest {
48 +
49 + private Random random = new Random();
50 + private Bmv2FlowRuleTranslator translator = new Bmv2DefaultFlowRuleTranslator();
51 + private Bmv2Model model = translator.config().model();
52 +
53 +
54 + @Test
55 + public void testCompiler() throws Exception {
56 +
57 + DeviceId deviceId = DeviceId.NONE;
58 + ApplicationId appId = new DefaultApplicationId(1, "test");
59 + int tableId = 0;
60 + MacAddress ethDstMac = MacAddress.valueOf(random.nextLong());
61 + MacAddress ethSrcMac = MacAddress.valueOf(random.nextLong());
62 + short ethType = (short) (0x0000FFFF & random.nextInt());
63 + short outPort = (short) random.nextInt(65);
64 + short inPort = (short) random.nextInt(65);
65 + int timeout = random.nextInt(100);
66 + int priority = random.nextInt(100);
67 +
68 + TrafficSelector matchInPort1 = DefaultTrafficSelector
69 + .builder()
70 + .matchInPort(PortNumber.portNumber(inPort))
71 + .matchEthDst(ethDstMac)
72 + .matchEthSrc(ethSrcMac)
73 + .matchEthType(ethType)
74 + .build();
75 +
76 + TrafficTreatment outPort2 = DefaultTrafficTreatment
77 + .builder()
78 + .setOutput(PortNumber.portNumber(outPort))
79 + .build();
80 +
81 + FlowRule rule1 = DefaultFlowRule.builder()
82 + .forDevice(deviceId)
83 + .forTable(tableId)
84 + .fromApp(appId)
85 + .withSelector(matchInPort1)
86 + .withTreatment(outPort2)
87 + .makeTemporary(timeout)
88 + .withPriority(priority)
89 + .build();
90 +
91 + FlowRule rule2 = DefaultFlowRule.builder()
92 + .forDevice(deviceId)
93 + .forTable(tableId)
94 + .fromApp(appId)
95 + .withSelector(matchInPort1)
96 + .withTreatment(outPort2)
97 + .makeTemporary(timeout)
98 + .withPriority(priority)
99 + .build();
100 +
101 + Bmv2TableEntry entry1 = translator.translate(rule1);
102 + Bmv2TableEntry entry2 = translator.translate(rule1);
103 +
104 + // check equality, i.e. same rules must produce same entries
105 + new EqualsTester()
106 + .addEqualityGroup(rule1, rule2)
107 + .addEqualityGroup(entry1, entry2)
108 + .testEquals();
109 +
110 + int numMatchParams = model.table(0).keys().size();
111 + // parse values stored in entry1
112 + Bmv2TernaryMatchParam inPortParam = (Bmv2TernaryMatchParam) entry1.matchKey().matchParams().get(0);
113 + Bmv2TernaryMatchParam ethDstParam = (Bmv2TernaryMatchParam) entry1.matchKey().matchParams().get(1);
114 + Bmv2TernaryMatchParam ethSrcParam = (Bmv2TernaryMatchParam) entry1.matchKey().matchParams().get(2);
115 + Bmv2TernaryMatchParam ethTypeParam = (Bmv2TernaryMatchParam) entry1.matchKey().matchParams().get(3);
116 + double expectedTimeout = (double) (model.table(0).hasTimeouts() ? rule1.timeout() : -1);
117 +
118 + // check that the number of parameters in the entry is the same as the number of table keys
119 + assertThat("Incorrect number of match parameters",
120 + entry1.matchKey().matchParams().size(), is(equalTo(numMatchParams)));
121 +
122 + // check that values stored in entry are the same used for the flow rule
123 + assertThat("Incorrect inPort match param value",
124 + inPortParam.value().asReadOnlyBuffer().getShort(), is(equalTo(inPort)));
125 + assertThat("Incorrect ethDestMac match param value",
126 + ethDstParam.value().asArray(), is(equalTo(ethDstMac.toBytes())));
127 + assertThat("Incorrect ethSrcMac match param value",
128 + ethSrcParam.value().asArray(), is(equalTo(ethSrcMac.toBytes())));
129 + assertThat("Incorrect ethType match param value",
130 + ethTypeParam.value().asReadOnlyBuffer().getShort(), is(equalTo(ethType)));
131 + assertThat("Incorrect priority value",
132 + entry1.priority(), is(equalTo(rule1.priority())));
133 + assertThat("Incorrect timeout value",
134 + entry1.timeout(), is(equalTo(expectedTimeout)));
135 +
136 + }
137 +}
...\ No newline at end of file ...\ No newline at end of file