/* * 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. */ package org.onosproject.provider.of.flow.impl; import org.onlab.packet.Ip4Address; import org.onosproject.net.PortNumber; import org.onosproject.net.driver.DriverService; import org.onosproject.net.flow.FlowRule; import org.onosproject.net.flow.TrafficTreatment; import org.onosproject.net.flow.instructions.Instruction; import org.onosproject.net.flow.instructions.Instructions.OutputInstruction; import org.onosproject.net.flow.instructions.Instructions.SetQueueInstruction; import org.onosproject.net.flow.instructions.L2ModificationInstruction; import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction; import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction; import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanPcpInstruction; import org.onosproject.net.flow.instructions.L3ModificationInstruction; import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModIPInstruction; import org.projectfloodlight.openflow.protocol.OFFactory; import org.projectfloodlight.openflow.protocol.OFFlowAdd; import org.projectfloodlight.openflow.protocol.OFFlowDelete; import org.projectfloodlight.openflow.protocol.OFFlowMod; import org.projectfloodlight.openflow.protocol.OFFlowModFlags; import org.projectfloodlight.openflow.protocol.action.OFAction; import org.projectfloodlight.openflow.protocol.action.OFActionOutput; import org.projectfloodlight.openflow.protocol.action.OFActionEnqueue; import org.projectfloodlight.openflow.protocol.match.Match; import org.projectfloodlight.openflow.types.IPv4Address; import org.projectfloodlight.openflow.types.MacAddress; import org.projectfloodlight.openflow.types.OFBufferId; import org.projectfloodlight.openflow.types.OFPort; import org.projectfloodlight.openflow.types.U64; import org.projectfloodlight.openflow.types.VlanPcp; import org.projectfloodlight.openflow.types.VlanVid; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Optional; /** * Flow mod builder for OpenFlow 1.0. */ public class FlowModBuilderVer10 extends FlowModBuilder { private final Logger log = LoggerFactory.getLogger(getClass()); private static final int OFPCML_NO_BUFFER = 0xffff; private final TrafficTreatment treatment; /** * Constructor for a flow mod builder for OpenFlow 1.0. * * @param flowRule the flow rule to transform into a flow mod * @param factory the OpenFlow factory to use to build the flow mod * @param xid the transaction ID * @param driverService the device driver service */ protected FlowModBuilderVer10(FlowRule flowRule, OFFactory factory, Optional<Long> xid, Optional<DriverService> driverService) { super(flowRule, factory, xid, driverService); this.treatment = flowRule.treatment(); } @Override public OFFlowAdd buildFlowAdd() { Match match = buildMatch(); List<OFAction> actions = buildActions(); long cookie = flowRule().id().value(); OFFlowAdd fm = factory().buildFlowAdd() .setXid(xid) .setCookie(U64.of(cookie)) .setBufferId(OFBufferId.NO_BUFFER) .setActions(actions) .setMatch(match) .setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM)) .setPriority(flowRule().priority()) .setHardTimeout(flowRule().hardTimeout()) .build(); return fm; } @Override public OFFlowMod buildFlowMod() { Match match = buildMatch(); List<OFAction> actions = buildActions(); long cookie = flowRule().id().value(); OFFlowMod fm = factory().buildFlowModify() .setXid(xid) .setCookie(U64.of(cookie)) .setBufferId(OFBufferId.NO_BUFFER) .setActions(actions) .setMatch(match) .setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM)) .setPriority(flowRule().priority()) .setHardTimeout(flowRule().hardTimeout()) .build(); return fm; } @Override public OFFlowDelete buildFlowDel() { Match match = buildMatch(); long cookie = flowRule().id().value(); OFFlowDelete fm = factory().buildFlowDelete() .setXid(xid) .setCookie(U64.of(cookie)) .setBufferId(OFBufferId.NO_BUFFER) .setMatch(match) .setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM)) .setPriority(flowRule().priority()) .setHardTimeout(flowRule().hardTimeout()) .build(); return fm; } private List<OFAction> buildActions() { List<OFAction> acts = new LinkedList<>(); OFAction act; if (treatment == null) { return acts; } for (Instruction i : treatment.immediate()) { switch (i.type()) { case NOACTION: return Collections.emptyList(); case L2MODIFICATION: act = buildL2Modification(i); if (act != null) { acts.add(buildL2Modification(i)); } break; case L3MODIFICATION: act = buildL3Modification(i); if (act != null) { acts.add(buildL3Modification(i)); } break; case OUTPUT: OutputInstruction out = (OutputInstruction) i; OFActionOutput.Builder action = factory().actions().buildOutput() .setPort(OFPort.of((int) out.port().toLong())); if (out.port().equals(PortNumber.CONTROLLER)) { action.setMaxLen(OFPCML_NO_BUFFER); } acts.add(action.build()); break; case QUEUE: SetQueueInstruction queue = (SetQueueInstruction) i; if (queue.port() == null) { log.warn("Required argument 'port' undefined for OFActionEnqueue"); } OFActionEnqueue.Builder queueBuilder = factory().actions().buildEnqueue() .setQueueId(queue.queueId()) .setPort(OFPort.ofInt((int) queue.port().toLong())); acts.add(queueBuilder.build()); break; case L0MODIFICATION: case L1MODIFICATION: case GROUP: case TABLE: case METADATA: log.warn("Instruction type {} not supported with protocol version {}", i.type(), factory().getVersion()); break; default: log.warn("Instruction type {} not yet implemented.", i.type()); } } return acts; } private OFAction buildL3Modification(Instruction i) { L3ModificationInstruction l3m = (L3ModificationInstruction) i; ModIPInstruction ip; Ip4Address ip4; switch (l3m.subtype()) { case IPV4_SRC: ip = (ModIPInstruction) i; ip4 = ip.ip().getIp4Address(); return factory().actions().setNwSrc(IPv4Address.of(ip4.toInt())); case IPV4_DST: ip = (ModIPInstruction) i; ip4 = ip.ip().getIp4Address(); return factory().actions().setNwDst(IPv4Address.of(ip4.toInt())); default: log.warn("Unimplemented action type {}.", l3m.subtype()); break; } return null; } private OFAction buildL2Modification(Instruction i) { L2ModificationInstruction l2m = (L2ModificationInstruction) i; ModEtherInstruction eth; switch (l2m.subtype()) { case ETH_DST: eth = (ModEtherInstruction) l2m; return factory().actions().setDlDst(MacAddress.of(eth.mac().toLong())); case ETH_SRC: eth = (ModEtherInstruction) l2m; return factory().actions().setDlSrc(MacAddress.of(eth.mac().toLong())); case VLAN_ID: ModVlanIdInstruction vlanId = (ModVlanIdInstruction) l2m; return factory().actions().setVlanVid(VlanVid.ofVlan(vlanId.vlanId().toShort())); case VLAN_PCP: ModVlanPcpInstruction vlanPcp = (ModVlanPcpInstruction) l2m; return factory().actions().setVlanPcp(VlanPcp.of(vlanPcp.vlanPcp())); case VLAN_POP: return factory().actions().stripVlan(); case VLAN_PUSH: return null; default: log.warn("Unimplemented action type {}.", l2m.subtype()); break; } return null; } }