/* * Copyright 2015-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.openflow.controller; import org.onlab.packet.DeserializationException; import org.onlab.packet.Ethernet; import org.projectfloodlight.openflow.protocol.OFPacketIn; import org.projectfloodlight.openflow.protocol.OFPacketOut; import org.projectfloodlight.openflow.protocol.OFVersion; import org.projectfloodlight.openflow.protocol.action.OFAction; import org.projectfloodlight.openflow.protocol.action.OFActionOutput; import org.projectfloodlight.openflow.protocol.match.MatchField; import org.projectfloodlight.openflow.types.OFBufferId; import org.projectfloodlight.openflow.types.OFPort; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.nio.BufferUnderflowException; import java.util.Collections; import java.util.Optional; import java.util.concurrent.atomic.AtomicBoolean; import static org.onosproject.security.AppGuard.checkPermission; import static org.onosproject.security.AppPermission.Type.*; /** * Default implementation of an OpenFlowPacketContext. */ public final class DefaultOpenFlowPacketContext implements OpenFlowPacketContext { private final AtomicBoolean free = new AtomicBoolean(true); private final AtomicBoolean isBuilt = new AtomicBoolean(false); private final OpenFlowSwitch sw; private final OFPacketIn pktin; private OFPacketOut pktout = null; private final boolean isBuffered; private DefaultOpenFlowPacketContext(OpenFlowSwitch s, OFPacketIn pkt) { this.sw = s; this.pktin = pkt; this.isBuffered = pktin.getBufferId() != OFBufferId.NO_BUFFER; } @Override public void send() { checkPermission(PACKET_WRITE); if (block() && isBuilt.get()) { sw.sendMsg(pktout); } } @Override public void build(OFPort outPort) { if (isBuilt.getAndSet(true)) { return; } OFPacketOut.Builder builder = sw.factory().buildPacketOut(); OFAction act = buildOutput(outPort.getPortNumber()); pktout = builder.setXid(pktin.getXid()) .setInPort(pktinInPort()) .setBufferId(OFBufferId.NO_BUFFER) .setData(pktin.getData()) // .setBufferId(pktin.getBufferId()) .setActions(Collections.singletonList(act)) .build(); } @Override public void build(Ethernet ethFrame, OFPort outPort) { if (isBuilt.getAndSet(true)) { return; } OFPacketOut.Builder builder = sw.factory().buildPacketOut(); OFAction act = buildOutput(outPort.getPortNumber()); pktout = builder.setXid(pktin.getXid()) .setBufferId(OFBufferId.NO_BUFFER) .setInPort(pktinInPort()) .setActions(Collections.singletonList(act)) .setData(ethFrame.serialize()) .build(); } @Override public Ethernet parsed() { checkPermission(PACKET_READ); try { return Ethernet.deserializer().deserialize(pktin.getData(), 0, pktin.getData().length); } catch (BufferUnderflowException | NullPointerException | DeserializationException e) { Logger log = LoggerFactory.getLogger(getClass()); log.error("packet deserialization problem : {}", e.getMessage()); return null; } } @Override public Dpid dpid() { checkPermission(PACKET_READ); return new Dpid(sw.getId()); } /** * Creates an OpenFlow packet context based on a packet-in. * * @param s OpenFlow switch * @param pkt OpenFlow packet-in * @return the OpenFlow packet context */ public static OpenFlowPacketContext packetContextFromPacketIn(OpenFlowSwitch s, OFPacketIn pkt) { return new DefaultOpenFlowPacketContext(s, pkt); } @Override public Integer inPort() { checkPermission(PACKET_READ); return pktinInPort().getPortNumber(); } private OFPort pktinInPort() { if (pktin.getVersion() == OFVersion.OF_10) { return pktin.getInPort(); } return pktin.getMatch().get(MatchField.IN_PORT); } @Override public byte[] unparsed() { checkPermission(PACKET_READ); return pktin.getData().clone(); } private OFActionOutput buildOutput(Integer port) { OFActionOutput act = sw.factory().actions() .buildOutput() .setPort(OFPort.of(port)) .build(); return act; } @Override public boolean block() { checkPermission(PACKET_WRITE); return free.getAndSet(false); } @Override public boolean isHandled() { checkPermission(PACKET_READ); return !free.get(); } @Override public boolean isBuffered() { checkPermission(PACKET_READ); return isBuffered; } @Override public Optional<Long> cookie() { checkPermission(PACKET_READ); if (pktin.getVersion() != OFVersion.OF_10) { return Optional.of(pktin.getCookie().getValue()); } else { return Optional.empty(); } } }