/* * 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.corsa; import com.google.common.collect.ImmutableSet; import org.onlab.packet.Ethernet; import org.onlab.packet.IPv4; import org.onlab.packet.VlanId; import org.onosproject.net.flow.DefaultFlowRule; import org.onosproject.net.flow.DefaultTrafficSelector; import org.onosproject.net.flow.DefaultTrafficTreatment; import org.onosproject.net.flow.FlowRule; import org.onosproject.net.flow.TrafficSelector; import org.onosproject.net.flow.TrafficTreatment; import org.onosproject.net.flow.criteria.Criterion; import org.onosproject.net.flow.criteria.IPCriterion; import org.onosproject.net.flow.criteria.IPProtocolCriterion; import org.onosproject.net.flow.instructions.Instruction; import org.onosproject.net.flow.instructions.Instructions; import org.onosproject.net.flow.instructions.L2ModificationInstruction; import org.onosproject.net.flowobjective.ForwardingObjective; import org.onosproject.net.flowobjective.ObjectiveError; import org.slf4j.Logger; import java.util.Collection; import java.util.Collections; import static org.onosproject.net.flow.FlowRule.Builder; import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.ETH_DST; import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.ETH_SRC; import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.VLAN_ID; import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.VLAN_POP; import static org.slf4j.LoggerFactory.getLogger; public class CorsaPipelineV39 extends CorsaPipelineV3 { private final Logger log = getLogger(getClass()); private static final Short NATIVE_VLAN = 4095; @Override public void initializePipeline() { processMeterTable(true); //Meter Table processPortBasedProtoTable(true); processVlanCheckTable(true); //Table 1 processVlanMacXlateTable(true); //Table 2 processVlanCircuitTable(true); //Table 3 processL3IFMacDATable(true); //Table 5 processEtherTable(true); //Table 6 //TODO: to be implemented for intents processFibTable(true); //Table 7 //processLocalTable(true); //Table 9 } @Override protected void processVlanCheckTable(boolean install) { //current device pipeline reports errors, but it is a bug processTableMissGoTo(true, VLAN_CHECK_TABLE, VLAN_MAC_XLATE_TABLE, "Provisioned vlan tagged"); //Tag untagged packets processUntaggedPackets(install); } private void processUntaggedPackets(boolean install) { deviceService.getPorts(deviceId).forEach(port -> { if (!port.number().isLogical()) { TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder() .pushVlan().setVlanId(VlanId.vlanId(NATIVE_VLAN)) .transition(VLAN_MAC_XLATE_TABLE); TrafficSelector.Builder selector = DefaultTrafficSelector.builder() .matchVlanId(VlanId.NONE) .matchInPort(port.number()); Builder rule = DefaultFlowRule.builder() .forDevice(deviceId) .withTreatment(treatment.build()) .withSelector(selector.build()) .withPriority(CONTROLLER_PRIORITY) .fromApp(appId) .makePermanent() .forTable(VLAN_CHECK_TABLE); processFlowRule(install, rule.build(), "Provisioned vlan untagged packet table"); } }); } @Override protected void processVlanCircuitTable(boolean install) { //Default action processTableMissDrop(install, VLAN_CIRCUIT_TABLE, "Provisioned vlan circuit table drop"); //FIXME: it should be done only per port based when intent is installed //Manage untagged packets processRouterPacket(install); } private void processRouterPacket(boolean install) { deviceService.getPorts(deviceId).forEach(port -> { if (!port.number().isLogical()) { TrafficSelector.Builder selector = DefaultTrafficSelector.builder() .matchVlanId(VlanId.vlanId(NATIVE_VLAN)) .matchInPort(port.number()); TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder() .setVlanPcp((byte) 0) .setQueue(0) .meter(defaultMeterId) .transition(L3_IF_MAC_DA_TABLE); FlowRule rule = DefaultFlowRule.builder() .forDevice(deviceId) .withSelector(selector.build()) .withTreatment(treatment.build()) .withPriority(CONTROLLER_PRIORITY) .fromApp(appId) .makePermanent() .forTable(VLAN_CIRCUIT_TABLE).build(); processFlowRule(install, rule, "Provisioned vlan circuit table"); } }); } @Override protected void processL3IFMacDATable(boolean install) { int table = L3_IF_MAC_DA_TABLE; //Default action processTableMissDrop(install, table, "Provisioned l3 table drop"); TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder() .transition(ETHER_TABLE); FlowRule rule = DefaultFlowRule.builder() .forDevice(deviceId) .withSelector(selector.build()) .withTreatment(treatment.build()) .withPriority(1) .fromApp(appId) .makePermanent() .forTable(table).build(); processFlowRule(install, rule, "Provisioned l3 table"); } protected void processEtherTable(boolean install) { //Default action processTableMissDrop(install, ETHER_TABLE, "Provisioned ether type table drop"); //IP to FIB_TABLE TrafficSelector.Builder selector = DefaultTrafficSelector.builder() .matchEthType(Ethernet.TYPE_IPV4); TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder().transition(FIB_TABLE); FlowRule rule = DefaultFlowRule.builder() .forDevice(deviceId) .withSelector(selector.build()) .withTreatment(treatment.build()) .withPriority(CONTROLLER_PRIORITY) .fromApp(appId) .makePermanent() .forTable(ETHER_TABLE).build(); processFlowRule(install, rule, "Provisioned ether type table ip"); } @Override protected Collection<FlowRule> processArpTraffic(ForwardingObjective fwd, Builder rule) { rule.forTable(PORT_BASED_PROTO_TABLE); rule.withPriority(255); return Collections.singletonList(rule.build()); } @Override protected Collection<FlowRule> processLinkDiscovery(ForwardingObjective fwd, Builder rule) { rule.forTable(PORT_BASED_PROTO_TABLE); rule.withPriority(255); return Collections.singletonList(rule.build()); } @Override protected Collection<FlowRule> processIpTraffic(ForwardingObjective fwd, Builder rule) { IPCriterion ipSrc = (IPCriterion) fwd.selector() .getCriterion(Criterion.Type.IPV4_SRC); if (ipSrc != null) { log.warn("Driver does not currently handle matching Src IP"); fail(fwd, ObjectiveError.UNSUPPORTED); return ImmutableSet.of(); } IPCriterion ipDst = (IPCriterion) fwd.selector() .getCriterion(Criterion.Type.IPV4_DST); if (ipDst != null) { log.error("Driver handles Dst IP matching as specific forwarding " + "objective, not versatile"); fail(fwd, ObjectiveError.UNSUPPORTED); return ImmutableSet.of(); } IPProtocolCriterion ipProto = (IPProtocolCriterion) fwd.selector() .getCriterion(Criterion.Type.IP_PROTO); if (ipProto != null && ipProto.protocol() == IPv4.PROTOCOL_TCP) { log.warn("Driver automatically punts all packets reaching the " + "LOCAL table to the controller"); pass(fwd); return ImmutableSet.of(); } return ImmutableSet.of(); } @Override protected CorsaTrafficTreatment processNextTreatment(TrafficTreatment treatment) { TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder(); treatment.immediate().stream() .filter(i -> { switch (i.type()) { case L2MODIFICATION: L2ModificationInstruction l2i = (L2ModificationInstruction) i; if (l2i.subtype() == VLAN_ID || l2i.subtype() == VLAN_POP || l2i.subtype() == ETH_DST || l2i.subtype() == ETH_SRC) { return true; } case OUTPUT: return true; default: return false; } }).forEach(i -> tb.add(i)); TrafficTreatment t = tb.build(); boolean isPresentModVlanId = false; boolean isPresentModEthSrc = false; boolean isPresentModEthDst = false; boolean isPresentOutpuPort = false; for (Instruction instruction : t.immediate()) { switch (instruction.type()) { case L2MODIFICATION: L2ModificationInstruction l2i = (L2ModificationInstruction) instruction; if (l2i instanceof L2ModificationInstruction.ModVlanIdInstruction) { isPresentModVlanId = true; } if (l2i instanceof L2ModificationInstruction.ModEtherInstruction) { L2ModificationInstruction.L2SubType subType = l2i.subtype(); if (subType.equals(L2ModificationInstruction.L2SubType.ETH_SRC)) { isPresentModEthSrc = true; } else if (subType.equals(L2ModificationInstruction.L2SubType.ETH_DST)) { isPresentModEthDst = true; } } case OUTPUT: isPresentOutpuPort = true; default: } } CorsaTrafficTreatmentType type = CorsaTrafficTreatmentType.ACTIONS; /** * These are the allowed groups for CorsaPipelinev39 */ if (isPresentModVlanId && isPresentModEthSrc && isPresentModEthDst && isPresentOutpuPort) { type = CorsaTrafficTreatmentType.GROUP; } else if ((!isPresentModVlanId && isPresentModEthSrc && isPresentModEthDst && isPresentOutpuPort) || (!isPresentModVlanId && !isPresentModEthSrc && isPresentModEthDst && isPresentOutpuPort) || (!isPresentModVlanId && !isPresentModEthSrc && !isPresentModEthDst && isPresentOutpuPort)) { type = CorsaTrafficTreatmentType.GROUP; TrafficTreatment.Builder tb2 = DefaultTrafficTreatment.builder(t); tb2.add(Instructions.popVlan()); t = tb2.build(); } CorsaTrafficTreatment corsaTreatment = new CorsaTrafficTreatment(type, t); return corsaTreatment; } }