blob: e04d8757cd2b56aedddfbca55f66441ff5e24801 [file] [log] [blame]
/*
* 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.drivers.bmv2;
import org.onlab.osgi.ServiceNotFoundException;
import org.onlab.util.ImmutableByteSequence;
import org.onosproject.bmv2.api.runtime.Bmv2DeviceAgent;
import org.onosproject.bmv2.api.runtime.Bmv2RuntimeException;
import org.onosproject.bmv2.api.service.Bmv2Controller;
import org.onosproject.net.DeviceId;
import org.onosproject.net.driver.AbstractHandlerBehaviour;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.packet.OutboundPacket;
import org.onosproject.net.packet.PacketProgrammable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import static java.lang.Math.toIntExact;
import static java.util.stream.Collectors.toList;
import static org.onosproject.net.flow.instructions.Instruction.Type.OUTPUT;
import static org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
/**
* Implementation of the packet programmable behaviour for BMv2.
*/
public class Bmv2PacketProgrammable extends AbstractHandlerBehaviour implements PacketProgrammable {
private final Logger log = LoggerFactory.getLogger(this.getClass());
@Override
public void emit(OutboundPacket packet) {
TrafficTreatment treatment = packet.treatment();
// BMv2 supports only OUTPUT instructions.
List<OutputInstruction> outInstructions = treatment.allInstructions()
.stream()
.filter(i -> i.type().equals(OUTPUT))
.map(i -> (OutputInstruction) i)
.collect(toList());
if (treatment.allInstructions().size() != outInstructions.size()) {
// There are other instructions that are not of type OUTPUT
log.warn("Dropping emit request, treatment nor supported: {}", treatment);
return;
}
outInstructions.forEach(outInst -> {
if (outInst.port().isLogical()) {
log.warn("Dropping emit request, logical port not supported: {}", outInst.port());
} else {
try {
int portNumber = toIntExact(outInst.port().toLong());
send(portNumber, packet);
} catch (ArithmeticException e) {
log.error("Dropping emit request, port number too big: {}", outInst.port().toLong());
}
}
});
}
private void send(int port, OutboundPacket packet) {
DeviceId deviceId = handler().data().deviceId();
Bmv2Controller controller;
try {
controller = handler().get(Bmv2Controller.class);
} catch (ServiceNotFoundException e) {
log.warn(e.getMessage());
return;
}
Bmv2DeviceAgent deviceAgent;
try {
deviceAgent = controller.getAgent(deviceId);
} catch (Bmv2RuntimeException e) {
log.error("Failed to get Bmv2 device agent for {}: {}", deviceId, e.explain());
return;
}
ImmutableByteSequence bs = ImmutableByteSequence.copyFrom(packet.data());
try {
deviceAgent.transmitPacket(port, bs);
} catch (Bmv2RuntimeException e) {
log.warn("Unable to emit packet trough {}: {}", deviceId, e.explain());
}
}
}