Carmelo Cascone
Committed by Thomas Vachuska

Added BMv2 demo apps (onos1.6 cherry-pick)

Change-Id: I19484a826acce724c1fcd5b6e9910d724bda686f
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<!--
3 + ~ Copyright 2016-present Open Networking Laboratory
4 + ~
5 + ~ Licensed under the Apache License, Version 2.0 (the "License");
6 + ~ you may not use this file except in compliance with the License.
7 + ~ You may obtain a copy of the License at
8 + ~
9 + ~ http://www.apache.org/licenses/LICENSE-2.0
10 + ~
11 + ~ Unless required by applicable law or agreed to in writing, software
12 + ~ distributed under the License is distributed on an "AS IS" BASIS,
13 + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 + ~ See the License for the specific language governing permissions and
15 + ~ limitations under the License.
16 + -->
17 +
18 +<project xmlns="http://maven.apache.org/POM/4.0.0"
19 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
20 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
21 + <modelVersion>4.0.0</modelVersion>
22 +
23 + <parent>
24 + <artifactId>onos-app-bmv2-demo</artifactId>
25 + <groupId>org.onosproject</groupId>
26 + <version>1.7.0-SNAPSHOT</version>
27 + <relativePath>../pom.xml</relativePath>
28 + </parent>
29 +
30 + <artifactId>onos-app-bmv2-demo-common</artifactId>
31 +
32 + <packaging>bundle</packaging>
33 +
34 + <dependencies>
35 + <dependency>
36 + <groupId>org.onosproject</groupId>
37 + <artifactId>onos-bmv2-protocol-api</artifactId>
38 + <version>${project.version}</version>
39 + </dependency>
40 + </dependencies>
41 +</project>
...\ No newline at end of file ...\ No newline at end of file
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 + * Bmv2 demo app common classes.
19 + */
20 +package org.onosproject.bmv2.demo.app.common;
...\ No newline at end of file ...\ No newline at end of file
1 +<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2 +
3 +<!--
4 + ~ Copyright 2016-present Open Networking Laboratory
5 + ~
6 + ~ Licensed under the Apache License, Version 2.0 (the "License");
7 + ~ you may not use this file except in compliance with the License.
8 + ~ You may obtain a copy of the License at
9 + ~
10 + ~ http://www.apache.org/licenses/LICENSE-2.0
11 + ~
12 + ~ Unless required by applicable law or agreed to in writing, software
13 + ~ distributed under the License is distributed on an "AS IS" BASIS,
14 + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 + ~ See the License for the specific language governing permissions and
16 + ~ limitations under the License.
17 + -->
18 +
19 +<features xmlns="http://karaf.apache.org/xmlns/features/v1.2.0" name="${project.artifactId}-${project.version}">
20 + <feature name="${project.artifactId}" version="${project.version}"
21 + description="${project.description}">
22 + <bundle>mvn:${project.groupId}/${project.artifactId}/${project.version}</bundle>
23 + <bundle>mvn:${project.groupId}/onos-app-bmv2-demo-common/${project.version}</bundle>
24 + </feature>
25 +</features>
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<!--
3 + ~ Copyright 2016-present Open Networking Laboratory
4 + ~
5 + ~ Licensed under the Apache License, Version 2.0 (the "License");
6 + ~ you may not use this file except in compliance with the License.
7 + ~ You may obtain a copy of the License at
8 + ~
9 + ~ http://www.apache.org/licenses/LICENSE-2.0
10 + ~
11 + ~ Unless required by applicable law or agreed to in writing, software
12 + ~ distributed under the License is distributed on an "AS IS" BASIS,
13 + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 + ~ See the License for the specific language governing permissions and
15 + ~ limitations under the License.
16 + -->
17 +
18 +<project xmlns="http://maven.apache.org/POM/4.0.0"
19 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
20 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
21 + <modelVersion>4.0.0</modelVersion>
22 +
23 + <parent>
24 + <artifactId>onos-app-bmv2-demo</artifactId>
25 + <groupId>org.onosproject</groupId>
26 + <version>1.7.0-SNAPSHOT</version>
27 + <relativePath>../pom.xml</relativePath>
28 + </parent>
29 +
30 + <artifactId>onos-app-bmv2-demo-ecmp</artifactId>
31 +
32 + <packaging>bundle</packaging>
33 +
34 + <properties>
35 + <onos.app.name>org.onosproject.bmv2-ecmp-fabric</onos.app.name>
36 + <onos.app.title>P4/BMv2 Demo Fabric App v1 (ECMP)</onos.app.title>
37 + <onos.app.category>Traffic Steering</onos.app.category>
38 + <onos.app.url>http://onosproject.org</onos.app.url>
39 + <onos.app.readme>P4/BMv2 demo application with ECMP support for a 2-stage clos fabric topology</onos.app.readme>
40 + </properties>
41 +
42 + <dependencies>
43 + <dependency>
44 + <groupId>org.onosproject</groupId>
45 + <artifactId>onos-app-bmv2-demo-common</artifactId>
46 + <version>${project.version}</version>
47 + </dependency>
48 + </dependencies>
49 +
50 +</project>
...\ No newline at end of file ...\ No newline at end of file
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 +}
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.ImmutableBiMap;
20 +import org.onlab.util.ImmutableByteSequence;
21 +import org.onosproject.bmv2.api.context.Bmv2Configuration;
22 +import org.onosproject.bmv2.api.context.Bmv2Interpreter;
23 +import org.onosproject.bmv2.api.context.Bmv2InterpreterException;
24 +import org.onosproject.bmv2.api.runtime.Bmv2Action;
25 +import org.onosproject.bmv2.api.utils.Bmv2TranslatorUtils;
26 +import org.onosproject.net.PortNumber;
27 +import org.onosproject.net.flow.TrafficTreatment;
28 +import org.onosproject.net.flow.criteria.Criterion;
29 +import org.onosproject.net.flow.instructions.Instruction;
30 +
31 +import static org.onosproject.bmv2.api.utils.Bmv2TranslatorUtils.fitByteSequence;
32 +import static org.onosproject.net.PortNumber.CONTROLLER;
33 +import static org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
34 +
35 +/**
36 + * Implementation of a BMv2 interpreter for the ecmp.json configuration.
37 + */
38 +public class EcmpInterpreter implements Bmv2Interpreter {
39 +
40 + protected static final String ECMP_METADATA_T = "ecmp_metadata_t";
41 + protected static final String ECMP_METADATA = "ecmp_metadata";
42 + protected static final String SELECTOR = "selector";
43 + protected static final String GROUP_ID = "groupId";
44 + protected static final String GROUP_SIZE = "groupSize";
45 + protected static final String ECMP_GROUP = "ecmp_group";
46 + protected static final String ECMP_GROUP_TABLE = "ecmp_group_table";
47 + protected static final String TABLE0 = "table0";
48 + protected static final String SEND_TO_CPU = "send_to_cpu";
49 + protected static final String DROP = "_drop";
50 + protected static final String SET_EGRESS_PORT = "set_egress_port";
51 + protected static final String PORT = "port";
52 +
53 + private static final ImmutableBiMap<Criterion.Type, String> CRITERION_TYPE_MAP = ImmutableBiMap.of(
54 + Criterion.Type.IN_PORT, "standard_metadata.ingress_port",
55 + Criterion.Type.ETH_DST, "ethernet.dstAddr",
56 + Criterion.Type.ETH_SRC, "ethernet.srcAddr",
57 + Criterion.Type.ETH_TYPE, "ethernet.etherType");
58 +
59 + private static final ImmutableBiMap<Integer, String> TABLE_ID_MAP = ImmutableBiMap.of(
60 + 0, TABLE0,
61 + 1, ECMP_GROUP_TABLE);
62 +
63 + @Override
64 + public ImmutableBiMap<Integer, String> tableIdMap() {
65 + return TABLE_ID_MAP;
66 + }
67 +
68 + @Override
69 + public ImmutableBiMap<Criterion.Type, String> criterionTypeMap() {
70 + return CRITERION_TYPE_MAP;
71 + }
72 +
73 + @Override
74 + public Bmv2Action mapTreatment(TrafficTreatment treatment, Bmv2Configuration configuration)
75 + throws Bmv2InterpreterException {
76 +
77 + if (treatment.allInstructions().size() == 0) {
78 + // No instructions means drop for us.
79 + return actionWithName(DROP);
80 + } else if (treatment.allInstructions().size() > 1) {
81 + // Otherwise, we understand treatments with only 1 instruction.
82 + throw new Bmv2InterpreterException("Treatment has multiple instructions");
83 + }
84 +
85 + Instruction instruction = treatment.allInstructions().get(0);
86 +
87 + switch (instruction.type()) {
88 + case OUTPUT:
89 + OutputInstruction outInstruction = (OutputInstruction) instruction;
90 + PortNumber port = outInstruction.port();
91 + if (!port.isLogical()) {
92 + return buildEgressAction(port, configuration);
93 + } else if (port.equals(CONTROLLER)) {
94 + return actionWithName(SEND_TO_CPU);
95 + } else {
96 + throw new Bmv2InterpreterException("Egress on logical port not supported: " + port);
97 + }
98 + case NOACTION:
99 + return actionWithName(DROP);
100 + default:
101 + throw new Bmv2InterpreterException("Instruction type not supported: " + instruction.type().name());
102 + }
103 + }
104 +
105 + private static Bmv2Action buildEgressAction(PortNumber port, Bmv2Configuration configuration)
106 + throws Bmv2InterpreterException {
107 +
108 + int portBitWidth = configuration.action(SET_EGRESS_PORT).runtimeData(PORT).bitWidth();
109 +
110 + try {
111 + ImmutableByteSequence portBs = fitByteSequence(ImmutableByteSequence.copyFrom(port.toLong()), portBitWidth);
112 + return Bmv2Action.builder()
113 + .withName(SET_EGRESS_PORT)
114 + .addParameter(portBs)
115 + .build();
116 + } catch (Bmv2TranslatorUtils.ByteSequenceFitException e) {
117 + throw new Bmv2InterpreterException(e.getMessage());
118 + }
119 + }
120 +
121 + private static Bmv2Action actionWithName(String name) {
122 + return Bmv2Action.builder().withName(name).build();
123 + }
124 +}
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 + * BMv2 demo app for the ECMP configuration.
19 + */
20 +package org.onosproject.bmv2.demo.app.ecmp;
...\ No newline at end of file ...\ No newline at end of file
1 +/Users/carmelo/workspace/onos-p4-dev/p4src/build/ecmp.json
...\ No newline at end of file ...\ No newline at end of file
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<!--
3 + ~ Copyright 2014-present Open Networking Laboratory
4 + ~
5 + ~ Licensed under the Apache License, Version 2.0 (the "License");
6 + ~ you may not use this file except in compliance with the License.
7 + ~ You may obtain a copy of the License at
8 + ~
9 + ~ http://www.apache.org/licenses/LICENSE-2.0
10 + ~
11 + ~ Unless required by applicable law or agreed to in writing, software
12 + ~ distributed under the License is distributed on an "AS IS" BASIS,
13 + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 + ~ See the License for the specific language governing permissions and
15 + ~ limitations under the License.
16 + -->
17 +<project xmlns="http://maven.apache.org/POM/4.0.0"
18 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
19 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
20 + <modelVersion>4.0.0</modelVersion>
21 +
22 + <parent>
23 + <groupId>org.onosproject</groupId>
24 + <artifactId>onos-apps</artifactId>
25 + <version>1.7.0-SNAPSHOT</version>
26 + <relativePath>../pom.xml</relativePath>
27 + </parent>
28 +
29 + <artifactId>onos-app-bmv2-demo</artifactId>
30 +
31 + <packaging>pom</packaging>
32 +
33 + <modules>
34 + <module>common</module>
35 + <module>ecmp</module>
36 + <module>wcmp</module>
37 + </modules>
38 +
39 +</project>
1 +<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2 +
3 +<!--
4 + ~ Copyright 2016-present Open Networking Laboratory
5 + ~
6 + ~ Licensed under the Apache License, Version 2.0 (the "License");
7 + ~ you may not use this file except in compliance with the License.
8 + ~ You may obtain a copy of the License at
9 + ~
10 + ~ http://www.apache.org/licenses/LICENSE-2.0
11 + ~
12 + ~ Unless required by applicable law or agreed to in writing, software
13 + ~ distributed under the License is distributed on an "AS IS" BASIS,
14 + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 + ~ See the License for the specific language governing permissions and
16 + ~ limitations under the License.
17 + -->
18 +
19 +<features xmlns="http://karaf.apache.org/xmlns/features/v1.2.0" name="${project.artifactId}-${project.version}">
20 + <feature name="${project.artifactId}" version="${project.version}"
21 + description="${project.description}">
22 + <bundle>mvn:${project.groupId}/${project.artifactId}/${project.version}</bundle>
23 + <bundle>mvn:${project.groupId}/onos-app-bmv2-demo-common/${project.version}</bundle>
24 + </feature>
25 +</features>
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<!--
3 + ~ Copyright 2016-present Open Networking Laboratory
4 + ~
5 + ~ Licensed under the Apache License, Version 2.0 (the "License");
6 + ~ you may not use this file except in compliance with the License.
7 + ~ You may obtain a copy of the License at
8 + ~
9 + ~ http://www.apache.org/licenses/LICENSE-2.0
10 + ~
11 + ~ Unless required by applicable law or agreed to in writing, software
12 + ~ distributed under the License is distributed on an "AS IS" BASIS,
13 + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 + ~ See the License for the specific language governing permissions and
15 + ~ limitations under the License.
16 + -->
17 +
18 +<project xmlns="http://maven.apache.org/POM/4.0.0"
19 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
20 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
21 + <modelVersion>4.0.0</modelVersion>
22 +
23 + <parent>
24 + <artifactId>onos-app-bmv2-demo</artifactId>
25 + <groupId>org.onosproject</groupId>
26 + <version>1.7.0-SNAPSHOT</version>
27 + <relativePath>../pom.xml</relativePath>
28 + </parent>
29 +
30 + <artifactId>onos-app-bmv2-demo-wcmp</artifactId>
31 +
32 + <packaging>bundle</packaging>
33 +
34 + <properties>
35 + <onos.app.name>org.onosproject.bmv2-wcmp-fabric</onos.app.name>
36 + <onos.app.title>P4/BMv2 Demo Fabric App v2 (WCMP)</onos.app.title>
37 + <onos.app.category>Traffic Steering</onos.app.category>
38 + <onos.app.url>http://onosproject.org</onos.app.url>
39 + <onos.app.readme>P4/BMv2 demo application with WCMP support for a 2-stage clos fabric topology</onos.app.readme>
40 + </properties>
41 +
42 + <dependencies>
43 + <dependency>
44 + <groupId>org.onosproject</groupId>
45 + <artifactId>onos-app-bmv2-demo-common</artifactId>
46 + <version>${project.version}</version>
47 + </dependency>
48 + </dependencies>
49 +
50 +</project>
...\ No newline at end of file ...\ No newline at end of file
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 +}
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.ImmutableBiMap;
20 +import org.onlab.util.ImmutableByteSequence;
21 +import org.onosproject.bmv2.api.context.Bmv2Configuration;
22 +import org.onosproject.bmv2.api.context.Bmv2Interpreter;
23 +import org.onosproject.bmv2.api.context.Bmv2InterpreterException;
24 +import org.onosproject.bmv2.api.runtime.Bmv2Action;
25 +import org.onosproject.bmv2.api.utils.Bmv2TranslatorUtils;
26 +import org.onosproject.net.PortNumber;
27 +import org.onosproject.net.flow.TrafficTreatment;
28 +import org.onosproject.net.flow.criteria.Criterion;
29 +import org.onosproject.net.flow.instructions.Instruction;
30 +import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
31 +
32 +import java.util.Map;
33 +
34 +import static org.onosproject.bmv2.api.utils.Bmv2TranslatorUtils.fitByteSequence;
35 +import static org.onosproject.net.PortNumber.CONTROLLER;
36 +
37 +/**
38 + * Implementation of a BMv2 interpreter for the wcmp.json configuration.
39 + */
40 +public final class WcmpInterpreter implements Bmv2Interpreter {
41 +
42 + protected static final String WCMP_META_T = "wcmp_meta_t";
43 + protected static final String WCMP_META = "wcmp_meta";
44 + protected static final String SELECTOR = "selector";
45 + protected static final String GROUP_ID = "groupId";
46 + protected static final String WCMP_GROUP = "wcmp_group";
47 + protected static final String WCMP_SET_SELECTOR = "wcmp_set_selector";
48 + protected static final String WCMP_SET_SELECTOR_TABLE = "wcmp_set_selector_table";
49 + protected static final String WCMP_GROUP_TABLE = "wcmp_group_table";
50 + protected static final String TABLE0 = "table0";
51 + protected static final String SEND_TO_CPU = "send_to_cpu";
52 + protected static final String DROP = "_drop";
53 + protected static final String SET_EGRESS_PORT = "set_egress_port";
54 + protected static final String PORT = "port";
55 +
56 + private static final ImmutableBiMap<Criterion.Type, String> CRITERION_TYPE_MAP = ImmutableBiMap.of(
57 + Criterion.Type.IN_PORT, "standard_metadata.ingress_port",
58 + Criterion.Type.ETH_DST, "ethernet.dstAddr",
59 + Criterion.Type.ETH_SRC, "ethernet.srcAddr",
60 + Criterion.Type.ETH_TYPE, "ethernet.etherType");
61 +
62 + private static final ImmutableBiMap<Integer, String> TABLE_ID_MAP = ImmutableBiMap.of(
63 + 0, TABLE0,
64 + 1, WCMP_GROUP_TABLE);
65 +
66 + private static final Map<String, Bmv2Action> DEFAULT_ACTIONS_MAP = ImmutableBiMap.of(
67 + WCMP_SET_SELECTOR_TABLE, actionWithName(WCMP_SET_SELECTOR));
68 +
69 + @Override
70 + public ImmutableBiMap<Integer, String> tableIdMap() {
71 + return TABLE_ID_MAP;
72 + }
73 +
74 + @Override
75 + public ImmutableBiMap<Criterion.Type, String> criterionTypeMap() {
76 + return CRITERION_TYPE_MAP;
77 + }
78 +
79 + public Map<String, Bmv2Action> defaultActionsMap() {
80 + return DEFAULT_ACTIONS_MAP;
81 + }
82 +
83 + @Override
84 + public Bmv2Action mapTreatment(TrafficTreatment treatment, Bmv2Configuration configuration)
85 + throws Bmv2InterpreterException {
86 +
87 + if (treatment.allInstructions().size() == 0) {
88 + // No instructions means drop for us.
89 + return actionWithName(DROP);
90 + } else if (treatment.allInstructions().size() > 1) {
91 + // Otherwise, we understand treatments with only 1 instruction.
92 + throw new Bmv2InterpreterException("Treatment has multiple instructions");
93 + }
94 +
95 + Instruction instruction = treatment.allInstructions().get(0);
96 +
97 + switch (instruction.type()) {
98 + case OUTPUT:
99 + OutputInstruction outInstruction = (OutputInstruction) instruction;
100 + PortNumber port = outInstruction.port();
101 + if (!port.isLogical()) {
102 + return buildEgressAction(port, configuration);
103 + } else if (port.equals(CONTROLLER)) {
104 + return actionWithName(SEND_TO_CPU);
105 + } else {
106 + throw new Bmv2InterpreterException("Egress on logical port not supported: " + port);
107 + }
108 + case NOACTION:
109 + return actionWithName(DROP);
110 + default:
111 + throw new Bmv2InterpreterException("Instruction type not supported: " + instruction.type().name());
112 + }
113 + }
114 +
115 + private static Bmv2Action buildEgressAction(PortNumber port, Bmv2Configuration configuration)
116 + throws Bmv2InterpreterException {
117 +
118 + int portBitWidth = configuration.action(SET_EGRESS_PORT).runtimeData(PORT).bitWidth();
119 +
120 + try {
121 + ImmutableByteSequence portBs = fitByteSequence(ImmutableByteSequence.copyFrom(port.toLong()), portBitWidth);
122 + return Bmv2Action.builder()
123 + .withName(SET_EGRESS_PORT)
124 + .addParameter(portBs)
125 + .build();
126 + } catch (Bmv2TranslatorUtils.ByteSequenceFitException e) {
127 + throw new Bmv2InterpreterException(e.getMessage());
128 + }
129 + }
130 +
131 + private static Bmv2Action actionWithName(String name) {
132 + return Bmv2Action.builder().withName(name).build();
133 + }
134 +}
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 + * BMv2 demo app for the WCMP configuration.
19 + */
20 +package org.onosproject.bmv2.demo.app.wcmp;
...\ No newline at end of file ...\ No newline at end of file
1 +/Users/carmelo/workspace/onos-p4-dev/p4src/build/wcmp.json
...\ No newline at end of file ...\ No newline at end of file
...@@ -71,6 +71,7 @@ ...@@ -71,6 +71,7 @@
71 <module>graphitemetrics</module> 71 <module>graphitemetrics</module>
72 <module>xosclient</module> 72 <module>xosclient</module>
73 <module>scalablegateway</module> 73 <module>scalablegateway</module>
74 + <module>bmv2-demo</module>
74 </modules> 75 </modules>
75 76
76 77
......