| /* |
| * 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.MacAddress; |
| 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.EthCriterion; |
| import org.onosproject.net.flow.criteria.IPCriterion; |
| import org.onosproject.net.flow.criteria.PortCriterion; |
| import org.onosproject.net.flow.criteria.VlanIdCriterion; |
| import org.onosproject.net.flow.instructions.Instruction; |
| import org.onosproject.net.flow.instructions.L2ModificationInstruction; |
| import org.onosproject.net.flowobjective.FilteringObjective; |
| import org.onosproject.net.flowobjective.ForwardingObjective; |
| import org.onosproject.net.flowobjective.NextObjective; |
| import org.onosproject.net.flowobjective.ObjectiveError; |
| import org.onosproject.net.meter.Band; |
| import org.onosproject.net.meter.DefaultBand; |
| import org.onosproject.net.meter.DefaultMeterRequest; |
| import org.onosproject.net.meter.Meter; |
| import org.onosproject.net.meter.MeterId; |
| import org.onosproject.net.meter.MeterRequest; |
| import org.slf4j.Logger; |
| |
| import java.util.Collection; |
| import java.util.Collections; |
| |
| import static org.onosproject.net.flow.FlowRule.Builder; |
| import static org.slf4j.LoggerFactory.getLogger; |
| |
| /** |
| * Implementation of the Corsa pipeline handler for pipeline version 3. |
| */ |
| public class CorsaPipelineV3 extends AbstractCorsaPipeline { |
| |
| private final Logger log = getLogger(getClass()); |
| |
| protected static final int PORT_BASED_PROTO_TABLE = 0; |
| protected static final int VLAN_CHECK_TABLE = 1; |
| protected static final int VLAN_MAC_XLATE_TABLE = 2; |
| protected static final int VLAN_CIRCUIT_TABLE = 3; |
| protected static final int PRIORITY_MAP_TABLE = 4; |
| protected static final int L3_IF_MAC_DA_TABLE = 5; |
| protected static final int ETHER_TABLE = 6; |
| protected static final int FIB_TABLE = 7; |
| protected static final int LOCAL_TABLE = 9; |
| |
| protected static final byte MAX_VLAN_PCP = 7; |
| |
| protected MeterId defaultMeterId = null; |
| |
| @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 instanceof L2ModificationInstruction.ModVlanIdInstruction || |
| l2i instanceof L2ModificationInstruction.ModEtherInstruction) { |
| 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; |
| /** |
| * This represents the allowed group for CorsaPipelinev3 |
| */ |
| if (isPresentModVlanId && |
| isPresentModEthSrc && |
| isPresentModEthDst && |
| isPresentOutpuPort) { |
| type = CorsaTrafficTreatmentType.GROUP; |
| } |
| CorsaTrafficTreatment corsaTreatment = new CorsaTrafficTreatment(type, t); |
| return corsaTreatment; |
| } |
| |
| @Override |
| protected TrafficTreatment.Builder processSpecificRoutingTreatment() { |
| return DefaultTrafficTreatment.builder().deferred(); |
| } |
| |
| @Override |
| protected Builder processSpecificRoutingRule(Builder rb) { |
| return rb.forTable(FIB_TABLE); |
| } |
| |
| @Override |
| protected Collection<FlowRule> processSpecificSwitch(ForwardingObjective fwd) { |
| TrafficSelector filteredSelector = |
| DefaultTrafficSelector.builder() |
| .matchInPort( |
| ((PortCriterion) fwd.selector().getCriterion(Criterion.Type.IN_PORT)).port()) |
| .matchVlanId( |
| ((VlanIdCriterion) fwd.selector().getCriterion(Criterion.Type.VLAN_VID)).vlanId()) |
| .build(); |
| |
| Builder ruleBuilder = DefaultFlowRule.builder() |
| .fromApp(fwd.appId()) |
| .withPriority(fwd.priority()) |
| .forDevice(deviceId) |
| .withSelector(filteredSelector) |
| .forTable(VLAN_CIRCUIT_TABLE); |
| |
| if (fwd.treatment() != null) { |
| ruleBuilder.withTreatment(fwd.treatment()); |
| } else { |
| if (fwd.nextId() != null) { |
| NextObjective nextObjective = pendingNext.getIfPresent(fwd.nextId()); |
| if (nextObjective != null) { |
| pendingNext.invalidate(fwd.nextId()); |
| TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder() |
| .setVlanPcp((byte) 0) |
| .setQueue(0) |
| .meter(defaultMeterId); |
| nextObjective.next().forEach(trafficTreatment -> { |
| trafficTreatment.allInstructions().forEach(instruction -> { |
| treatment.add(instruction); |
| }); |
| }); |
| ruleBuilder.withTreatment(treatment.build()); |
| } else { |
| log.warn("The group left!"); |
| fwd.context().ifPresent(c -> c.onError(fwd, ObjectiveError.GROUPMISSING)); |
| return ImmutableSet.of(); |
| } |
| } else { |
| log.warn("Missing NextObjective ID for ForwardingObjective {}", fwd.id()); |
| fail(fwd, ObjectiveError.BADPARAMS); |
| return ImmutableSet.of(); |
| } |
| } |
| |
| if (fwd.permanent()) { |
| ruleBuilder.makePermanent(); |
| } else { |
| ruleBuilder.makeTemporary(fwd.timeout()); |
| } |
| |
| return Collections.singletonList(ruleBuilder.build()); |
| } |
| |
| @Override |
| protected Collection<FlowRule> processArpTraffic(ForwardingObjective fwd, Builder rule) { |
| //TODO |
| return ImmutableSet.of(); |
| } |
| |
| @Override |
| protected Collection<FlowRule> processLinkDiscovery(ForwardingObjective fwd, Builder rule) { |
| //TODO |
| return ImmutableSet.of(); |
| } |
| |
| @Override |
| protected Collection<FlowRule> processIpTraffic(ForwardingObjective fwd, Builder rule) { |
| //TODO |
| return ImmutableSet.of(); |
| } |
| |
| @Override |
| protected Builder processEthFiler(FilteringObjective filt, EthCriterion eth, PortCriterion port) { |
| log.debug("adding rule for MAC: {}", eth.mac()); |
| TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); |
| TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); |
| selector.matchEthDst(eth.mac()); |
| selector.matchInPort(port.port()); |
| treatment.transition(ETHER_TABLE); |
| return DefaultFlowRule.builder() |
| .withSelector(selector.build()) |
| .withTreatment(treatment.build()) |
| .withPriority(CONTROLLER_PRIORITY) |
| .makePermanent() |
| .forTable(L3_IF_MAC_DA_TABLE); |
| } |
| |
| @Override |
| protected Builder processVlanFiler(FilteringObjective filt, VlanIdCriterion vlan, PortCriterion port) { |
| log.debug("adding rule for VLAN: {}", vlan.vlanId()); |
| TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); |
| TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); |
| selector.matchVlanId(vlan.vlanId()); |
| selector.matchInPort(port.port()); |
| /* Static treatment for VLAN_CIRCUIT_TABLE */ |
| treatment.setVlanPcp(MAX_VLAN_PCP); |
| treatment.setQueue(0); |
| treatment.meter(MeterId.meterId(defaultMeterId.id())); /* use default meter (Green) */ |
| treatment.transition(L3_IF_MAC_DA_TABLE); |
| return DefaultFlowRule.builder() |
| .withSelector(selector.build()) |
| .withTreatment(treatment.build()) |
| .withPriority(CONTROLLER_PRIORITY) |
| .makePermanent() |
| .forTable(VLAN_CIRCUIT_TABLE); |
| } |
| |
| @Override |
| protected Builder processIpFilter(FilteringObjective filt, IPCriterion ip, PortCriterion port) { |
| log.debug("adding rule for IP: {}", ip.ip()); |
| TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); |
| TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); |
| selector.matchEthType(Ethernet.TYPE_IPV4); |
| selector.matchIPDst(ip.ip()); |
| treatment.transition(LOCAL_TABLE); |
| return DefaultFlowRule.builder() |
| .withSelector(selector.build()) |
| .withTreatment(treatment.build()) |
| .withPriority(HIGHEST_PRIORITY) |
| .makePermanent() |
| .forTable(FIB_TABLE); |
| } |
| |
| @Override |
| public void initializePipeline() { |
| processMeterTable(true); |
| processPortBasedProtoTable(true); /* Table 0 */ |
| processVlanCheckTable(true); /* Table 1 */ |
| processVlanMacXlateTable(true); /* Table 2 */ |
| processVlanCircuitTable(true); /* Table 3 */ |
| processPriorityMapTable(true); /* Table 4 */ |
| processL3IFMacDATable(true); /* Table 5 */ |
| processEtherTable(true); /* Table 6 */ |
| processFibTable(true); /* Table 7 */ |
| processLocalTable(true); /* Table 9 */ |
| } |
| |
| protected void processMeterTable(boolean install) { |
| //Green meter : Pass all traffic |
| Band dropBand = DefaultBand.builder() |
| .ofType(Band.Type.DROP) |
| .withRate(0xFFFFFFFF) /* Max Rate */ |
| .build(); |
| MeterRequest.Builder ops = DefaultMeterRequest.builder() |
| .forDevice(deviceId) |
| .withBands(Collections.singletonList(dropBand)) |
| .fromApp(appId); |
| |
| Meter meter = meterService.submit(install ? ops.add() : ops.remove()); |
| defaultMeterId = meter.id(); |
| } |
| |
| protected void processPortBasedProtoTable(boolean install) { |
| /* Default action */ |
| processTableMissGoTo(install, PORT_BASED_PROTO_TABLE, VLAN_CHECK_TABLE, "Provisioned port-based table"); |
| } |
| |
| protected void processVlanCheckTable(boolean install) { |
| |
| /* Default action */ |
| processTableMissDrop(install, VLAN_CHECK_TABLE, "Provisioned vlantable drop"); |
| |
| processTaggedPackets(install); |
| |
| } |
| |
| /* Tagged packets to VLAN_MAC_XLATE */ |
| protected void processTaggedPackets(boolean install) { |
| TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); |
| selector.matchVlanId(VlanId.ANY); |
| |
| TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); |
| treatment.transition(VLAN_MAC_XLATE_TABLE); |
| |
| FlowRule rule = DefaultFlowRule.builder() |
| .forDevice(deviceId) |
| .withSelector(selector.build()) |
| .withTreatment(treatment.build()) |
| .withPriority(CONTROLLER_PRIORITY) |
| .fromApp(appId) |
| .makePermanent() |
| .forTable(VLAN_CHECK_TABLE).build(); |
| processFlowRule(install, rule, "Provisioned vlan table tagged packets"); |
| } |
| |
| protected void processVlanMacXlateTable(boolean install) { |
| /* Default action */ |
| processTableMissGoTo(install, VLAN_MAC_XLATE_TABLE, VLAN_CIRCUIT_TABLE, "Provisioned vlan mac table"); |
| } |
| |
| protected void processVlanCircuitTable(boolean install) { |
| /* Default action */ |
| processTableMissDrop(install, VLAN_CIRCUIT_TABLE, "Provisioned vlan circuit"); |
| } |
| |
| private void processPriorityMapTable(boolean install) { |
| /* Not required currently */ |
| } |
| |
| protected void processL3IFMacDATable(boolean install) { |
| int table = L3_IF_MAC_DA_TABLE; |
| |
| /* Default action */ |
| processTableMissDrop(install, table, "Provisioned l3 table drop"); |
| |
| /* Allow MAC broadcast frames on all ports */ |
| TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); |
| selector.matchEthDst(MacAddress.BROADCAST); |
| |
| TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); |
| treatment.transition(ETHER_TABLE); |
| |
| FlowRule rule = DefaultFlowRule.builder() |
| .forDevice(deviceId) |
| .withSelector(selector.build()) |
| .withTreatment(treatment.build()) |
| .withPriority(CONTROLLER_PRIORITY) |
| .fromApp(appId) |
| .makePermanent() |
| .forTable(table).build(); |
| processFlowRule(install, rule, "Provisioned l3 table"); |
| } |
| |
| |
| protected void processEtherTable(boolean install) { |
| int table = ETHER_TABLE; |
| |
| /* Default action */ |
| processTableMissDrop(install, table, "Provisioned ether type table drop"); |
| |
| /* Arp to controller */ |
| TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); |
| selector.matchEthType(Ethernet.TYPE_ARP); |
| |
| TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); |
| treatment.punt(); |
| |
| FlowRule rule = DefaultFlowRule.builder() |
| .forDevice(deviceId) |
| .withSelector(selector.build()) |
| .withTreatment(treatment.build()) |
| .withPriority(CONTROLLER_PRIORITY) |
| .fromApp(appId) |
| .makePermanent() |
| .forTable(table).build(); |
| processFlowRule(install, rule, "Provisioned ether type table arp"); |
| |
| /* IP to FIB_TABLE */ |
| selector = DefaultTrafficSelector.builder(); |
| selector.matchEthType(Ethernet.TYPE_IPV4); |
| |
| treatment = DefaultTrafficTreatment.builder(); |
| treatment.transition(FIB_TABLE); |
| |
| rule = DefaultFlowRule.builder() |
| .forDevice(deviceId) |
| .withSelector(selector.build()) |
| .withTreatment(treatment.build()) |
| .withPriority(CONTROLLER_PRIORITY) |
| .fromApp(appId) |
| .makePermanent() |
| .forTable(table).build(); |
| processFlowRule(install, rule, "Provisioned ether type table ip"); |
| } |
| |
| protected void processFibTable(boolean install) { |
| /* Default action */ |
| processTableMissDrop(install, FIB_TABLE, "Provisioned fib drop"); |
| } |
| |
| private void processLocalTable(boolean install) { |
| int table = LOCAL_TABLE; |
| /* Default action */ |
| processTableMissDrop(install, table, "Provisioned local table drop"); |
| |
| /* Send all protocols to controller */ |
| TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); |
| |
| TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); |
| treatment.punt(); |
| |
| FlowRule rule = DefaultFlowRule.builder() |
| .forDevice(deviceId) |
| .withSelector(selector.build()) |
| .withTreatment(treatment.build()) |
| .withPriority(CONTROLLER_PRIORITY) |
| .fromApp(appId) |
| .makePermanent() |
| .forTable(table).build(); |
| processFlowRule(install, rule, "Provisioned ether type table to controller"); |
| } |
| |
| |
| } |