Carmelo Cascone
Committed by Gerrit Code Review

Added BMv2 demo apps

Change-Id: Id93f6b4f407ddd224fde8e31d79c9426633b4d75
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2016-present Open Networking Laboratory
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>onos-app-bmv2-demo</artifactId>
<groupId>org.onosproject</groupId>
<version>1.6.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>onos-app-bmv2-demo-common</artifactId>
<packaging>bundle</packaging>
<dependencies>
<dependency>
<groupId>org.onosproject</groupId>
<artifactId>onos-bmv2-protocol-api</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>
\ No newline at end of file
/*
* Copyright 2016-present Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Bmv2 demo app common classes.
*/
package org.onosproject.bmv2.demo.app.common;
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!--
~ Copyright 2016-present Open Networking Laboratory
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<features xmlns="http://karaf.apache.org/xmlns/features/v1.2.0" name="${project.artifactId}-${project.version}">
<feature name="${project.artifactId}" version="${project.version}"
description="${project.description}">
<bundle>mvn:${project.groupId}/${project.artifactId}/${project.version}</bundle>
<bundle>mvn:${project.groupId}/onos-app-bmv2-demo-common/${project.version}</bundle>
</feature>
</features>
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2016-present Open Networking Laboratory
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>onos-app-bmv2-demo</artifactId>
<groupId>org.onosproject</groupId>
<version>1.6.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>onos-app-bmv2-demo-ecmp</artifactId>
<packaging>bundle</packaging>
<properties>
<onos.app.name>org.onosproject.bmv2-ecmp-fabric</onos.app.name>
<onos.app.title>P4/BMv2 Demo Fabric App v1 (ECMP)</onos.app.title>
<onos.app.category>Traffic Steering</onos.app.category>
<onos.app.url>http://onosproject.org</onos.app.url>
<onos.app.readme>P4/BMv2 demo application with ECMP support for a 2-stage clos fabric topology</onos.app.readme>
</properties>
<dependencies>
<dependency>
<groupId>org.onosproject</groupId>
<artifactId>onos-app-bmv2-demo-common</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>
\ No newline at end of file
/*
* Copyright 2016-present Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.bmv2.demo.app.ecmp;
import com.google.common.collect.ImmutableMap;
import org.onlab.util.ImmutableByteSequence;
import org.onosproject.bmv2.api.context.Bmv2HeaderTypeModel;
import org.onosproject.bmv2.api.runtime.Bmv2ExactMatchParam;
import org.onosproject.bmv2.api.runtime.Bmv2ExtensionSelector;
import org.onosproject.bmv2.api.utils.Bmv2TranslatorUtils;
import org.onosproject.net.flow.criteria.ExtensionSelector;
import static org.onosproject.bmv2.api.utils.Bmv2TranslatorUtils.fitByteSequence;
import static org.onosproject.bmv2.demo.app.ecmp.EcmpFabricApp.ECMP_CONTEXT;
import static org.onosproject.bmv2.demo.app.ecmp.EcmpInterpreter.*;
/**
* Builder of ECMP group table extension selector.
*/
public class EcmpGroupTableSelectorBuilder {
private int groupId;
private int selector;
/**
* Sets the ECMP group ID.
*
* @param groupId an integer value
* @return this
*/
public EcmpGroupTableSelectorBuilder withGroupId(int groupId) {
this.groupId = groupId;
return this;
}
/**
* Sets the ECMP selector.
*
* @param selector an integer value
* @return this
*/
public EcmpGroupTableSelectorBuilder withSelector(int selector) {
this.selector = selector;
return this;
}
/**
* Returns a new extension selector.
*
* @return an extension selector
*/
public ExtensionSelector build() {
Bmv2HeaderTypeModel headerTypeModel = ECMP_CONTEXT.configuration().headerType(ECMP_METADATA_T);
int groupIdBitWidth = headerTypeModel.field(GROUP_ID).bitWidth();
int selectorBitWidth = headerTypeModel.field(SELECTOR).bitWidth();
try {
ImmutableByteSequence groupIdBs = fitByteSequence(ImmutableByteSequence.copyFrom(groupId),
groupIdBitWidth);
ImmutableByteSequence selectorBs = fitByteSequence(ImmutableByteSequence.copyFrom(selector),
selectorBitWidth);
Bmv2ExactMatchParam groupIdMatch = new Bmv2ExactMatchParam(groupIdBs);
Bmv2ExactMatchParam hashMatch = new Bmv2ExactMatchParam(selectorBs);
return new Bmv2ExtensionSelector(ImmutableMap.of(
ECMP_METADATA + "." + GROUP_ID, groupIdMatch,
ECMP_METADATA + "." + SELECTOR, hashMatch));
} catch (Bmv2TranslatorUtils.ByteSequenceFitException e) {
throw new RuntimeException(e);
}
}
}
/*
* Copyright 2016-present Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.bmv2.demo.app.ecmp;
import com.google.common.collect.Maps;
import org.onlab.util.ImmutableByteSequence;
import org.onosproject.bmv2.api.context.Bmv2ActionModel;
import org.onosproject.bmv2.api.runtime.Bmv2Action;
import org.onosproject.bmv2.api.runtime.Bmv2ExtensionTreatment;
import org.onosproject.bmv2.api.utils.Bmv2TranslatorUtils;
import org.onosproject.net.DeviceId;
import org.onosproject.net.PortNumber;
import org.onosproject.net.flow.instructions.ExtensionTreatment;
import java.util.Map;
import java.util.Set;
import static org.onosproject.bmv2.api.utils.Bmv2TranslatorUtils.fitByteSequence;
import static org.onosproject.bmv2.demo.app.ecmp.EcmpFabricApp.ECMP_CONTEXT;
import static org.onosproject.bmv2.demo.app.ecmp.EcmpInterpreter.*;
/**
* Builder of ECMP extension treatments.
*/
public class EcmpGroupTreatmentBuilder {
private static final Map<DeviceId, Map<Set<PortNumber>, Short>> DEVICE_GROUP_ID_MAP = Maps.newHashMap();
private int groupId;
private int groupSize;
/**
* Sets the group ID.
*
* @param groupId an integer value
* @return this
*/
public EcmpGroupTreatmentBuilder withGroupId(int groupId) {
this.groupId = groupId;
return this;
}
/**
* Sets the group size.
*
* @param groupSize an integer value
* @return this
*/
public EcmpGroupTreatmentBuilder withGroupSize(int groupSize) {
this.groupSize = groupSize;
return this;
}
/**
* Returns a new extension treatment.
*
* @return an extension treatment
*/
public ExtensionTreatment build() {
Bmv2ActionModel actionModel = ECMP_CONTEXT.configuration().action(ECMP_GROUP);
int groupIdBitWidth = actionModel.runtimeData(GROUP_ID).bitWidth();
int groupSizeBitWidth = actionModel.runtimeData(GROUP_SIZE).bitWidth();
try {
ImmutableByteSequence groupIdBs = fitByteSequence(ImmutableByteSequence.copyFrom(groupId), groupIdBitWidth);
ImmutableByteSequence groupSizeBs = fitByteSequence(ImmutableByteSequence.copyFrom(groupSize),
groupSizeBitWidth);
return new Bmv2ExtensionTreatment(Bmv2Action.builder()
.withName(ECMP_GROUP)
.addParameter(groupIdBs)
.addParameter(groupSizeBs)
.build());
} catch (Bmv2TranslatorUtils.ByteSequenceFitException e) {
throw new RuntimeException(e);
}
}
/**
* Returns a group ID for the given device and set of ports.
*
* @param deviceId a device ID
* @param ports a set of ports
* @return an integer value
*/
public static int groupIdOf(DeviceId deviceId, Set<PortNumber> ports) {
DEVICE_GROUP_ID_MAP.putIfAbsent(deviceId, Maps.newHashMap());
// Counts the number of unique portNumber sets for each deviceId.
// Each distinct set of portNumbers will have a unique ID.
return DEVICE_GROUP_ID_MAP.get(deviceId).computeIfAbsent(ports, (pp) ->
(short) (DEVICE_GROUP_ID_MAP.get(deviceId).size() + 1));
}
}
/*
* Copyright 2016-present Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.bmv2.demo.app.ecmp;
import com.google.common.collect.ImmutableBiMap;
import org.onlab.util.ImmutableByteSequence;
import org.onosproject.bmv2.api.context.Bmv2Configuration;
import org.onosproject.bmv2.api.context.Bmv2Interpreter;
import org.onosproject.bmv2.api.context.Bmv2InterpreterException;
import org.onosproject.bmv2.api.runtime.Bmv2Action;
import org.onosproject.bmv2.api.utils.Bmv2TranslatorUtils;
import org.onosproject.net.PortNumber;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.flow.criteria.Criterion;
import org.onosproject.net.flow.instructions.Instruction;
import static org.onosproject.bmv2.api.utils.Bmv2TranslatorUtils.fitByteSequence;
import static org.onosproject.net.PortNumber.CONTROLLER;
import static org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
/**
* Implementation of a BMv2 interpreter for the ecmp.json configuration.
*/
public class EcmpInterpreter implements Bmv2Interpreter {
protected static final String ECMP_METADATA_T = "ecmp_metadata_t";
protected static final String ECMP_METADATA = "ecmp_metadata";
protected static final String SELECTOR = "selector";
protected static final String GROUP_ID = "groupId";
protected static final String GROUP_SIZE = "groupSize";
protected static final String ECMP_GROUP = "ecmp_group";
protected static final String ECMP_GROUP_TABLE = "ecmp_group_table";
protected static final String TABLE0 = "table0";
protected static final String SEND_TO_CPU = "send_to_cpu";
protected static final String DROP = "_drop";
protected static final String SET_EGRESS_PORT = "set_egress_port";
protected static final String PORT = "port";
private static final ImmutableBiMap<Criterion.Type, String> CRITERION_TYPE_MAP = ImmutableBiMap.of(
Criterion.Type.IN_PORT, "standard_metadata.ingress_port",
Criterion.Type.ETH_DST, "ethernet.dstAddr",
Criterion.Type.ETH_SRC, "ethernet.srcAddr",
Criterion.Type.ETH_TYPE, "ethernet.etherType");
private static final ImmutableBiMap<Integer, String> TABLE_ID_MAP = ImmutableBiMap.of(
0, TABLE0,
1, ECMP_GROUP_TABLE);
@Override
public ImmutableBiMap<Integer, String> tableIdMap() {
return TABLE_ID_MAP;
}
@Override
public ImmutableBiMap<Criterion.Type, String> criterionTypeMap() {
return CRITERION_TYPE_MAP;
}
@Override
public Bmv2Action mapTreatment(TrafficTreatment treatment, Bmv2Configuration configuration)
throws Bmv2InterpreterException {
if (treatment.allInstructions().size() == 0) {
// No instructions means drop for us.
return actionWithName(DROP);
} else if (treatment.allInstructions().size() > 1) {
// Otherwise, we understand treatments with only 1 instruction.
throw new Bmv2InterpreterException("Treatment has multiple instructions");
}
Instruction instruction = treatment.allInstructions().get(0);
switch (instruction.type()) {
case OUTPUT:
OutputInstruction outInstruction = (OutputInstruction) instruction;
PortNumber port = outInstruction.port();
if (!port.isLogical()) {
return buildEgressAction(port, configuration);
} else if (port.equals(CONTROLLER)) {
return actionWithName(SEND_TO_CPU);
} else {
throw new Bmv2InterpreterException("Egress on logical port not supported: " + port);
}
case NOACTION:
return actionWithName(DROP);
default:
throw new Bmv2InterpreterException("Instruction type not supported: " + instruction.type().name());
}
}
private static Bmv2Action buildEgressAction(PortNumber port, Bmv2Configuration configuration)
throws Bmv2InterpreterException {
int portBitWidth = configuration.action(SET_EGRESS_PORT).runtimeData(PORT).bitWidth();
try {
ImmutableByteSequence portBs = fitByteSequence(ImmutableByteSequence.copyFrom(port.toLong()), portBitWidth);
return Bmv2Action.builder()
.withName(SET_EGRESS_PORT)
.addParameter(portBs)
.build();
} catch (Bmv2TranslatorUtils.ByteSequenceFitException e) {
throw new Bmv2InterpreterException(e.getMessage());
}
}
private static Bmv2Action actionWithName(String name) {
return Bmv2Action.builder().withName(name).build();
}
}
/*
* Copyright 2016-present Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* BMv2 demo app for the ECMP configuration.
*/
package org.onosproject.bmv2.demo.app.ecmp;
\ No newline at end of file
/Users/carmelo/workspace/onos-p4-dev/p4src/build/ecmp.json
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2014-present Open Networking Laboratory
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.onosproject</groupId>
<artifactId>onos-apps</artifactId>
<version>1.6.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>onos-app-bmv2-demo</artifactId>
<packaging>pom</packaging>
<modules>
<module>common</module>
<module>ecmp</module>
<module>wcmp</module>
</modules>
</project>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!--
~ Copyright 2016-present Open Networking Laboratory
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<features xmlns="http://karaf.apache.org/xmlns/features/v1.2.0" name="${project.artifactId}-${project.version}">
<feature name="${project.artifactId}" version="${project.version}"
description="${project.description}">
<bundle>mvn:${project.groupId}/${project.artifactId}/${project.version}</bundle>
<bundle>mvn:${project.groupId}/onos-app-bmv2-demo-common/${project.version}</bundle>
</feature>
</features>
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2016-present Open Networking Laboratory
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>onos-app-bmv2-demo</artifactId>
<groupId>org.onosproject</groupId>
<version>1.6.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>onos-app-bmv2-demo-wcmp</artifactId>
<packaging>bundle</packaging>
<properties>
<onos.app.name>org.onosproject.bmv2-wcmp-fabric</onos.app.name>
<onos.app.title>P4/BMv2 Demo Fabric App v2 (WCMP)</onos.app.title>
<onos.app.category>Traffic Steering</onos.app.category>
<onos.app.url>http://onosproject.org</onos.app.url>
<onos.app.readme>P4/BMv2 demo application with WCMP support for a 2-stage clos fabric topology</onos.app.readme>
</properties>
<dependencies>
<dependency>
<groupId>org.onosproject</groupId>
<artifactId>onos-app-bmv2-demo-common</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>
\ No newline at end of file
/*
* Copyright 2016-present Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.bmv2.demo.app.wcmp;
import com.google.common.collect.ImmutableMap;
import org.onlab.util.ImmutableByteSequence;
import org.onosproject.bmv2.api.runtime.Bmv2ExactMatchParam;
import org.onosproject.bmv2.api.runtime.Bmv2ExtensionSelector;
import org.onosproject.bmv2.api.runtime.Bmv2LpmMatchParam;
import org.onosproject.bmv2.api.utils.Bmv2TranslatorUtils;
import org.onosproject.net.flow.criteria.ExtensionSelector;
import static com.google.common.base.Preconditions.checkArgument;
import static org.onosproject.bmv2.api.utils.Bmv2TranslatorUtils.fitByteSequence;
import static org.onosproject.bmv2.api.utils.Bmv2TranslatorUtils.roundToBytes;
import static org.onosproject.bmv2.demo.app.wcmp.WcmpFabricApp.WCMP_CONTEXT;
import static org.onosproject.bmv2.demo.app.wcmp.WcmpInterpreter.*;
/**
* Builder of WCMP group table extension selector.
*/
public final class WcmpGroupTableSelectorBuilder {
private int groupId;
private int prefixLength;
/**
* Sets the WCMP group ID.
*
* @param groupId an integer value
* @return this
*/
public WcmpGroupTableSelectorBuilder withGroupId(int groupId) {
this.groupId = groupId;
return this;
}
/**
* Sets the WCMP selector's prefix length.
*
* @param prefixLength an integer value
* @return this
*/
public WcmpGroupTableSelectorBuilder withPrefixLength(int prefixLength) {
this.prefixLength = prefixLength;
return this;
}
/**
* Returns a new extension selector.
*
* @return an extension selector
*/
public ExtensionSelector build() {
final int selectorBitWidth = WCMP_CONTEXT.configuration().headerType(WCMP_META_T).field(SELECTOR).bitWidth();
final int groupIdBitWidth = WCMP_CONTEXT.configuration().headerType(WCMP_META_T).field(GROUP_ID).bitWidth();
final ImmutableByteSequence ones = ImmutableByteSequence.ofOnes(roundToBytes(selectorBitWidth));
checkArgument(prefixLength >= 1 && prefixLength <= selectorBitWidth,
"prefix length must be between 1 and " + selectorBitWidth);
try {
ImmutableByteSequence groupIdBs = fitByteSequence(ImmutableByteSequence.copyFrom(groupId), groupIdBitWidth);
Bmv2ExactMatchParam groupIdMatch = new Bmv2ExactMatchParam(groupIdBs);
Bmv2LpmMatchParam selectorMatch = new Bmv2LpmMatchParam(ones, prefixLength);
return new Bmv2ExtensionSelector(ImmutableMap.of(
WCMP_META + "." + GROUP_ID, groupIdMatch,
WCMP_META + "." + SELECTOR, selectorMatch));
} catch (Bmv2TranslatorUtils.ByteSequenceFitException e) {
throw new RuntimeException(e);
}
}
}
/*
* Copyright 2016-present Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.bmv2.demo.app.wcmp;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.onlab.util.ImmutableByteSequence;
import org.onosproject.bmv2.api.runtime.Bmv2Action;
import org.onosproject.bmv2.api.runtime.Bmv2ExtensionTreatment;
import org.onosproject.bmv2.api.utils.Bmv2TranslatorUtils;
import org.onosproject.net.DeviceId;
import org.onosproject.net.PortNumber;
import org.onosproject.net.flow.instructions.ExtensionTreatment;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import static com.google.common.base.Preconditions.checkArgument;
import static java.util.stream.Collectors.toList;
import static org.onosproject.bmv2.api.utils.Bmv2TranslatorUtils.fitByteSequence;
import static org.onosproject.bmv2.demo.app.wcmp.WcmpFabricApp.WCMP_CONTEXT;
import static org.onosproject.bmv2.demo.app.wcmp.WcmpInterpreter.*;
/**
* Builder of WCMP extension treatment.
*/
public final class WcmpGroupTreatmentBuilder {
private static final double MAX_ERROR = 0.0001;
private static final Map<DeviceId, Map<Map<PortNumber, Double>, Integer>> DEVICE_GROUP_ID_MAP = Maps.newHashMap();
private int groupId;
/**
* Sets the WCMP group ID.
*
* @param groupId an integer value
* @return this
*/
public WcmpGroupTreatmentBuilder withGroupId(int groupId) {
this.groupId = groupId;
return this;
}
/**
* Returns a new extension treatment.
*
* @return an extension treatment
*/
public ExtensionTreatment build() {
checkArgument(groupId >= 0, "group id must be a non-zero positive integer");
ImmutableByteSequence groupIdBs = ImmutableByteSequence.copyFrom(groupId);
final int groupIdBitWidth = WCMP_CONTEXT.configuration().headerType(WCMP_META_T).field(GROUP_ID).bitWidth();
try {
groupIdBs = fitByteSequence(groupIdBs, groupIdBitWidth);
return new Bmv2ExtensionTreatment(
Bmv2Action.builder()
.withName(WCMP_GROUP)
.addParameter(groupIdBs)
.build());
} catch (Bmv2TranslatorUtils.ByteSequenceFitException e) {
throw new RuntimeException(e);
}
}
public static int groupIdOf(DeviceId did, Map<PortNumber, Double> weightedPorts) {
DEVICE_GROUP_ID_MAP.putIfAbsent(did, Maps.newHashMap());
// Counts the number of unique portNumber sets for each device ID.
// Each distinct set of portNumbers will have a unique ID.
return DEVICE_GROUP_ID_MAP.get(did).computeIfAbsent(weightedPorts,
(pp) -> DEVICE_GROUP_ID_MAP.get(did).size() + 1);
}
public static List<Integer> toPrefixLengths(List<Double> weigths) throws WcmpGroupException {
double weightSum = weigths.stream()
.mapToDouble(Double::doubleValue)
.map(WcmpGroupTreatmentBuilder::roundDouble)
.sum();
if (Math.abs(weightSum - 1) > MAX_ERROR) {
throw new WcmpGroupException("weights sum is expected to be 1, found was " + weightSum);
}
final int selectorBitWidth = WCMP_CONTEXT.configuration().headerType(WCMP_META_T).field(SELECTOR).bitWidth();
final int availableBits = selectorBitWidth - 1;
List<Long> prefixDiffs = weigths.stream().map(w -> Math.round(w * availableBits)).collect(toList());
final long bitSum = prefixDiffs.stream().mapToLong(Long::longValue).sum();
final long error = availableBits - bitSum;
if (error != 0) {
// Lazy intuition here is that the error can be absorbed by the longest prefixDiff with the minor impact.
Long maxDiff = Collections.max(prefixDiffs);
int idx = prefixDiffs.indexOf(maxDiff);
prefixDiffs.remove(idx);
prefixDiffs.add(idx, maxDiff + error);
}
List<Integer> prefixLengths = Lists.newArrayList();
int prefix = 1;
for (Long p : prefixDiffs) {
prefixLengths.add(prefix);
prefix += p;
}
return ImmutableList.copyOf(prefixLengths);
}
private static double roundDouble(double n) {
// 5 digits precision.
return (double) Math.round(n * 100000d) / 100000d;
}
public static class WcmpGroupException extends Exception {
public WcmpGroupException(String s) {
}
}
}
/*
* Copyright 2016-present Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.bmv2.demo.app.wcmp;
import com.google.common.collect.ImmutableBiMap;
import org.onlab.util.ImmutableByteSequence;
import org.onosproject.bmv2.api.context.Bmv2Configuration;
import org.onosproject.bmv2.api.context.Bmv2Interpreter;
import org.onosproject.bmv2.api.context.Bmv2InterpreterException;
import org.onosproject.bmv2.api.runtime.Bmv2Action;
import org.onosproject.bmv2.api.utils.Bmv2TranslatorUtils;
import org.onosproject.net.PortNumber;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.flow.criteria.Criterion;
import org.onosproject.net.flow.instructions.Instruction;
import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
import java.util.Map;
import static org.onosproject.bmv2.api.utils.Bmv2TranslatorUtils.fitByteSequence;
import static org.onosproject.net.PortNumber.CONTROLLER;
/**
* Implementation of a BMv2 interpreter for the wcmp.json configuration.
*/
public final class WcmpInterpreter implements Bmv2Interpreter {
protected static final String WCMP_META_T = "wcmp_meta_t";
protected static final String WCMP_META = "wcmp_meta";
protected static final String SELECTOR = "selector";
protected static final String GROUP_ID = "groupId";
protected static final String WCMP_GROUP = "wcmp_group";
protected static final String WCMP_SET_SELECTOR = "wcmp_set_selector";
protected static final String WCMP_SET_SELECTOR_TABLE = "wcmp_set_selector_table";
protected static final String WCMP_GROUP_TABLE = "wcmp_group_table";
protected static final String TABLE0 = "table0";
protected static final String SEND_TO_CPU = "send_to_cpu";
protected static final String DROP = "_drop";
protected static final String SET_EGRESS_PORT = "set_egress_port";
protected static final String PORT = "port";
private static final ImmutableBiMap<Criterion.Type, String> CRITERION_TYPE_MAP = ImmutableBiMap.of(
Criterion.Type.IN_PORT, "standard_metadata.ingress_port",
Criterion.Type.ETH_DST, "ethernet.dstAddr",
Criterion.Type.ETH_SRC, "ethernet.srcAddr",
Criterion.Type.ETH_TYPE, "ethernet.etherType");
private static final ImmutableBiMap<Integer, String> TABLE_ID_MAP = ImmutableBiMap.of(
0, TABLE0,
1, WCMP_GROUP_TABLE);
private static final Map<String, Bmv2Action> DEFAULT_ACTIONS_MAP = ImmutableBiMap.of(
WCMP_SET_SELECTOR_TABLE, actionWithName(WCMP_SET_SELECTOR));
@Override
public ImmutableBiMap<Integer, String> tableIdMap() {
return TABLE_ID_MAP;
}
@Override
public ImmutableBiMap<Criterion.Type, String> criterionTypeMap() {
return CRITERION_TYPE_MAP;
}
public Map<String, Bmv2Action> defaultActionsMap() {
return DEFAULT_ACTIONS_MAP;
}
@Override
public Bmv2Action mapTreatment(TrafficTreatment treatment, Bmv2Configuration configuration)
throws Bmv2InterpreterException {
if (treatment.allInstructions().size() == 0) {
// No instructions means drop for us.
return actionWithName(DROP);
} else if (treatment.allInstructions().size() > 1) {
// Otherwise, we understand treatments with only 1 instruction.
throw new Bmv2InterpreterException("Treatment has multiple instructions");
}
Instruction instruction = treatment.allInstructions().get(0);
switch (instruction.type()) {
case OUTPUT:
OutputInstruction outInstruction = (OutputInstruction) instruction;
PortNumber port = outInstruction.port();
if (!port.isLogical()) {
return buildEgressAction(port, configuration);
} else if (port.equals(CONTROLLER)) {
return actionWithName(SEND_TO_CPU);
} else {
throw new Bmv2InterpreterException("Egress on logical port not supported: " + port);
}
case NOACTION:
return actionWithName(DROP);
default:
throw new Bmv2InterpreterException("Instruction type not supported: " + instruction.type().name());
}
}
private static Bmv2Action buildEgressAction(PortNumber port, Bmv2Configuration configuration)
throws Bmv2InterpreterException {
int portBitWidth = configuration.action(SET_EGRESS_PORT).runtimeData(PORT).bitWidth();
try {
ImmutableByteSequence portBs = fitByteSequence(ImmutableByteSequence.copyFrom(port.toLong()), portBitWidth);
return Bmv2Action.builder()
.withName(SET_EGRESS_PORT)
.addParameter(portBs)
.build();
} catch (Bmv2TranslatorUtils.ByteSequenceFitException e) {
throw new Bmv2InterpreterException(e.getMessage());
}
}
private static Bmv2Action actionWithName(String name) {
return Bmv2Action.builder().withName(name).build();
}
}
/*
* Copyright 2016-present Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* BMv2 demo app for the WCMP configuration.
*/
package org.onosproject.bmv2.demo.app.wcmp;
\ No newline at end of file
/Users/carmelo/workspace/onos-p4-dev/p4src/build/wcmp.json
\ No newline at end of file
......@@ -70,6 +70,7 @@
<module>graphitemetrics</module>
<module>xosclient</module>
<module>scalablegateway</module>
<module>bmv2-demo</module>
</modules>
......