Carmelo Cascone
Committed by Jonathan Hart

Implemented convenient builders of BMv2 extension selectors and

treatments. 

Match and action parameters can now be built from primitive data types
(short, int, long or byte[]) which are then casted automatically
according to a given BMv2 configuration. Also, simplified demo
applications code / structure.

Change-Id: Ia5bebf62301c73c0b20cf6a4ddfb74165889106f
...@@ -19,11 +19,14 @@ package org.onosproject.bmv2.demo.app.ecmp; ...@@ -19,11 +19,14 @@ package org.onosproject.bmv2.demo.app.ecmp;
19 import com.eclipsesource.json.Json; 19 import com.eclipsesource.json.Json;
20 import com.eclipsesource.json.JsonObject; 20 import com.eclipsesource.json.JsonObject;
21 import com.google.common.collect.Lists; 21 import com.google.common.collect.Lists;
22 +import com.google.common.collect.Maps;
22 import org.apache.commons.lang3.tuple.Pair; 23 import org.apache.commons.lang3.tuple.Pair;
23 import org.apache.felix.scr.annotations.Component; 24 import org.apache.felix.scr.annotations.Component;
24 import org.onosproject.bmv2.api.context.Bmv2Configuration; 25 import org.onosproject.bmv2.api.context.Bmv2Configuration;
25 import org.onosproject.bmv2.api.context.Bmv2DefaultConfiguration; 26 import org.onosproject.bmv2.api.context.Bmv2DefaultConfiguration;
26 import org.onosproject.bmv2.api.context.Bmv2DeviceContext; 27 import org.onosproject.bmv2.api.context.Bmv2DeviceContext;
28 +import org.onosproject.bmv2.api.runtime.Bmv2ExtensionSelector;
29 +import org.onosproject.bmv2.api.runtime.Bmv2ExtensionTreatment;
27 import org.onosproject.bmv2.demo.app.common.AbstractUpgradableFabricApp; 30 import org.onosproject.bmv2.demo.app.common.AbstractUpgradableFabricApp;
28 import org.onosproject.net.DeviceId; 31 import org.onosproject.net.DeviceId;
29 import org.onosproject.net.Host; 32 import org.onosproject.net.Host;
...@@ -46,14 +49,13 @@ import java.io.InputStreamReader; ...@@ -46,14 +49,13 @@ import java.io.InputStreamReader;
46 import java.util.Collection; 49 import java.util.Collection;
47 import java.util.Iterator; 50 import java.util.Iterator;
48 import java.util.List; 51 import java.util.List;
52 +import java.util.Map;
49 import java.util.Set; 53 import java.util.Set;
50 import java.util.stream.Collectors; 54 import java.util.stream.Collectors;
51 55
52 import static java.util.stream.Collectors.toSet; 56 import static java.util.stream.Collectors.toSet;
53 import static org.onlab.packet.EthType.EtherType.IPV4; 57 import static org.onlab.packet.EthType.EtherType.IPV4;
54 -import static org.onosproject.bmv2.demo.app.ecmp.EcmpGroupTreatmentBuilder.groupIdOf; 58 +import static org.onosproject.bmv2.demo.app.ecmp.EcmpInterpreter.*;
55 -import static org.onosproject.bmv2.demo.app.ecmp.EcmpInterpreter.ECMP_GROUP_TABLE;
56 -import static org.onosproject.bmv2.demo.app.ecmp.EcmpInterpreter.TABLE0;
57 59
58 /** 60 /**
59 * Implementation of an upgradable fabric app for the ECMP configuration. 61 * Implementation of an upgradable fabric app for the ECMP configuration.
...@@ -69,6 +71,8 @@ public class EcmpFabricApp extends AbstractUpgradableFabricApp { ...@@ -69,6 +71,8 @@ public class EcmpFabricApp extends AbstractUpgradableFabricApp {
69 private static final EcmpInterpreter ECMP_INTERPRETER = new EcmpInterpreter(); 71 private static final EcmpInterpreter ECMP_INTERPRETER = new EcmpInterpreter();
70 protected static final Bmv2DeviceContext ECMP_CONTEXT = new Bmv2DeviceContext(ECMP_CONFIGURATION, ECMP_INTERPRETER); 72 protected static final Bmv2DeviceContext ECMP_CONTEXT = new Bmv2DeviceContext(ECMP_CONFIGURATION, ECMP_INTERPRETER);
71 73
74 + private static final Map<DeviceId, Map<Set<PortNumber>, Short>> DEVICE_GROUP_ID_MAP = Maps.newHashMap();
75 +
72 public EcmpFabricApp() { 76 public EcmpFabricApp() {
73 super(APP_NAME, MODEL_NAME, ECMP_CONTEXT); 77 super(APP_NAME, MODEL_NAME, ECMP_CONTEXT);
74 } 78 }
...@@ -211,10 +215,7 @@ public class EcmpFabricApp extends AbstractUpgradableFabricApp { ...@@ -211,10 +215,7 @@ public class EcmpFabricApp extends AbstractUpgradableFabricApp {
211 Iterator<PortNumber> portIterator = fabricPorts.iterator(); 215 Iterator<PortNumber> portIterator = fabricPorts.iterator();
212 List<FlowRule> rules = Lists.newArrayList(); 216 List<FlowRule> rules = Lists.newArrayList();
213 for (short i = 0; i < groupSize; i++) { 217 for (short i = 0; i < groupSize; i++) {
214 - ExtensionSelector extSelector = new EcmpGroupTableSelectorBuilder() 218 + ExtensionSelector extSelector = buildEcmpSelector(groupId, i);
215 - .withGroupId(groupId)
216 - .withSelector(i)
217 - .build();
218 FlowRule rule = flowRuleBuilder(deviceId, ECMP_GROUP_TABLE) 219 FlowRule rule = flowRuleBuilder(deviceId, ECMP_GROUP_TABLE)
219 .withSelector( 220 .withSelector(
220 DefaultTrafficSelector.builder() 221 DefaultTrafficSelector.builder()
...@@ -228,14 +229,37 @@ public class EcmpFabricApp extends AbstractUpgradableFabricApp { ...@@ -228,14 +229,37 @@ public class EcmpFabricApp extends AbstractUpgradableFabricApp {
228 rules.add(rule); 229 rules.add(rule);
229 } 230 }
230 231
231 - ExtensionTreatment extTreatment = new EcmpGroupTreatmentBuilder() 232 + ExtensionTreatment extTreatment = buildEcmpTreatment(groupId, groupSize);
232 - .withGroupId(groupId)
233 - .withGroupSize(groupSize)
234 - .build();
235 233
236 return Pair.of(extTreatment, rules); 234 return Pair.of(extTreatment, rules);
237 } 235 }
238 236
237 + private Bmv2ExtensionTreatment buildEcmpTreatment(int groupId, int groupSize) {
238 + return Bmv2ExtensionTreatment.builder()
239 + .forConfiguration(ECMP_CONTEXT.configuration())
240 + .setActionName(ECMP_GROUP)
241 + .addParameter(GROUP_ID, groupId)
242 + .addParameter(GROUP_SIZE, groupSize)
243 + .build();
244 + }
245 +
246 + private Bmv2ExtensionSelector buildEcmpSelector(int groupId, int selector) {
247 + return Bmv2ExtensionSelector.builder()
248 + .forConfiguration(ECMP_CONTEXT.configuration())
249 + .matchExact(ECMP_METADATA, GROUP_ID, groupId)
250 + .matchExact(ECMP_METADATA, SELECTOR, selector)
251 + .build();
252 + }
253 +
254 +
255 + public int groupIdOf(DeviceId deviceId, Set<PortNumber> ports) {
256 + DEVICE_GROUP_ID_MAP.putIfAbsent(deviceId, Maps.newHashMap());
257 + // Counts the number of unique portNumber sets for each deviceId.
258 + // Each distinct set of portNumbers will have a unique ID.
259 + return DEVICE_GROUP_ID_MAP.get(deviceId).computeIfAbsent(ports, (pp) ->
260 + (short) (DEVICE_GROUP_ID_MAP.get(deviceId).size() + 1));
261 + }
262 +
239 private static Bmv2Configuration loadConfiguration() { 263 private static Bmv2Configuration loadConfiguration() {
240 try { 264 try {
241 JsonObject json = Json.parse(new BufferedReader(new InputStreamReader( 265 JsonObject json = Json.parse(new BufferedReader(new InputStreamReader(
......
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.bmv2.demo.app.ecmp;
18 -
19 -import com.google.common.collect.ImmutableMap;
20 -import org.onlab.util.ImmutableByteSequence;
21 -import org.onosproject.bmv2.api.context.Bmv2HeaderTypeModel;
22 -import org.onosproject.bmv2.api.runtime.Bmv2ExactMatchParam;
23 -import org.onosproject.bmv2.api.runtime.Bmv2ExtensionSelector;
24 -import org.onosproject.bmv2.api.utils.Bmv2TranslatorUtils;
25 -import org.onosproject.net.flow.criteria.ExtensionSelector;
26 -
27 -import static org.onosproject.bmv2.api.utils.Bmv2TranslatorUtils.fitByteSequence;
28 -import static org.onosproject.bmv2.demo.app.ecmp.EcmpFabricApp.ECMP_CONTEXT;
29 -import static org.onosproject.bmv2.demo.app.ecmp.EcmpInterpreter.*;
30 -
31 -/**
32 - * Builder of ECMP group table extension selector.
33 - */
34 -public class EcmpGroupTableSelectorBuilder {
35 -
36 - private int groupId;
37 - private int selector;
38 -
39 - /**
40 - * Sets the ECMP group ID.
41 - *
42 - * @param groupId an integer value
43 - * @return this
44 - */
45 - public EcmpGroupTableSelectorBuilder withGroupId(int groupId) {
46 - this.groupId = groupId;
47 - return this;
48 - }
49 -
50 - /**
51 - * Sets the ECMP selector.
52 - *
53 - * @param selector an integer value
54 - * @return this
55 - */
56 - public EcmpGroupTableSelectorBuilder withSelector(int selector) {
57 - this.selector = selector;
58 - return this;
59 - }
60 -
61 - /**
62 - * Returns a new extension selector.
63 - *
64 - * @return an extension selector
65 - */
66 - public ExtensionSelector build() {
67 - Bmv2HeaderTypeModel headerTypeModel = ECMP_CONTEXT.configuration().headerType(ECMP_METADATA_T);
68 - int groupIdBitWidth = headerTypeModel.field(GROUP_ID).bitWidth();
69 - int selectorBitWidth = headerTypeModel.field(SELECTOR).bitWidth();
70 -
71 - try {
72 - ImmutableByteSequence groupIdBs = fitByteSequence(ImmutableByteSequence.copyFrom(groupId),
73 - groupIdBitWidth);
74 - ImmutableByteSequence selectorBs = fitByteSequence(ImmutableByteSequence.copyFrom(selector),
75 - selectorBitWidth);
76 -
77 - Bmv2ExactMatchParam groupIdMatch = new Bmv2ExactMatchParam(groupIdBs);
78 - Bmv2ExactMatchParam hashMatch = new Bmv2ExactMatchParam(selectorBs);
79 -
80 - return new Bmv2ExtensionSelector(ImmutableMap.of(
81 - ECMP_METADATA + "." + GROUP_ID, groupIdMatch,
82 - ECMP_METADATA + "." + SELECTOR, hashMatch));
83 -
84 - } catch (Bmv2TranslatorUtils.ByteSequenceFitException e) {
85 - throw new RuntimeException(e);
86 - }
87 - }
88 -}
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.bmv2.demo.app.ecmp;
18 -
19 -import com.google.common.collect.Maps;
20 -import org.onlab.util.ImmutableByteSequence;
21 -import org.onosproject.bmv2.api.context.Bmv2ActionModel;
22 -import org.onosproject.bmv2.api.runtime.Bmv2Action;
23 -import org.onosproject.bmv2.api.runtime.Bmv2ExtensionTreatment;
24 -import org.onosproject.bmv2.api.utils.Bmv2TranslatorUtils;
25 -import org.onosproject.net.DeviceId;
26 -import org.onosproject.net.PortNumber;
27 -import org.onosproject.net.flow.instructions.ExtensionTreatment;
28 -
29 -import java.util.Map;
30 -import java.util.Set;
31 -
32 -import static org.onosproject.bmv2.api.utils.Bmv2TranslatorUtils.fitByteSequence;
33 -import static org.onosproject.bmv2.demo.app.ecmp.EcmpFabricApp.ECMP_CONTEXT;
34 -import static org.onosproject.bmv2.demo.app.ecmp.EcmpInterpreter.*;
35 -
36 -/**
37 - * Builder of ECMP extension treatments.
38 - */
39 -public class EcmpGroupTreatmentBuilder {
40 -
41 - private static final Map<DeviceId, Map<Set<PortNumber>, Short>> DEVICE_GROUP_ID_MAP = Maps.newHashMap();
42 - private int groupId;
43 - private int groupSize;
44 -
45 - /**
46 - * Sets the group ID.
47 - *
48 - * @param groupId an integer value
49 - * @return this
50 - */
51 - public EcmpGroupTreatmentBuilder withGroupId(int groupId) {
52 - this.groupId = groupId;
53 - return this;
54 - }
55 -
56 - /**
57 - * Sets the group size.
58 - *
59 - * @param groupSize an integer value
60 - * @return this
61 - */
62 - public EcmpGroupTreatmentBuilder withGroupSize(int groupSize) {
63 - this.groupSize = groupSize;
64 - return this;
65 - }
66 -
67 - /**
68 - * Returns a new extension treatment.
69 - *
70 - * @return an extension treatment
71 - */
72 - public ExtensionTreatment build() {
73 - Bmv2ActionModel actionModel = ECMP_CONTEXT.configuration().action(ECMP_GROUP);
74 - int groupIdBitWidth = actionModel.runtimeData(GROUP_ID).bitWidth();
75 - int groupSizeBitWidth = actionModel.runtimeData(GROUP_SIZE).bitWidth();
76 -
77 - try {
78 - ImmutableByteSequence groupIdBs = fitByteSequence(ImmutableByteSequence.copyFrom(groupId), groupIdBitWidth);
79 - ImmutableByteSequence groupSizeBs = fitByteSequence(ImmutableByteSequence.copyFrom(groupSize),
80 - groupSizeBitWidth);
81 -
82 - return new Bmv2ExtensionTreatment(Bmv2Action.builder()
83 - .withName(ECMP_GROUP)
84 - .addParameter(groupIdBs)
85 - .addParameter(groupSizeBs)
86 - .build());
87 -
88 - } catch (Bmv2TranslatorUtils.ByteSequenceFitException e) {
89 - throw new RuntimeException(e);
90 - }
91 - }
92 -
93 - /**
94 - * Returns a group ID for the given device and set of ports.
95 - *
96 - * @param deviceId a device ID
97 - * @param ports a set of ports
98 - * @return an integer value
99 - */
100 - public static int groupIdOf(DeviceId deviceId, Set<PortNumber> ports) {
101 - DEVICE_GROUP_ID_MAP.putIfAbsent(deviceId, Maps.newHashMap());
102 - // Counts the number of unique portNumber sets for each deviceId.
103 - // Each distinct set of portNumbers will have a unique ID.
104 - return DEVICE_GROUP_ID_MAP.get(deviceId).computeIfAbsent(ports, (pp) ->
105 - (short) (DEVICE_GROUP_ID_MAP.get(deviceId).size() + 1));
106 - }
107 -}
...@@ -37,7 +37,6 @@ import static org.onosproject.net.flow.instructions.Instructions.OutputInstructi ...@@ -37,7 +37,6 @@ import static org.onosproject.net.flow.instructions.Instructions.OutputInstructi
37 */ 37 */
38 public class EcmpInterpreter implements Bmv2Interpreter { 38 public class EcmpInterpreter implements Bmv2Interpreter {
39 39
40 - protected static final String ECMP_METADATA_T = "ecmp_metadata_t";
41 protected static final String ECMP_METADATA = "ecmp_metadata"; 40 protected static final String ECMP_METADATA = "ecmp_metadata";
42 protected static final String SELECTOR = "selector"; 41 protected static final String SELECTOR = "selector";
43 protected static final String GROUP_ID = "groupId"; 42 protected static final String GROUP_ID = "groupId";
......
...@@ -18,6 +18,7 @@ package org.onosproject.bmv2.demo.app.wcmp; ...@@ -18,6 +18,7 @@ package org.onosproject.bmv2.demo.app.wcmp;
18 18
19 import com.eclipsesource.json.Json; 19 import com.eclipsesource.json.Json;
20 import com.eclipsesource.json.JsonObject; 20 import com.eclipsesource.json.JsonObject;
21 +import com.google.common.collect.ImmutableList;
21 import com.google.common.collect.Lists; 22 import com.google.common.collect.Lists;
22 import com.google.common.collect.Maps; 23 import com.google.common.collect.Maps;
23 import com.google.common.collect.Sets; 24 import com.google.common.collect.Sets;
...@@ -30,6 +31,8 @@ import org.onosproject.bmv2.api.context.Bmv2DefaultConfiguration; ...@@ -30,6 +31,8 @@ import org.onosproject.bmv2.api.context.Bmv2DefaultConfiguration;
30 import org.onosproject.bmv2.api.context.Bmv2DeviceContext; 31 import org.onosproject.bmv2.api.context.Bmv2DeviceContext;
31 import org.onosproject.bmv2.api.runtime.Bmv2Action; 32 import org.onosproject.bmv2.api.runtime.Bmv2Action;
32 import org.onosproject.bmv2.api.runtime.Bmv2DeviceAgent; 33 import org.onosproject.bmv2.api.runtime.Bmv2DeviceAgent;
34 +import org.onosproject.bmv2.api.runtime.Bmv2ExtensionSelector;
35 +import org.onosproject.bmv2.api.runtime.Bmv2ExtensionTreatment;
33 import org.onosproject.bmv2.api.runtime.Bmv2RuntimeException; 36 import org.onosproject.bmv2.api.runtime.Bmv2RuntimeException;
34 import org.onosproject.bmv2.api.service.Bmv2Controller; 37 import org.onosproject.bmv2.api.service.Bmv2Controller;
35 import org.onosproject.bmv2.demo.app.common.AbstractUpgradableFabricApp; 38 import org.onosproject.bmv2.demo.app.common.AbstractUpgradableFabricApp;
...@@ -50,18 +53,19 @@ import org.onosproject.net.topology.TopologyGraph; ...@@ -50,18 +53,19 @@ import org.onosproject.net.topology.TopologyGraph;
50 import java.io.BufferedReader; 53 import java.io.BufferedReader;
51 import java.io.IOException; 54 import java.io.IOException;
52 import java.io.InputStreamReader; 55 import java.io.InputStreamReader;
56 +import java.util.Arrays;
53 import java.util.Collection; 57 import java.util.Collection;
58 +import java.util.Collections;
54 import java.util.List; 59 import java.util.List;
55 import java.util.Map; 60 import java.util.Map;
56 import java.util.Set; 61 import java.util.Set;
57 import java.util.stream.Collectors; 62 import java.util.stream.Collectors;
58 63
64 +import static java.util.stream.Collectors.toList;
59 import static java.util.stream.Collectors.toSet; 65 import static java.util.stream.Collectors.toSet;
60 import static org.onlab.packet.EthType.EtherType.IPV4; 66 import static org.onlab.packet.EthType.EtherType.IPV4;
61 -import static org.onosproject.bmv2.demo.app.wcmp.WcmpGroupTreatmentBuilder.groupIdOf; 67 +import static org.onosproject.bmv2.api.utils.Bmv2TranslatorUtils.roundToBytes;
62 -import static org.onosproject.bmv2.demo.app.wcmp.WcmpGroupTreatmentBuilder.toPrefixLengths; 68 +import static org.onosproject.bmv2.demo.app.wcmp.WcmpInterpreter.*;
63 -import static org.onosproject.bmv2.demo.app.wcmp.WcmpInterpreter.TABLE0;
64 -import static org.onosproject.bmv2.demo.app.wcmp.WcmpInterpreter.WCMP_GROUP_TABLE;
65 69
66 /** 70 /**
67 * Implementation of an upgradable fabric app for the WCMP configuration. 71 * Implementation of an upgradable fabric app for the WCMP configuration.
...@@ -79,6 +83,8 @@ public class WcmpFabricApp extends AbstractUpgradableFabricApp { ...@@ -79,6 +83,8 @@ public class WcmpFabricApp extends AbstractUpgradableFabricApp {
79 private static final WcmpInterpreter WCMP_INTERPRETER = new WcmpInterpreter(); 83 private static final WcmpInterpreter WCMP_INTERPRETER = new WcmpInterpreter();
80 protected static final Bmv2DeviceContext WCMP_CONTEXT = new Bmv2DeviceContext(WCMP_CONFIGURATION, WCMP_INTERPRETER); 84 protected static final Bmv2DeviceContext WCMP_CONTEXT = new Bmv2DeviceContext(WCMP_CONFIGURATION, WCMP_INTERPRETER);
81 85
86 + private static final Map<DeviceId, Map<Map<PortNumber, Double>, Integer>> DEVICE_GROUP_ID_MAP = Maps.newHashMap();
87 +
82 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 88 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
83 private Bmv2Controller bmv2Controller; 89 private Bmv2Controller bmv2Controller;
84 90
...@@ -252,19 +258,11 @@ public class WcmpFabricApp extends AbstractUpgradableFabricApp { ...@@ -252,19 +258,11 @@ public class WcmpFabricApp extends AbstractUpgradableFabricApp {
252 portNumbers.add(p); 258 portNumbers.add(p);
253 weights.add(w); 259 weights.add(w);
254 }); 260 });
255 - List<Integer> prefixLengths; 261 + List<Integer> prefixLengths = toPrefixLengths(weights);
256 - try {
257 - prefixLengths = toPrefixLengths(weights);
258 - } catch (WcmpGroupTreatmentBuilder.WcmpGroupException e) {
259 - throw new FlowRuleGeneratorException(e);
260 - }
261 262
262 List<FlowRule> rules = Lists.newArrayList(); 263 List<FlowRule> rules = Lists.newArrayList();
263 for (int i = 0; i < portNumbers.size(); i++) { 264 for (int i = 0; i < portNumbers.size(); i++) {
264 - ExtensionSelector extSelector = new WcmpGroupTableSelectorBuilder() 265 + ExtensionSelector extSelector = buildWcmpSelector(groupId, prefixLengths.get(i));
265 - .withGroupId(groupId)
266 - .withPrefixLength(prefixLengths.get(i))
267 - .build();
268 FlowRule rule = flowRuleBuilder(deviceId, WCMP_GROUP_TABLE) 266 FlowRule rule = flowRuleBuilder(deviceId, WCMP_GROUP_TABLE)
269 .withSelector(DefaultTrafficSelector.builder() 267 .withSelector(DefaultTrafficSelector.builder()
270 .extension(extSelector, deviceId) 268 .extension(extSelector, deviceId)
...@@ -277,11 +275,78 @@ public class WcmpFabricApp extends AbstractUpgradableFabricApp { ...@@ -277,11 +275,78 @@ public class WcmpFabricApp extends AbstractUpgradableFabricApp {
277 rules.add(rule); 275 rules.add(rule);
278 } 276 }
279 277
280 - ExtensionTreatment extTreatment = new WcmpGroupTreatmentBuilder().withGroupId(groupId).build(); 278 + ExtensionTreatment extTreatment = buildWcmpTreatment(groupId);
281 279
282 return Pair.of(extTreatment, rules); 280 return Pair.of(extTreatment, rules);
283 } 281 }
284 282
283 + private Bmv2ExtensionSelector buildWcmpSelector(int groupId, int prefixLength) {
284 + byte[] ones = new byte[roundToBytes(prefixLength)];
285 + Arrays.fill(ones, (byte) 0xFF);
286 + return Bmv2ExtensionSelector.builder()
287 + .forConfiguration(WCMP_CONTEXT.configuration())
288 + .matchExact(WCMP_META, GROUP_ID, groupId)
289 + .matchLpm(WCMP_META, SELECTOR, ones, prefixLength)
290 + .build();
291 + }
292 +
293 + private Bmv2ExtensionTreatment buildWcmpTreatment(int groupId) {
294 + return Bmv2ExtensionTreatment.builder()
295 + .forConfiguration(WCMP_CONTEXT.configuration())
296 + .setActionName(WCMP_GROUP)
297 + .addParameter(GROUP_ID, groupId)
298 + .build();
299 + }
300 +
301 + public int groupIdOf(DeviceId did, Map<PortNumber, Double> weightedPorts) {
302 + DEVICE_GROUP_ID_MAP.putIfAbsent(did, Maps.newHashMap());
303 + // Counts the number of unique portNumber sets for each device ID.
304 + // Each distinct set of portNumbers will have a unique ID.
305 + return DEVICE_GROUP_ID_MAP.get(did).computeIfAbsent(weightedPorts,
306 + (pp) -> DEVICE_GROUP_ID_MAP.get(did).size() + 1);
307 + }
308 +
309 + public List<Integer> toPrefixLengths(List<Double> weigths) {
310 +
311 + final double weightSum = weigths.stream()
312 + .mapToDouble(Double::doubleValue)
313 + .map(this::roundDouble)
314 + .sum();
315 +
316 + if (Math.abs(weightSum - 1) > 0.0001) {
317 + throw new RuntimeException("WCMP weights sum is expected to be 1, found was " + weightSum);
318 + }
319 +
320 + final int selectorBitWidth = WCMP_CONTEXT.configuration().headerType(WCMP_META_T).field(SELECTOR).bitWidth();
321 + final int availableBits = selectorBitWidth - 1;
322 +
323 + List<Long> prefixDiffs = weigths.stream().map(w -> Math.round(w * availableBits)).collect(toList());
324 +
325 + final long bitSum = prefixDiffs.stream().mapToLong(Long::longValue).sum();
326 + final long error = availableBits - bitSum;
327 +
328 + if (error != 0) {
329 + // Lazy intuition here is that the error can be absorbed by the longest prefixDiff with the minor impact.
330 + Long maxDiff = Collections.max(prefixDiffs);
331 + int idx = prefixDiffs.indexOf(maxDiff);
332 + prefixDiffs.remove(idx);
333 + prefixDiffs.add(idx, maxDiff + error);
334 + }
335 + List<Integer> prefixLengths = Lists.newArrayList();
336 +
337 + int prefix = 1;
338 + for (Long p : prefixDiffs) {
339 + prefixLengths.add(prefix);
340 + prefix += p;
341 + }
342 + return ImmutableList.copyOf(prefixLengths);
343 + }
344 +
345 + private double roundDouble(double n) {
346 + // 5 digits precision.
347 + return (double) Math.round(n * 100000d) / 100000d;
348 + }
349 +
285 private static Bmv2Configuration loadConfiguration() { 350 private static Bmv2Configuration loadConfiguration() {
286 try { 351 try {
287 JsonObject json = Json.parse(new BufferedReader(new InputStreamReader( 352 JsonObject json = Json.parse(new BufferedReader(new InputStreamReader(
......
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.bmv2.demo.app.wcmp;
18 -
19 -import com.google.common.collect.ImmutableMap;
20 -import org.onlab.util.ImmutableByteSequence;
21 -import org.onosproject.bmv2.api.runtime.Bmv2ExactMatchParam;
22 -import org.onosproject.bmv2.api.runtime.Bmv2ExtensionSelector;
23 -import org.onosproject.bmv2.api.runtime.Bmv2LpmMatchParam;
24 -import org.onosproject.bmv2.api.utils.Bmv2TranslatorUtils;
25 -import org.onosproject.net.flow.criteria.ExtensionSelector;
26 -
27 -import static com.google.common.base.Preconditions.checkArgument;
28 -import static org.onosproject.bmv2.api.utils.Bmv2TranslatorUtils.fitByteSequence;
29 -import static org.onosproject.bmv2.api.utils.Bmv2TranslatorUtils.roundToBytes;
30 -import static org.onosproject.bmv2.demo.app.wcmp.WcmpFabricApp.WCMP_CONTEXT;
31 -import static org.onosproject.bmv2.demo.app.wcmp.WcmpInterpreter.*;
32 -
33 -/**
34 - * Builder of WCMP group table extension selector.
35 - */
36 -public final class WcmpGroupTableSelectorBuilder {
37 -
38 - private int groupId;
39 - private int prefixLength;
40 -
41 - /**
42 - * Sets the WCMP group ID.
43 - *
44 - * @param groupId an integer value
45 - * @return this
46 - */
47 - public WcmpGroupTableSelectorBuilder withGroupId(int groupId) {
48 - this.groupId = groupId;
49 - return this;
50 - }
51 -
52 - /**
53 - * Sets the WCMP selector's prefix length.
54 - *
55 - * @param prefixLength an integer value
56 - * @return this
57 - */
58 - public WcmpGroupTableSelectorBuilder withPrefixLength(int prefixLength) {
59 - this.prefixLength = prefixLength;
60 - return this;
61 - }
62 -
63 - /**
64 - * Returns a new extension selector.
65 - *
66 - * @return an extension selector
67 - */
68 - public ExtensionSelector build() {
69 -
70 - final int selectorBitWidth = WCMP_CONTEXT.configuration().headerType(WCMP_META_T).field(SELECTOR).bitWidth();
71 - final int groupIdBitWidth = WCMP_CONTEXT.configuration().headerType(WCMP_META_T).field(GROUP_ID).bitWidth();
72 - final ImmutableByteSequence ones = ImmutableByteSequence.ofOnes(roundToBytes(selectorBitWidth));
73 -
74 - checkArgument(prefixLength >= 1 && prefixLength <= selectorBitWidth,
75 - "prefix length must be between 1 and " + selectorBitWidth);
76 - try {
77 - ImmutableByteSequence groupIdBs = fitByteSequence(ImmutableByteSequence.copyFrom(groupId), groupIdBitWidth);
78 - Bmv2ExactMatchParam groupIdMatch = new Bmv2ExactMatchParam(groupIdBs);
79 - Bmv2LpmMatchParam selectorMatch = new Bmv2LpmMatchParam(ones, prefixLength);
80 -
81 - return new Bmv2ExtensionSelector(ImmutableMap.of(
82 - WCMP_META + "." + GROUP_ID, groupIdMatch,
83 - WCMP_META + "." + SELECTOR, selectorMatch));
84 -
85 - } catch (Bmv2TranslatorUtils.ByteSequenceFitException e) {
86 - throw new RuntimeException(e);
87 - }
88 - }
89 -}
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.bmv2.demo.app.wcmp;
18 -
19 -import com.google.common.collect.ImmutableList;
20 -import com.google.common.collect.Lists;
21 -import com.google.common.collect.Maps;
22 -import org.onlab.util.ImmutableByteSequence;
23 -import org.onosproject.bmv2.api.runtime.Bmv2Action;
24 -import org.onosproject.bmv2.api.runtime.Bmv2ExtensionTreatment;
25 -import org.onosproject.bmv2.api.utils.Bmv2TranslatorUtils;
26 -import org.onosproject.net.DeviceId;
27 -import org.onosproject.net.PortNumber;
28 -import org.onosproject.net.flow.instructions.ExtensionTreatment;
29 -
30 -import java.util.Collections;
31 -import java.util.List;
32 -import java.util.Map;
33 -
34 -import static com.google.common.base.Preconditions.checkArgument;
35 -import static java.util.stream.Collectors.toList;
36 -import static org.onosproject.bmv2.api.utils.Bmv2TranslatorUtils.fitByteSequence;
37 -import static org.onosproject.bmv2.demo.app.wcmp.WcmpFabricApp.WCMP_CONTEXT;
38 -import static org.onosproject.bmv2.demo.app.wcmp.WcmpInterpreter.*;
39 -
40 -/**
41 - * Builder of WCMP extension treatment.
42 - */
43 -public final class WcmpGroupTreatmentBuilder {
44 -
45 - private static final double MAX_ERROR = 0.0001;
46 -
47 - private static final Map<DeviceId, Map<Map<PortNumber, Double>, Integer>> DEVICE_GROUP_ID_MAP = Maps.newHashMap();
48 -
49 - private int groupId;
50 -
51 - /**
52 - * Sets the WCMP group ID.
53 - *
54 - * @param groupId an integer value
55 - * @return this
56 - */
57 - public WcmpGroupTreatmentBuilder withGroupId(int groupId) {
58 - this.groupId = groupId;
59 - return this;
60 - }
61 -
62 - /**
63 - * Returns a new extension treatment.
64 - *
65 - * @return an extension treatment
66 - */
67 - public ExtensionTreatment build() {
68 - checkArgument(groupId >= 0, "group id must be a non-zero positive integer");
69 - ImmutableByteSequence groupIdBs = ImmutableByteSequence.copyFrom(groupId);
70 - final int groupIdBitWidth = WCMP_CONTEXT.configuration().headerType(WCMP_META_T).field(GROUP_ID).bitWidth();
71 - try {
72 - groupIdBs = fitByteSequence(groupIdBs, groupIdBitWidth);
73 - return new Bmv2ExtensionTreatment(
74 - Bmv2Action.builder()
75 - .withName(WCMP_GROUP)
76 - .addParameter(groupIdBs)
77 - .build());
78 - } catch (Bmv2TranslatorUtils.ByteSequenceFitException e) {
79 - throw new RuntimeException(e);
80 - }
81 - }
82 -
83 - public static int groupIdOf(DeviceId did, Map<PortNumber, Double> weightedPorts) {
84 - DEVICE_GROUP_ID_MAP.putIfAbsent(did, Maps.newHashMap());
85 - // Counts the number of unique portNumber sets for each device ID.
86 - // Each distinct set of portNumbers will have a unique ID.
87 - return DEVICE_GROUP_ID_MAP.get(did).computeIfAbsent(weightedPorts,
88 - (pp) -> DEVICE_GROUP_ID_MAP.get(did).size() + 1);
89 - }
90 -
91 - public static List<Integer> toPrefixLengths(List<Double> weigths) throws WcmpGroupException {
92 -
93 - double weightSum = weigths.stream()
94 - .mapToDouble(Double::doubleValue)
95 - .map(WcmpGroupTreatmentBuilder::roundDouble)
96 - .sum();
97 -
98 - if (Math.abs(weightSum - 1) > MAX_ERROR) {
99 - throw new WcmpGroupException("weights sum is expected to be 1, found was " + weightSum);
100 - }
101 -
102 - final int selectorBitWidth = WCMP_CONTEXT.configuration().headerType(WCMP_META_T).field(SELECTOR).bitWidth();
103 - final int availableBits = selectorBitWidth - 1;
104 -
105 - List<Long> prefixDiffs = weigths.stream().map(w -> Math.round(w * availableBits)).collect(toList());
106 -
107 - final long bitSum = prefixDiffs.stream().mapToLong(Long::longValue).sum();
108 - final long error = availableBits - bitSum;
109 -
110 - if (error != 0) {
111 - // Lazy intuition here is that the error can be absorbed by the longest prefixDiff with the minor impact.
112 - Long maxDiff = Collections.max(prefixDiffs);
113 - int idx = prefixDiffs.indexOf(maxDiff);
114 - prefixDiffs.remove(idx);
115 - prefixDiffs.add(idx, maxDiff + error);
116 - }
117 - List<Integer> prefixLengths = Lists.newArrayList();
118 -
119 - int prefix = 1;
120 - for (Long p : prefixDiffs) {
121 - prefixLengths.add(prefix);
122 - prefix += p;
123 - }
124 - return ImmutableList.copyOf(prefixLengths);
125 - }
126 -
127 - private static double roundDouble(double n) {
128 - // 5 digits precision.
129 - return (double) Math.round(n * 100000d) / 100000d;
130 - }
131 -
132 - public static class WcmpGroupException extends Exception {
133 - public WcmpGroupException(String s) {
134 - }
135 - }
136 -}
...@@ -22,8 +22,6 @@ import org.onosproject.net.driver.AbstractHandlerBehaviour; ...@@ -22,8 +22,6 @@ import org.onosproject.net.driver.AbstractHandlerBehaviour;
22 import org.onosproject.net.flow.criteria.ExtensionSelector; 22 import org.onosproject.net.flow.criteria.ExtensionSelector;
23 import org.onosproject.net.flow.criteria.ExtensionSelectorType; 23 import org.onosproject.net.flow.criteria.ExtensionSelectorType;
24 24
25 -import java.util.Collections;
26 -
27 import static org.onosproject.net.flow.criteria.ExtensionSelectorType.ExtensionSelectorTypes.BMV2_MATCH_PARAMS; 25 import static org.onosproject.net.flow.criteria.ExtensionSelectorType.ExtensionSelectorTypes.BMV2_MATCH_PARAMS;
28 26
29 /** 27 /**
...@@ -34,7 +32,7 @@ public class Bmv2ExtensionSelectorResolver extends AbstractHandlerBehaviour impl ...@@ -34,7 +32,7 @@ public class Bmv2ExtensionSelectorResolver extends AbstractHandlerBehaviour impl
34 @Override 32 @Override
35 public ExtensionSelector getExtensionSelector(ExtensionSelectorType type) { 33 public ExtensionSelector getExtensionSelector(ExtensionSelectorType type) {
36 if (type.equals(BMV2_MATCH_PARAMS.type())) { 34 if (type.equals(BMV2_MATCH_PARAMS.type())) {
37 - return new Bmv2ExtensionSelector(Collections.emptyMap()); 35 + return Bmv2ExtensionSelector.empty();
38 } 36 }
39 37
40 return null; 38 return null;
......
...@@ -32,7 +32,7 @@ public class Bmv2ExtensionTreatmentResolver extends AbstractHandlerBehaviour imp ...@@ -32,7 +32,7 @@ public class Bmv2ExtensionTreatmentResolver extends AbstractHandlerBehaviour imp
32 @Override 32 @Override
33 public ExtensionTreatment getExtensionInstruction(ExtensionTreatmentType type) { 33 public ExtensionTreatment getExtensionInstruction(ExtensionTreatmentType type) {
34 if (type.equals(BMV2_ACTION.type())) { 34 if (type.equals(BMV2_ACTION.type())) {
35 - return new Bmv2ExtensionTreatment(null); 35 + return Bmv2ExtensionTreatment.empty();
36 } 36 }
37 return null; 37 return null;
38 } 38 }
......
...@@ -37,7 +37,7 @@ public final class Bmv2Action { ...@@ -37,7 +37,7 @@ public final class Bmv2Action {
37 private final String name; 37 private final String name;
38 private final List<ImmutableByteSequence> parameters; 38 private final List<ImmutableByteSequence> parameters;
39 39
40 - private Bmv2Action(String name, List<ImmutableByteSequence> parameters) { 40 + protected Bmv2Action(String name, List<ImmutableByteSequence> parameters) {
41 // hide constructor 41 // hide constructor
42 this.name = name; 42 this.name = name;
43 this.parameters = parameters; 43 this.parameters = parameters;
......
...@@ -19,11 +19,26 @@ package org.onosproject.bmv2.api.runtime; ...@@ -19,11 +19,26 @@ package org.onosproject.bmv2.api.runtime;
19 import com.google.common.annotations.Beta; 19 import com.google.common.annotations.Beta;
20 import com.google.common.base.MoreObjects; 20 import com.google.common.base.MoreObjects;
21 import com.google.common.base.Objects; 21 import com.google.common.base.Objects;
22 +import com.google.common.collect.Maps;
23 +import org.onlab.util.ImmutableByteSequence;
22 import org.onlab.util.KryoNamespace; 24 import org.onlab.util.KryoNamespace;
25 +import org.onosproject.bmv2.api.context.Bmv2ActionModel;
26 +import org.onosproject.bmv2.api.context.Bmv2Configuration;
27 +import org.onosproject.bmv2.api.context.Bmv2RuntimeDataModel;
28 +import org.onosproject.bmv2.api.utils.Bmv2TranslatorUtils;
23 import org.onosproject.net.flow.AbstractExtension; 29 import org.onosproject.net.flow.AbstractExtension;
24 import org.onosproject.net.flow.instructions.ExtensionTreatment; 30 import org.onosproject.net.flow.instructions.ExtensionTreatment;
25 import org.onosproject.net.flow.instructions.ExtensionTreatmentType; 31 import org.onosproject.net.flow.instructions.ExtensionTreatmentType;
26 32
33 +import java.nio.ByteBuffer;
34 +import java.util.ArrayList;
35 +import java.util.List;
36 +import java.util.Map;
37 +
38 +import static com.google.common.base.Preconditions.checkArgument;
39 +import static com.google.common.base.Preconditions.checkNotNull;
40 +import static org.onlab.util.ImmutableByteSequence.copyFrom;
41 +import static org.onosproject.bmv2.api.utils.Bmv2TranslatorUtils.fitByteSequence;
27 import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.BMV2_ACTION; 42 import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.BMV2_ACTION;
28 43
29 /** 44 /**
...@@ -40,7 +55,7 @@ public final class Bmv2ExtensionTreatment extends AbstractExtension implements E ...@@ -40,7 +55,7 @@ public final class Bmv2ExtensionTreatment extends AbstractExtension implements E
40 * 55 *
41 * @param action an action 56 * @param action an action
42 */ 57 */
43 - public Bmv2ExtensionTreatment(Bmv2Action action) { 58 + private Bmv2ExtensionTreatment(Bmv2Action action) {
44 this.action = action; 59 this.action = action;
45 } 60 }
46 61
...@@ -91,4 +106,167 @@ public final class Bmv2ExtensionTreatment extends AbstractExtension implements E ...@@ -91,4 +106,167 @@ public final class Bmv2ExtensionTreatment extends AbstractExtension implements E
91 .add("action", action) 106 .add("action", action)
92 .toString(); 107 .toString();
93 } 108 }
109 +
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 + }
94 } 272 }
......
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.bmv2.api.runtime;
18 +
19 +import com.eclipsesource.json.Json;
20 +import com.eclipsesource.json.JsonObject;
21 +import org.junit.Before;
22 +import org.junit.Test;
23 +import org.onlab.packet.MacAddress;
24 +import org.onosproject.bmv2.api.context.Bmv2Configuration;
25 +import org.onosproject.bmv2.api.context.Bmv2DefaultConfiguration;
26 +
27 +import java.io.BufferedReader;
28 +import java.io.InputStreamReader;
29 +
30 +import static org.hamcrest.MatcherAssert.assertThat;
31 +import static org.hamcrest.Matchers.is;
32 +
33 +public class Bmv2ExtensionBuilderTest {
34 +
35 + private Bmv2Configuration config;
36 +
37 + @Before
38 + public void setUp() throws Exception {
39 + JsonObject json = Json.parse(new BufferedReader(new InputStreamReader(
40 + this.getClass().getResourceAsStream("/simple.json")))).asObject();
41 + config = Bmv2DefaultConfiguration.parse(json);
42 + }
43 +
44 + @Test
45 + public void testExtensionSelector() throws Exception {
46 +
47 + Bmv2ExtensionSelector extSelectorExact = Bmv2ExtensionSelector.builder()
48 + .forConfiguration(config)
49 + .matchExact("standard_metadata", "ingress_port", (short) 255)
50 + .matchExact("ethernet", "etherType", 512)
51 + .matchExact("ethernet", "dstAddr", 1024L)
52 + .matchExact("ethernet", "srcAddr", MacAddress.BROADCAST.toBytes())
53 + .build();
54 +
55 + Bmv2ExtensionSelector extSelectorTernary = Bmv2ExtensionSelector.builder()
56 + .forConfiguration(config)
57 + .matchTernary("standard_metadata", "ingress_port", (short) 255, (short) 255)
58 + .matchTernary("ethernet", "etherType", 512, 512)
59 + .matchTernary("ethernet", "dstAddr", 1024L, 1024L)
60 + .matchTernary("ethernet", "srcAddr", MacAddress.BROADCAST.toBytes(), MacAddress.NONE.toBytes())
61 + .build();
62 +
63 + Bmv2ExtensionSelector extSelectorLpm = Bmv2ExtensionSelector.builder()
64 + .forConfiguration(config)
65 + .matchLpm("standard_metadata", "ingress_port", (short) 255, 1)
66 + .matchLpm("ethernet", "etherType", 512, 2)
67 + .matchLpm("ethernet", "dstAddr", 1024L, 3)
68 + .matchLpm("ethernet", "srcAddr", MacAddress.BROADCAST.toBytes(), 4)
69 + .build();
70 +
71 + Bmv2ExtensionSelector extSelectorValid = Bmv2ExtensionSelector.builder()
72 + .forConfiguration(config)
73 + .matchValid("standard_metadata", "ingress_port", true)
74 + .matchValid("ethernet", "etherType", true)
75 + .matchValid("ethernet", "dstAddr", false)
76 + .matchValid("ethernet", "srcAddr", false)
77 + .build();
78 +
79 + assertThat(extSelectorExact.parameterMap().size(), is(4));
80 + assertThat(extSelectorTernary.parameterMap().size(), is(4));
81 + assertThat(extSelectorLpm.parameterMap().size(), is(4));
82 + assertThat(extSelectorValid.parameterMap().size(), is(4));
83 +
84 + // TODO add more tests, e.g. check for byte sequences content and size.
85 + }
86 +
87 + @Test
88 + public void testExtensionTreatment() throws Exception {
89 +
90 + Bmv2ExtensionTreatment treatment = Bmv2ExtensionTreatment.builder()
91 + .forConfiguration(config)
92 + .setActionName("set_egress_port")
93 + .addParameter("port", 1)
94 + .build();
95 +
96 + assertThat(treatment.action().parameters().size(), is(1));
97 +
98 + // TODO add more tests, e.g. check for byte sequences content and size.
99 + }
100 +}
...\ No newline at end of file ...\ No newline at end of file