Skip to content

Commit

Permalink
All containers with corr. code included and complete
Browse files Browse the repository at this point in the history
  • Loading branch information
theUltraMarine19 committed Mar 4, 2019
1 parent 5942496 commit 68500d3
Show file tree
Hide file tree
Showing 6 changed files with 766 additions and 28 deletions.
319 changes: 319 additions & 0 deletions gateway/PipelineInterpreterImpl.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,319 @@
/*
* Copyright 2017-present Open Networking Foundation
*
* 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.p4tutorial.pipeconf;

import com.google.common.collect.BiMap;
import com.google.common.collect.ImmutableBiMap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import org.onlab.packet.DeserializationException;
import org.onlab.packet.Ethernet;
import org.onlab.util.ImmutableByteSequence;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Port;
import org.onosproject.net.PortNumber;
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.driver.AbstractHandlerBehaviour;
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 org.onosproject.net.packet.DefaultInboundPacket;
import org.onosproject.net.packet.InboundPacket;
import org.onosproject.net.packet.OutboundPacket;
import org.onosproject.net.pi.model.PiActionId;
import org.onosproject.net.pi.model.PiActionParamId;
import org.onosproject.net.pi.model.PiControlMetadataId;
import org.onosproject.net.pi.model.PiMatchFieldId;
import org.onosproject.net.pi.model.PiPipelineInterpreter;
import org.onosproject.net.pi.model.PiTableId;
import org.onosproject.net.pi.runtime.PiAction;
import org.onosproject.net.pi.runtime.PiActionParam;
import org.onosproject.net.pi.runtime.PiControlMetadata;
import org.onosproject.net.pi.runtime.PiPacketOperation;

import java.nio.ByteBuffer;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.Arrays;

import static java.lang.String.format;
import static org.onlab.util.ImmutableByteSequence.copyFrom;
import static org.onosproject.net.PortNumber.CONTROLLER;
import static org.onosproject.net.PortNumber.FLOOD;
import static org.onosproject.net.flow.instructions.Instruction.Type.OUTPUT;
import static org.onosproject.net.pi.model.PiPacketOperationType.PACKET_OUT;
import static org.slf4j.LoggerFactory.getLogger;
import org.slf4j.Logger;

/**
* Implementation of a pipeline interpreter for the mytunnel.p4 program.
*/
public final class PipelineInterpreterImpl
extends AbstractHandlerBehaviour
implements PiPipelineInterpreter {

private static final Logger log = getLogger(PipelineInterpreterImpl.class);

private static final String DOT = ".";
private static final String HDR = "hdr";
private static final String C_INGRESS = "c_ingress";

private static final String C_EGRESS = "c_egress";
private static final String T_KV_STORE = "kv_store";
private static final String GF = "gateway_forward";


private static final String EGRESS_PORT = "egress_port";
private static final String INGRESS_PORT = "ingress_port";
private static final String ETHERNET = "ethernet";
private static final String IPV4 = "ipv4";
private static final String UDP = "udp";
private static final String DATA = "data";

private static final String STANDARD_METADATA = "standard_metadata";
private static final int PORT_FIELD_BITWIDTH = 9;

private static final PiMatchFieldId INGRESS_PORT_ID =
PiMatchFieldId.of(STANDARD_METADATA + DOT + "ingress_port");
private static final PiMatchFieldId ETH_DST_ID =
PiMatchFieldId.of(HDR + DOT + ETHERNET + DOT + "dstAddr");
private static final PiMatchFieldId ETH_SRC_ID =
PiMatchFieldId.of(HDR + DOT + ETHERNET + DOT + "srcAddr");
private static final PiMatchFieldId IPV4_SRC_ID =
PiMatchFieldId.of(HDR + DOT + IPV4 + DOT + "srcAddr");
private static final PiMatchFieldId IPV4_DST_ID =
PiMatchFieldId.of(HDR + DOT + IPV4 + DOT + "dstAddr");
private static final PiMatchFieldId UDP_DST_PORT_ID =
PiMatchFieldId.of(HDR + DOT + UDP + DOT + "dstPort");
private static final PiMatchFieldId ETH_TYPE_ID =
PiMatchFieldId.of(HDR + DOT + ETHERNET + DOT + "etherType");
private static final PiMatchFieldId KEY1 =
PiMatchFieldId.of(HDR + DOT + DATA + DOT + "key1");
private static final PiMatchFieldId TYPE_SYNC =
PiMatchFieldId.of(HDR + DOT + DATA + DOT + "type_sync");


private static final PiTableId TABLE_KV_STORE_ID =
PiTableId.of(C_INGRESS + DOT + T_KV_STORE);
private static final PiTableId GF_ID =
PiTableId.of(C_INGRESS + DOT + GF);

private static final PiActionId ACT_ID_NOP =
PiActionId.of("NoAction");
private static final PiActionId ACT_ID_SEND_TO_CPU =
PiActionId.of(C_INGRESS + DOT + "send_to_cpu");
private static final PiActionId ACT_ID_MYFORWARD =
PiActionId.of(C_INGRESS + DOT + "myforward");
private static final PiActionId ACT_ID_REPLY_TO_READ =
PiActionId.of(C_INGRESS + DOT + "reply_to_read");

private static final PiActionParamId ACT_PARAM_ID_VALUE =
PiActionParamId.of("value");

private static final PiActionParamId ACT_PARAM_ID_VALUE1 =
PiActionParamId.of("port");
private static final PiActionParamId ACT_PARAM_ID_VALUE2 =
PiActionParamId.of("dst_mac");

//
// private static final PiActionParamId ACT_PARAM_ID_PORT =
// PiActionParamId.of("port");

private static final BiMap<Integer, PiTableId> TABLE_MAP =
new ImmutableBiMap.Builder<Integer, PiTableId>()
.put(0, TABLE_KV_STORE_ID)
.build();

private static final BiMap<Integer, PiTableId> TABLE_MAP1 =
new ImmutableBiMap.Builder<Integer, PiTableId>()
.put(1, GF_ID)
.build();

private static final BiMap<Criterion.Type, PiMatchFieldId> CRITERION_MAP =
new ImmutableBiMap.Builder<Criterion.Type, PiMatchFieldId>()
// .put(Criterion.Type.IPV4_DST,IPV4_DST_ID)
.put(Criterion.Type.IN_PORT, INGRESS_PORT_ID)
.put(Criterion.Type.ETH_DST, ETH_DST_ID)
.put(Criterion.Type.ETH_SRC, ETH_SRC_ID)
.put(Criterion.Type.ETH_TYPE, ETH_TYPE_ID)
.build();

@Override
public Optional<PiMatchFieldId> mapCriterionType(Criterion.Type type) {
return Optional.ofNullable(CRITERION_MAP.get(type));
}

@Override
public Optional<Criterion.Type> mapPiMatchFieldId(PiMatchFieldId headerFieldId) {
return Optional.ofNullable(CRITERION_MAP.inverse().get(headerFieldId));
}

@Override
public Optional<PiTableId> mapFlowRuleTableId(int flowRuleTableId) {
return Optional.ofNullable(TABLE_MAP.get(flowRuleTableId));
}

@Override
public Optional<Integer> mapPiTableId(PiTableId piTableId) {
return Optional.ofNullable(TABLE_MAP.inverse().get(piTableId));
}

@Override
public PiAction mapTreatment(TrafficTreatment treatment, PiTableId piTableId)
throws PiInterpreterException {

if (piTableId != TABLE_KV_STORE_ID || piTableId != GF_ID) {
throw new PiInterpreterException(
"Can map treatments only for defined tables");
}

if (treatment.allInstructions().size() == 0) {
// 0 instructions means "NoAction"
return PiAction.builder().withId(ACT_ID_NOP).build();
} else if (treatment.allInstructions().size() > 1) {
// We understand treatments with only 1 instruction.
throw new PiInterpreterException("Treatment has multiple instructions");
}

// Get the first and only instruction.
Instruction instruction = treatment.allInstructions().get(0);
// log.warn("interpretor instruction = {}",instruction);

if (instruction.type() != OUTPUT) {
// We can map only instructions of type OUTPUT.
throw new PiInterpreterException(format(
"Instruction of type '%s' not supported", instruction.type()));
}

OutputInstruction outInstruction = (OutputInstruction) instruction;
PortNumber port = outInstruction.port();
// log.warn("interpretor port = {}",port.toLong());
List<PiActionParam> list = Arrays.asList(new PiActionParam(
ACT_PARAM_ID_VALUE1, copyFrom(port.toLong())), new PiActionParam(
ACT_PARAM_ID_VALUE2, copyFrom(port.toLong())));
if (!port.isLogical()) {
// log.warn("interpretor inside !port.isLogical()");
return PiAction.builder()
.withId(ACT_ID_MYFORWARD)
.withParameters(list)
.build();
} else if (port.equals(CONTROLLER)) {
// log.warn("interpretor inside port.equals(CONTROLLER)");

return PiAction.builder()
.withId(ACT_ID_NOP)
.build();
} else {
throw new PiInterpreterException(format(
"Output on logical port '%s' not supported", port));
}
}

@Override
public Collection<PiPacketOperation> mapOutboundPacket(OutboundPacket packet)
throws PiInterpreterException {

TrafficTreatment treatment = packet.treatment();

// We support only packet-out with OUTPUT instructions.
if (treatment.allInstructions().size() != 1 &&
treatment.allInstructions().get(0).type() != OUTPUT) {
throw new PiInterpreterException(
"Treatment not supported: " + treatment.toString());
}

Instruction instruction = treatment.allInstructions().get(0);
PortNumber port = ((OutputInstruction) instruction).port();
List<PiPacketOperation> piPacketOps = Lists.newArrayList();

if (!port.isLogical()) {
piPacketOps.add(createPiPacketOp(packet.data(), port.toLong()));
} else if (port.equals(FLOOD)) {
// Since mytunnel.p4 does not support flooding, we create a packet
// operation for each switch port.
DeviceService deviceService = handler().get(DeviceService.class);
DeviceId deviceId = packet.sendThrough();
for (Port p : deviceService.getPorts(deviceId)) {
piPacketOps.add(createPiPacketOp(packet.data(), p.number().toLong()));
}
} else {
throw new PiInterpreterException(format(
"Output on logical port '%s' not supported", port));
}

return piPacketOps;
}

@Override
public InboundPacket mapInboundPacket(PiPacketOperation packetIn)
throws PiInterpreterException {
// We assume that the packet is ethernet, which is fine since mytunnel.p4
// can deparse only ethernet packets.
Ethernet ethPkt;

try {
ethPkt = Ethernet.deserializer().deserialize(
packetIn.data().asArray(), 0, packetIn.data().size());
} catch (DeserializationException dex) {
throw new PiInterpreterException(dex.getMessage());
}

// Returns the ingress port packet metadata.
Optional<PiControlMetadata> packetMetadata = packetIn.metadatas().stream()
.filter(metadata -> metadata.id().toString().equals(INGRESS_PORT))
.findFirst();

if (packetMetadata.isPresent()) {
short s = packetMetadata.get().value().asReadOnlyBuffer().getShort();
ConnectPoint receivedFrom = new ConnectPoint(
packetIn.deviceId(), PortNumber.portNumber(s));
return new DefaultInboundPacket(
receivedFrom, ethPkt, packetIn.data().asReadOnlyBuffer());
} else {
throw new PiInterpreterException(format(
"Missing metadata '%s' in packet-in received from '%s': %s",
INGRESS_PORT, packetIn.deviceId(), packetIn));
}
}

private PiPacketOperation createPiPacketOp(ByteBuffer data, long portNumber)
throws PiInterpreterException {
PiControlMetadata metadata = createControlMetadata(portNumber);
return PiPacketOperation.builder()
.forDevice(this.data().deviceId())
.withType(PACKET_OUT)
.withData(copyFrom(data))
.withMetadatas(ImmutableList.of(metadata))
.build();
}

private PiControlMetadata createControlMetadata(long portNumber)
throws PiInterpreterException {
try {
return PiControlMetadata.builder()
.withId(PiControlMetadataId.of(EGRESS_PORT))
.withValue(copyFrom(portNumber).fit(PORT_FIELD_BITWIDTH))
.build();
} catch (ImmutableByteSequence.ByteSequenceTrimException e) {
throw new PiInterpreterException(format(
"Port number %d too big, %s", portNumber, e.getMessage()));
}
}
}
9 changes: 9 additions & 0 deletions gateway/command.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
table_add c_ingress.gateway_forward 0 => 2 0x00163ea84e01
table_add c_ingress.gateway_forward 2 => 2 0x00163ea84e01
table_add c_ingress.gateway_forward 1 => 1 0x00163e7867d6
table_add c_ingress.gateway_forward 3 => 1 0x00163e7867d6

table_add c_ingress.gateway_forward 0 => 3 0x00163e0c3710
table_add c_ingress.gateway_forward 2 => 3 0x00163e0c3710
table_add c_ingress.gateway_forward 1 => 1 0x00163e7867d6
table_add c_ingress.gateway_forward 3 => 1 0x00163e7867d6
Loading

0 comments on commit 68500d3

Please sign in to comment.