/* * 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 org.onlab.packet.Ethernet; import org.onlab.packet.IPv4; 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.FlowRuleOperations; 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.IPProtocolCriterion; import org.onosproject.net.flow.criteria.PortCriterion; import org.onosproject.net.flow.criteria.VlanIdCriterion; import org.onosproject.net.flowobjective.FilteringObjective; 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.slf4j.LoggerFactory.getLogger; /** * OpenvSwitch emulation of the Corsa pipeline handler. */ public class OvsCorsaPipeline extends AbstractCorsaPipeline { private final Logger log = getLogger(getClass()); protected static final int MAC_TABLE = 0; protected static final int VLAN_MPLS_TABLE = 1; protected static final int VLAN_TABLE = 2; //protected static final int MPLS_TABLE = 3; protected static final int ETHER_TABLE = 4; protected static final int COS_MAP_TABLE = 5; protected static final int FIB_TABLE = 6; protected static final int LOCAL_TABLE = 9; @Override protected Collection<FlowRule> processArpTraffic(ForwardingObjective fwd, FlowRule.Builder rule) { log.warn("Driver automatically handles ARP packets by punting to controller " + " from ETHER table"); pass(fwd); return Collections.emptyList(); } @Override protected Collection<FlowRule> processLinkDiscovery(ForwardingObjective fwd, FlowRule.Builder rule) { log.warn("Driver currently does not currently handle LLDP packets"); fail(fwd, ObjectiveError.UNSUPPORTED); return Collections.emptyList(); } @Override protected Collection<FlowRule> processIpTraffic(ForwardingObjective fwd, FlowRule.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 Collections.emptySet(); } 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 Collections.emptySet(); } 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 Collections.emptySet(); } return Collections.emptySet(); } @Override protected FlowRule.Builder processSpecificRoutingRule(FlowRule.Builder rb) { return rb.forTable(FIB_TABLE); } @Override protected FlowRule.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 protected FlowRule.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()); treatment.transition(ETHER_TABLE); treatment.deferred().popVlan(); return DefaultFlowRule.builder() .forDevice(deviceId) .withSelector(selector.build()) .withTreatment(treatment.build()) .withPriority(CONTROLLER_PRIORITY) .makePermanent() .forTable(VLAN_TABLE); } protected FlowRule.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()); treatment.transition(VLAN_MPLS_TABLE); return DefaultFlowRule.builder() .forDevice(deviceId) .withSelector(selector.build()) .withTreatment(treatment.build()) .withPriority(CONTROLLER_PRIORITY) .makePermanent() .forTable(MAC_TABLE); } @Override protected void initializePipeline() { processMacTable(true); processVlanMplsTable(true); processVlanTable(true); processEtherTable(true); processCosTable(true); processFibTable(true); processLocalTable(true); } private void processMacTable(boolean install) { TrafficSelector.Builder selector; TrafficTreatment.Builder treatment; // Bcast rule selector = DefaultTrafficSelector.builder(); treatment = DefaultTrafficTreatment.builder(); selector.matchEthDst(MacAddress.BROADCAST); treatment.transition(VLAN_MPLS_TABLE); FlowRule rule = DefaultFlowRule.builder() .forDevice(deviceId) .withSelector(selector.build()) .withTreatment(treatment.build()) .withPriority(CONTROLLER_PRIORITY) .fromApp(appId) .makePermanent() .forTable(MAC_TABLE).build(); processFlowRule(true, rule, "Provisioned mac table transition"); //Drop rule processTableMissDrop(true, MAC_TABLE, "Provisioned mac table drop action"); } protected void processVlanMplsTable(boolean install) { TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); TrafficTreatment.Builder treatment = DefaultTrafficTreatment .builder(); FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); FlowRule rule; selector.matchVlanId(VlanId.ANY); treatment.transition(VLAN_TABLE); rule = DefaultFlowRule.builder() .forDevice(deviceId) .withSelector(selector.build()) .withTreatment(treatment.build()) .withPriority(CONTROLLER_PRIORITY) .fromApp(appId) .makePermanent() .forTable(VLAN_MPLS_TABLE).build(); processFlowRule(true, rule, "Provisioned vlan/mpls table"); } private void processVlanTable(boolean install) { processTableMissDrop(true, VLAN_TABLE, "Provisioned vlan table"); } private void processEtherTable(boolean install) { TrafficSelector.Builder selector = DefaultTrafficSelector.builder() .matchEthType(Ethernet.TYPE_ARP); TrafficTreatment.Builder treatment = DefaultTrafficTreatment .builder() .punt(); FlowRule rule = DefaultFlowRule.builder() .forDevice(deviceId) .withSelector(selector.build()) .withTreatment(treatment.build()) .withPriority(CONTROLLER_PRIORITY) .fromApp(appId) .makePermanent() .forTable(ETHER_TABLE).build(); processFlowRule(true, rule, "Provisioned ether table"); selector = DefaultTrafficSelector.builder() .matchEthType(Ethernet.TYPE_IPV4); treatment = DefaultTrafficTreatment.builder() .transition(COS_MAP_TABLE); rule = DefaultFlowRule.builder() .forDevice(deviceId) .withPriority(CONTROLLER_PRIORITY) .withSelector(selector.build()) .withTreatment(treatment.build()) .fromApp(appId) .makePermanent() .forTable(ETHER_TABLE).build(); processFlowRule(true, rule, "Provisioned ether table"); //Drop rule processTableMissDrop(true, VLAN_TABLE, "Provisioned ether table"); } private void processCosTable(boolean install) { TrafficTreatment.Builder treatment = DefaultTrafficTreatment .builder() .transition(FIB_TABLE); TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); FlowRule rule = DefaultFlowRule.builder() .forDevice(deviceId) .withSelector(selector.build()) .withTreatment(treatment.build()) .withPriority(DROP_PRIORITY) .fromApp(appId) .makePermanent() .forTable(COS_MAP_TABLE).build(); processFlowRule(true, rule, "Provisioned cos table"); } private void processFibTable(boolean install) { processTableMissDrop(true, FIB_TABLE, "Provisioned FIB table"); } private void processLocalTable(boolean install) { TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); TrafficTreatment.Builder treatment = DefaultTrafficTreatment .builder() .punt(); FlowRule rule = DefaultFlowRule.builder() .forDevice(deviceId) .withSelector(selector.build()) .withTreatment(treatment.build()) .withPriority(CONTROLLER_PRIORITY) .fromApp(appId) .makePermanent() .forTable(LOCAL_TABLE).build(); processFlowRule(true, rule, "Provisioned Local table"); } }