/* * Copyright 2015 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.driver.pipeline; import org.onlab.osgi.ServiceDirectory; import org.onlab.packet.Ethernet; import org.onosproject.core.ApplicationId; import org.onosproject.core.CoreService; import org.onosproject.net.DeviceId; import org.onosproject.net.behaviour.Pipeliner; import org.onosproject.net.behaviour.PipelinerContext; 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.FlowRuleOperationsContext; import org.onosproject.net.flow.FlowRuleService; 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.EthTypeCriterion; import org.onosproject.net.flow.criteria.UdpPortCriterion; import org.onosproject.net.flowobjective.FilteringObjective; import org.onosproject.net.flowobjective.FlowObjectiveStore; import org.onosproject.net.flowobjective.ForwardingObjective; import org.onosproject.net.flowobjective.NextObjective; import org.onosproject.net.flowobjective.Objective; import org.onosproject.net.flowobjective.ObjectiveError; import org.slf4j.Logger; import java.util.Collection; import java.util.Collections; import static org.slf4j.LoggerFactory.getLogger; /** * Driver for OpenstackSwitching. */ public class OpenstackPipeline extends DefaultSingleTablePipeline implements Pipeliner { private final Logger log = getLogger(getClass()); private CoreService coreService; private ServiceDirectory serviceDirectory; protected FlowObjectiveStore flowObjectiveStore; protected DeviceId deviceId; protected ApplicationId appId; protected FlowRuleService flowRuleService; protected static final int VNI_TABLE = 0; protected static final int FORWARDING_TABLE = 1; private static final int DROP_PRIORITY = 0; private static final int TIME_OUT = 0; private static final int DHCP_SERVER_PORT = 67; private static final int DHCP_CLIENT_PORT = 68; @Override public void init(DeviceId deviceId, PipelinerContext context) { super.init(deviceId, context); this.serviceDirectory = context.directory(); this.deviceId = deviceId; coreService = serviceDirectory.get(CoreService.class); flowRuleService = serviceDirectory.get(FlowRuleService.class); flowObjectiveStore = context.store(); appId = coreService.registerApplication( "org.onosproject.driver.OpenstackPipeline"); initializePipeline(); } @Override public void filter(FilteringObjective filteringObjective) { super.filter(filteringObjective); } @Override public void next(NextObjective nextObjective) { super.next(nextObjective); } @Override public void forward(ForwardingObjective forwardingObjective) { Collection rules; FlowRuleOperations.Builder flowOpsBuilder = FlowRuleOperations.builder(); rules = processForward(forwardingObjective); switch (forwardingObjective.op()) { case ADD: rules.stream() .filter(rule -> rule != null) .forEach(flowOpsBuilder::add); break; case REMOVE: rules.stream() .filter(rule -> rule != null) .forEach(flowOpsBuilder::remove); break; default: fail(forwardingObjective, ObjectiveError.UNKNOWN); log.warn("Unknown forwarding type {}"); } flowRuleService.apply(flowOpsBuilder.build(new FlowRuleOperationsContext() { @Override public void onSuccess(FlowRuleOperations ops) { pass(forwardingObjective); } @Override public void onError(FlowRuleOperations ops) { fail(forwardingObjective, ObjectiveError.FLOWINSTALLATIONFAILED); } })); } private void initializePipeline() { processVNITable(true); processForwardingTable(true); } private void processVNITable(boolean install) { TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); treatment.transition(FORWARDING_TABLE); FlowRule flowRule = DefaultFlowRule.builder() .forDevice(deviceId) .withSelector(selector.build()) .withTreatment(treatment.build()) .withPriority(DROP_PRIORITY) .fromApp(appId) .makePermanent() .forTable(VNI_TABLE) .build(); applyRules(install, flowRule); } private void processForwardingTable(boolean install) { TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); treatment.drop(); FlowRule flowRule = DefaultFlowRule.builder() .forDevice(deviceId) .withSelector(selector.build()) .withTreatment(treatment.build()) .withPriority(DROP_PRIORITY) .fromApp(appId) .makePermanent() .forTable(FORWARDING_TABLE) .build(); applyRules(install, flowRule); } private void applyRules(boolean install, FlowRule flowRule) { FlowRuleOperations.Builder flowOpsBuilder = FlowRuleOperations.builder(); flowOpsBuilder = install ? flowOpsBuilder.add(flowRule) : flowOpsBuilder.remove(flowRule); flowRuleService.apply(flowOpsBuilder.build(new FlowRuleOperationsContext() { @Override public void onSuccess(FlowRuleOperations ops) { log.debug("Provisioned vni or forwarding table"); } @Override public void onError(FlowRuleOperations ops) { log.debug("Failed to privision vni or forwarding table"); } })); } private Collection processForward(ForwardingObjective forwardingObjective) { switch (forwardingObjective.flag()) { case SPECIFIC: return processSpecific(forwardingObjective); case VERSATILE: return processVersatile(forwardingObjective); default: fail(forwardingObjective, ObjectiveError.UNKNOWN); log.warn("Unknown forwarding flag {}", forwardingObjective.flag()); } return Collections.emptySet(); } private Collection processVersatile(ForwardingObjective forwardingObjective) { log.debug("Processing versatile forwarding objective"); FlowRule.Builder ruleBuilder = DefaultFlowRule.builder() .forDevice(deviceId) .withSelector(forwardingObjective.selector()) .withTreatment(forwardingObjective.treatment()) .withPriority(forwardingObjective.priority()) .fromApp(forwardingObjective.appId()); if (forwardingObjective.permanent()) { ruleBuilder.makePermanent(); } else { ruleBuilder.makeTemporary(TIME_OUT); } //ARP & DHCP Rule EthTypeCriterion ethCriterion = (EthTypeCriterion) forwardingObjective.selector().getCriterion(Criterion.Type.ETH_TYPE); UdpPortCriterion udpPortCriterion = (UdpPortCriterion) forwardingObjective .selector().getCriterion(Criterion.Type.UDP_DST); if (ethCriterion != null) { if (ethCriterion.ethType().toShort() == Ethernet.TYPE_ARP || ethCriterion.ethType().toShort() == Ethernet.TYPE_LLDP) { ruleBuilder.forTable(VNI_TABLE); return Collections.singletonList(ruleBuilder.build()); } else if (udpPortCriterion != null && udpPortCriterion.udpPort().toInt() == DHCP_SERVER_PORT) { ruleBuilder.forTable(VNI_TABLE); return Collections.singletonList(ruleBuilder.build()); } } return Collections.emptySet(); } private Collection processSpecific(ForwardingObjective forwardingObjective) { log.debug("Processing specific forwarding objective"); FlowRule.Builder ruleBuilder = DefaultFlowRule.builder() .forDevice(deviceId) .withSelector(forwardingObjective.selector()) .withTreatment(forwardingObjective.treatment()) .withPriority(forwardingObjective.priority()) .fromApp(forwardingObjective.appId()); if (forwardingObjective.permanent()) { ruleBuilder.makePermanent(); } else { ruleBuilder.makeTemporary(TIME_OUT); } //VNI Table Rule if (forwardingObjective.selector().getCriterion(Criterion.Type.IN_PORT) != null) { TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder(); forwardingObjective.treatment().allInstructions().forEach(tBuilder::add); tBuilder.transition(FORWARDING_TABLE); ruleBuilder.withTreatment(tBuilder.build()); ruleBuilder.forTable(VNI_TABLE); } else { ruleBuilder.forTable(FORWARDING_TABLE); } return Collections.singletonList(ruleBuilder.build()); } private void pass(Objective obj) { if (obj.context().isPresent()) { obj.context().get().onSuccess(obj); } } private void fail(Objective obj, ObjectiveError error) { if (obj.context().isPresent()) { obj.context().get().onError(obj, error); } } }