diff options
Diffstat (limited to 'framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline')
14 files changed, 0 insertions, 7140 deletions
diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/CentecV350Pipeline.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/CentecV350Pipeline.java deleted file mode 100644 index cd7a1b66..00000000 --- a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/CentecV350Pipeline.java +++ /dev/null @@ -1,640 +0,0 @@ -/* - * 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 com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.RemovalCause; -import com.google.common.cache.RemovalNotification; - -import org.onlab.osgi.ServiceDirectory; -import org.onlab.packet.Ethernet; -import org.onlab.packet.IPv4; -import org.onlab.packet.TpPort; -import org.onlab.packet.VlanId; -import org.onlab.util.KryoNamespace; -import org.onosproject.core.ApplicationId; -import org.onosproject.core.CoreService; -import org.onosproject.net.DeviceId; -import org.onosproject.net.PortNumber; -import org.onosproject.net.behaviour.NextGroup; -import org.onosproject.net.behaviour.Pipeliner; -import org.onosproject.net.behaviour.PipelinerContext; -import org.onosproject.net.driver.AbstractHandlerBehaviour; -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.Criteria; -import org.onosproject.net.flow.criteria.EthCriterion; -import org.onosproject.net.flow.criteria.PortCriterion; -import org.onosproject.net.flow.criteria.EthTypeCriterion; -import org.onosproject.net.flow.criteria.IPCriterion; -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.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.onosproject.net.group.DefaultGroupBucket; -import org.onosproject.net.group.DefaultGroupDescription; -import org.onosproject.net.group.DefaultGroupKey; -import org.onosproject.net.group.Group; -import org.onosproject.net.group.GroupBucket; -import org.onosproject.net.group.GroupBuckets; -import org.onosproject.net.group.GroupDescription; -import org.onosproject.net.group.GroupEvent; -import org.onosproject.net.group.GroupKey; -import org.onosproject.net.group.GroupListener; -import org.onosproject.net.group.GroupService; -import org.slf4j.Logger; - -import java.util.Collection; -import java.util.Collections; -import java.util.Set; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; - -import static org.onlab.util.Tools.groupedThreads; -import static org.slf4j.LoggerFactory.getLogger; - -/** - * Driver for Centec's V350 switches. - */ -public class CentecV350Pipeline extends AbstractHandlerBehaviour implements Pipeliner { - - protected static final int PORT_VLAN_TABLE = 0; - protected static final int FILTER_TABLE = 1; - // TMAC is configured in MAC Table to redirect packets to ROUTE_TABLE. - protected static final int MAC_TABLE = 2; - protected static final int ROUTE_TABLE = 3; - - private static final long DEFAULT_METADATA = 100; - private static final long DEFAULT_METADATA_MASK = 0xffffffffffffffffL; - - // Priority used in PORT_VLAN Table, the only priority accepted is PORT_VLAN_TABLE_PRIORITY. - // The packet passed PORT+VLAN check will goto FILTER Table. - private static final int PORT_VLAN_TABLE_PRIORITY = 0xffff; - - // Priority used in Filter Table. - private static final int FILTER_TABLE_CONTROLLER_PRIORITY = 500; - // TMAC priority should be lower than controller. - private static final int FILTER_TABLE_TMAC_PRIORITY = 200; - private static final int FILTER_TABLE_HIGHEST_PRIORITY = 0xffff; - - // Priority used in MAC Table. - // We do exact matching for DMAC+metadata, so priority is ignored and required to be set to 0xffff. - private static final int MAC_TABLE_PRIORITY = 0xffff; - - // Priority used in Route Table. - // We do LPM matching in Route Table, so priority is ignored and required to be set to 0xffff. - private static final int ROUTE_TABLE_PRIORITY = 0xffff; - - private static final short BGP_PORT = 179; - - private final Logger log = getLogger(getClass()); - - private ServiceDirectory serviceDirectory; - private FlowRuleService flowRuleService; - private CoreService coreService; - private GroupService groupService; - private FlowObjectiveStore flowObjectiveStore; - private DeviceId deviceId; - private ApplicationId appId; - - private KryoNamespace appKryo = new KryoNamespace.Builder() - .register(GroupKey.class) - .register(DefaultGroupKey.class) - .register(CentecV350Group.class) - .register(byte[].class) - .build(); - - private Cache<GroupKey, NextObjective> pendingGroups; - - private ScheduledExecutorService groupChecker = - Executors.newScheduledThreadPool(2, groupedThreads("onos/pipeliner", - "centec-V350-%d")); - - @Override - public void init(DeviceId deviceId, PipelinerContext context) { - this.serviceDirectory = context.directory(); - this.deviceId = deviceId; - - pendingGroups = CacheBuilder.newBuilder() - .expireAfterWrite(20, TimeUnit.SECONDS) - .removalListener((RemovalNotification<GroupKey, NextObjective> notification) -> { - if (notification.getCause() == RemovalCause.EXPIRED) { - fail(notification.getValue(), ObjectiveError.GROUPINSTALLATIONFAILED); - } - }).build(); - - groupChecker.scheduleAtFixedRate(new GroupChecker(), 0, 500, TimeUnit.MILLISECONDS); - - coreService = serviceDirectory.get(CoreService.class); - flowRuleService = serviceDirectory.get(FlowRuleService.class); - groupService = serviceDirectory.get(GroupService.class); - flowObjectiveStore = context.store(); - - groupService.addListener(new InnerGroupListener()); - - appId = coreService.registerApplication( - "org.onosproject.driver.CentecV350Pipeline"); - - initializePipeline(); - } - - @Override - public void filter(FilteringObjective filteringObjective) { - if (filteringObjective.type() == FilteringObjective.Type.PERMIT) { - processFilter(filteringObjective, - filteringObjective.op() == Objective.Operation.ADD, - filteringObjective.appId()); - } else { - fail(filteringObjective, ObjectiveError.UNSUPPORTED); - } - } - - @Override - public void forward(ForwardingObjective fwd) { - Collection<FlowRule> rules; - FlowRuleOperations.Builder flowBuilder = FlowRuleOperations.builder(); - - rules = processForward(fwd); - switch (fwd.op()) { - case ADD: - rules.stream() - .filter(rule -> rule != null) - .forEach(flowBuilder::add); - break; - case REMOVE: - rules.stream() - .filter(rule -> rule != null) - .forEach(flowBuilder::remove); - break; - default: - fail(fwd, ObjectiveError.UNKNOWN); - log.warn("Unknown forwarding type {}", fwd.op()); - } - - - flowRuleService.apply(flowBuilder.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - pass(fwd); - } - - @Override - public void onError(FlowRuleOperations ops) { - fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED); - } - })); - - } - - @Override - public void next(NextObjective nextObjective) { - switch (nextObjective.type()) { - case SIMPLE: - Collection<TrafficTreatment> treatments = nextObjective.next(); - if (treatments.size() == 1) { - TrafficTreatment treatment = treatments.iterator().next(); - - // Since we do not support strip_vlan in PORT_VLAN table, we use mod_vlan - // to modify the packet to desired vlan. - // Note: if we use push_vlan here, the switch will add a second VLAN tag to the outgoing - // packet, which is not what we want. - TrafficTreatment.Builder treatmentWithoutPushVlan = DefaultTrafficTreatment.builder(); - VlanId modVlanId; - for (Instruction ins : treatment.allInstructions()) { - if (ins.type() == Instruction.Type.L2MODIFICATION) { - L2ModificationInstruction l2ins = (L2ModificationInstruction) ins; - switch (l2ins.subtype()) { - case ETH_DST: - treatmentWithoutPushVlan.setEthDst( - ((L2ModificationInstruction.ModEtherInstruction) l2ins).mac()); - break; - case ETH_SRC: - treatmentWithoutPushVlan.setEthSrc( - ((L2ModificationInstruction.ModEtherInstruction) l2ins).mac()); - break; - case VLAN_ID: - modVlanId = ((L2ModificationInstruction.ModVlanIdInstruction) l2ins).vlanId(); - treatmentWithoutPushVlan.setVlanId(modVlanId); - break; - default: - break; - } - } else if (ins.type() == Instruction.Type.OUTPUT) { - //long portNum = ((Instructions.OutputInstruction) ins).port().toLong(); - treatmentWithoutPushVlan.add(ins); - } else { - // Ignore the vlan_pcp action since it's does matter much. - log.warn("Driver does not handle this type of TrafficTreatment" - + " instruction in nextObjectives: {}", ins.type()); - } - } - - GroupBucket bucket = - DefaultGroupBucket.createIndirectGroupBucket(treatmentWithoutPushVlan.build()); - final GroupKey key = new DefaultGroupKey(appKryo.serialize(nextObjective.id())); - GroupDescription groupDescription - = new DefaultGroupDescription(deviceId, - GroupDescription.Type.INDIRECT, - new GroupBuckets(Collections - .singletonList(bucket)), - key, - null, // let group service determine group id - nextObjective.appId()); - groupService.addGroup(groupDescription); - pendingGroups.put(key, nextObjective); - } - break; - case HASHED: - case BROADCAST: - case FAILOVER: - fail(nextObjective, ObjectiveError.UNSUPPORTED); - log.warn("Unsupported next objective type {}", nextObjective.type()); - break; - default: - fail(nextObjective, ObjectiveError.UNKNOWN); - log.warn("Unknown next objective type {}", nextObjective.type()); - } - - } - - private Collection<FlowRule> processForward(ForwardingObjective fwd) { - switch (fwd.flag()) { - case SPECIFIC: - return processSpecific(fwd); - case VERSATILE: - return processVersatile(fwd); - default: - fail(fwd, ObjectiveError.UNKNOWN); - log.warn("Unknown forwarding flag {}", fwd.flag()); - } - return Collections.emptySet(); - } - - private Collection<FlowRule> processVersatile(ForwardingObjective fwd) { - log.warn("Driver does not support versatile forwarding objective"); - fail(fwd, ObjectiveError.UNSUPPORTED); - return Collections.emptySet(); - } - - private Collection<FlowRule> processSpecific(ForwardingObjective fwd) { - log.debug("Processing specific forwarding objective"); - TrafficSelector selector = fwd.selector(); - EthTypeCriterion ethType = - (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE); - if (ethType == null || ethType.ethType().toShort() != Ethernet.TYPE_IPV4) { - fail(fwd, ObjectiveError.UNSUPPORTED); - return Collections.emptySet(); - } - - // Must have metadata as key. - TrafficSelector filteredSelector = - DefaultTrafficSelector.builder() - .matchEthType(Ethernet.TYPE_IPV4) - .matchMetadata(DEFAULT_METADATA) - .matchIPDst( - ((IPCriterion) - selector.getCriterion(Criterion.Type.IPV4_DST)).ip()) - .build(); - - TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder(); - - if (fwd.nextId() != null) { - NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId()); - GroupKey key = appKryo.deserialize(next.data()); - Group group = groupService.getGroup(deviceId, key); - if (group == null) { - log.warn("The group left!"); - fail(fwd, ObjectiveError.GROUPMISSING); - return Collections.emptySet(); - } - tb.group(group.id()); - } - - FlowRule.Builder ruleBuilder = DefaultFlowRule.builder() - .fromApp(fwd.appId()) - .withPriority(ROUTE_TABLE_PRIORITY) - .forDevice(deviceId) - .withSelector(filteredSelector) - .withTreatment(tb.build()); - - if (fwd.permanent()) { - ruleBuilder.makePermanent(); - } else { - ruleBuilder.makeTemporary(fwd.timeout()); - } - - ruleBuilder.forTable(ROUTE_TABLE); - - return Collections.singletonList(ruleBuilder.build()); - - } - - private void processFilter(FilteringObjective filt, boolean install, - ApplicationId applicationId) { - PortCriterion p; - if (!filt.key().equals(Criteria.dummy()) && - filt.key().type() == Criterion.Type.IN_PORT) { - p = (PortCriterion) filt.key(); - } else { - log.warn("No key defined in filtering objective from app: {}. Not" - + "processing filtering objective", applicationId); - fail(filt, ObjectiveError.UNKNOWN); - return; - } - - // Convert filtering conditions for switch-intfs into flow rules. - FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); - - for (Criterion c : filt.conditions()) { - // Here we do a trick to install 2 flow rules to MAC_TABLE and ROUTE_TABLE. - if (c.type() == Criterion.Type.ETH_DST) { - EthCriterion e = (EthCriterion) c; - - // Install TMAC flow rule. - log.debug("adding rule for Termination MAC in Filter Table: {}", e.mac()); - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); - selector.matchEthDst(e.mac()); - // Add IPv4 matching explicitly since we will redirect it to ROUTE Table - // through MAC table. - selector.matchEthType(Ethernet.TYPE_IPV4); - treatment.transition(MAC_TABLE); - FlowRule rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(FILTER_TABLE_TMAC_PRIORITY) - .fromApp(applicationId) - .makePermanent() - .forTable(FILTER_TABLE).build(); - ops = install ? ops.add(rule) : ops.remove(rule); - - // Must install another rule to direct the IPv4 packets that hit TMAC to - // Route table. - log.debug("adding rule for Termination MAC in MAC Table: {}", e.mac()); - selector = DefaultTrafficSelector.builder(); - treatment = DefaultTrafficTreatment.builder(); - selector.matchEthDst(e.mac()); - // MAC_Table must have metadata matching configured, use the default metadata. - selector.matchMetadata(DEFAULT_METADATA); - treatment.transition(ROUTE_TABLE); - rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(MAC_TABLE_PRIORITY) - .fromApp(applicationId) - .makePermanent() - .forTable(MAC_TABLE).build(); - ops = install ? ops.add(rule) : ops.remove(rule); - } else if (c.type() == Criterion.Type.VLAN_VID) { - VlanIdCriterion v = (VlanIdCriterion) c; - log.debug("adding rule for VLAN: {}", v.vlanId()); - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); - selector.matchVlanId(v.vlanId()); - selector.matchInPort(p.port()); - // Although the accepted packets will be sent to filter table, we must - // explicitly set goto_table instruction here. - treatment.writeMetadata(DEFAULT_METADATA, DEFAULT_METADATA_MASK); - // set default metadata written by PORT_VLAN Table. - treatment.transition(FILTER_TABLE); - // We do not support strip vlan here, treatment.deferred().popVlan(); - // PORT_VLAN table only accept 0xffff priority since it does exact match only. - FlowRule rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(PORT_VLAN_TABLE_PRIORITY) - .fromApp(applicationId) - .makePermanent() - .forTable(PORT_VLAN_TABLE).build(); - ops = install ? ops.add(rule) : ops.remove(rule); - } else if (c.type() == Criterion.Type.IPV4_DST) { - IPCriterion ipaddr = (IPCriterion) c; - log.debug("adding IP filtering rules in FILTER table: {}", ipaddr.ip()); - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); - selector.matchEthType(Ethernet.TYPE_IPV4); - selector.matchIPDst(ipaddr.ip()); // router IPs to the controller - treatment.setOutput(PortNumber.CONTROLLER); - FlowRule rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(FILTER_TABLE_CONTROLLER_PRIORITY) - .fromApp(applicationId) - .makePermanent() - .forTable(FILTER_TABLE).build(); - ops = install ? ops.add(rule) : ops.remove(rule); - } else { - log.warn("Driver does not currently process filtering condition" - + " of type: {}", c.type()); - fail(filt, ObjectiveError.UNSUPPORTED); - } - } - - // apply filtering flow rules - flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - pass(filt); - log.info("Applied filtering rules"); - } - - @Override - public void onError(FlowRuleOperations ops) { - fail(filt, ObjectiveError.FLOWINSTALLATIONFAILED); - log.info("Failed to apply filtering rules"); - } - })); - } - - 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); - } - } - - private void initializePipeline() { - // CENTEC_V350: PORT_VLAN_TABLE->FILTER_TABLE->MAC_TABLE(TMAC)->ROUTE_TABLE. - processPortVlanTable(true); - processFilterTable(true); - } - - private void processPortVlanTable(boolean install) { - // By default the packet are dropped, need install port+vlan by some ways. - - // XXX can we add table-miss-entry to drop? Code says drops by default - // XXX TTP description says default goes to table1. - // It also says that match is only on vlan -- not port-vlan -- which one is true? - } - - private void processFilterTable(boolean install) { - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); - TrafficTreatment.Builder treatment = DefaultTrafficTreatment - .builder(); - FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); - FlowRule rule; - - // Punt ARP packets to controller by default. - selector.matchEthType(Ethernet.TYPE_ARP); - treatment.punt(); - rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(FILTER_TABLE_CONTROLLER_PRIORITY) - .fromApp(appId) - .makePermanent() - .forTable(FILTER_TABLE).build(); - ops = install ? ops.add(rule) : ops.remove(rule); - - // Punt BGP packets to controller directly. - selector = DefaultTrafficSelector.builder(); - treatment = DefaultTrafficTreatment.builder(); - selector.matchEthType(Ethernet.TYPE_IPV4) - .matchIPProtocol(IPv4.PROTOCOL_TCP) - .matchTcpSrc(TpPort.tpPort(BGP_PORT)); - treatment.punt(); - rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withPriority(FILTER_TABLE_HIGHEST_PRIORITY) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .fromApp(appId) - .makePermanent() - .forTable(FILTER_TABLE).build(); - ops = install ? ops.add(rule) : ops.remove(rule); - - selector = DefaultTrafficSelector.builder(); - treatment = DefaultTrafficTreatment.builder(); - selector.matchEthType(Ethernet.TYPE_IPV4) - .matchIPProtocol(IPv4.PROTOCOL_TCP) - .matchTcpDst(TpPort.tpPort(BGP_PORT)); - treatment.punt(); - rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withPriority(FILTER_TABLE_HIGHEST_PRIORITY) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .fromApp(appId) - .makePermanent() - .forTable(FILTER_TABLE).build(); - - ops = install ? ops.add(rule) : ops.remove(rule); - - // Packet will be discard in PORT_VLAN table, no need to install rule in - // filter table. - - // XXX does not tell me if packets are going to be dropped by default in - // filter table or not? TTP says it will be dropped by default - - flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - log.info("Provisioned filter table"); - } - - @Override - public void onError(FlowRuleOperations ops) { - log.info("Failed to provision filter table"); - } - })); - } - - private class InnerGroupListener implements GroupListener { - @Override - public void event(GroupEvent event) { - if (event.type() == GroupEvent.Type.GROUP_ADDED) { - GroupKey key = event.subject().appCookie(); - - NextObjective obj = pendingGroups.getIfPresent(key); - if (obj != null) { - flowObjectiveStore.putNextGroup(obj.id(), new CentecV350Group(key)); - pass(obj); - pendingGroups.invalidate(key); - } - } - } - } - - - private class GroupChecker implements Runnable { - - @Override - public void run() { - Set<GroupKey> keys = pendingGroups.asMap().keySet().stream() - .filter(key -> groupService.getGroup(deviceId, key) != null) - .collect(Collectors.toSet()); - - keys.stream().forEach(key -> { - NextObjective obj = pendingGroups.getIfPresent(key); - if (obj == null) { - return; - } - pass(obj); - pendingGroups.invalidate(key); - log.info("Heard back from group service for group {}. " - + "Applying pending forwarding objectives", obj.id()); - flowObjectiveStore.putNextGroup(obj.id(), new CentecV350Group(key)); - }); - } - } - - private class CentecV350Group implements NextGroup { - - private final GroupKey key; - - public CentecV350Group(GroupKey key) { - this.key = key; - } - - @SuppressWarnings("unused") - public GroupKey key() { - return key; - } - - @Override - public byte[] data() { - return appKryo.serialize(key); - } - - } -} diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/CorsaPipeline.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/CorsaPipeline.java deleted file mode 100644 index ccf73079..00000000 --- a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/CorsaPipeline.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * 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 static org.slf4j.LoggerFactory.getLogger; - -import org.onlab.packet.Ethernet; -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.TrafficSelector; -import org.onosproject.net.flow.TrafficTreatment; -import org.slf4j.Logger; - -/** - * Driver for Corsa TTP. - * - */ -public class CorsaPipeline extends OVSCorsaPipeline { - - private final Logger log = getLogger(getClass()); - - @Override - protected void processVlanMplsTable(boolean install) { - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); - TrafficTreatment.Builder treatment = DefaultTrafficTreatment - .builder(); - FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); - FlowRule rule; - // corsa uses non-OF-standard way to match on presence of VLAN tags - selector.matchEthType(Ethernet.TYPE_VLAN); - 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(); - - ops = install ? ops.add(rule) : ops.remove(rule); - - flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - log.info("Provisioned vlan/mpls table"); - } - - @Override - public void onError(FlowRuleOperations ops) { - log.info( - "Failed to provision vlan/mpls table"); - } - })); - - } - -} diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/CpqdOFDPA2Pipeline.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/CpqdOFDPA2Pipeline.java deleted file mode 100644 index 02522cf1..00000000 --- a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/CpqdOFDPA2Pipeline.java +++ /dev/null @@ -1,497 +0,0 @@ -/* - * 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 static org.slf4j.LoggerFactory.getLogger; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Deque; -import java.util.List; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - -import org.onlab.packet.Ethernet; -import org.onlab.packet.VlanId; -import org.onosproject.core.ApplicationId; -import org.onosproject.net.Port; -import org.onosproject.net.PortNumber; -import org.onosproject.net.behaviour.NextGroup; -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.TrafficSelector; -import org.onosproject.net.flow.TrafficTreatment; -import org.onosproject.net.flow.criteria.Criteria; -import org.onosproject.net.flow.criteria.Criterion; -import org.onosproject.net.flow.criteria.EthCriterion; -import org.onosproject.net.flow.criteria.EthTypeCriterion; -import org.onosproject.net.flow.criteria.IPCriterion; -import org.onosproject.net.flow.criteria.MplsBosCriterion; -import org.onosproject.net.flow.criteria.MplsCriterion; -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.flowobjective.ForwardingObjective; -import org.onosproject.net.flowobjective.ObjectiveError; -import org.onosproject.net.group.Group; -import org.onosproject.net.group.GroupKey; -import org.slf4j.Logger; - - -/** - * Driver for software switch emulation of the OFDPA 2.0 pipeline. - * The software switch is the CPqD OF 1.3 switch. - */ -public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline { - - private final Logger log = getLogger(getClass()); - - /* - * Cpqd emulation does not require the non-OF standard rules for - * matching untagged packets. - * - * (non-Javadoc) - * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processVlanIdFilter - */ - - @Override - protected List<FlowRule> processVlanIdFilter(PortCriterion portCriterion, - VlanIdCriterion vidCriterion, - VlanId assignedVlan, - ApplicationId applicationId) { - List<FlowRule> rules = new ArrayList<FlowRule>(); - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); - selector.matchVlanId(vidCriterion.vlanId()); - treatment.transition(TMAC_TABLE); - - VlanId storeVlan = null; - if (vidCriterion.vlanId() == VlanId.NONE) { - // untagged packets are assigned vlans - treatment.pushVlan().setVlanId(assignedVlan); - storeVlan = assignedVlan; - } else { - storeVlan = vidCriterion.vlanId(); - } - - // ofdpa cannot match on ALL portnumber, so we need to use separate - // rules for each port. - List<PortNumber> portnums = new ArrayList<PortNumber>(); - if (portCriterion.port() == PortNumber.ALL) { - for (Port port : deviceService.getPorts(deviceId)) { - if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) { - portnums.add(port.number()); - } - } - } else { - portnums.add(portCriterion.port()); - } - - for (PortNumber pnum : portnums) { - // update storage - port2Vlan.put(pnum, storeVlan); - Set<PortNumber> vlanPorts = vlan2Port.get(storeVlan); - if (vlanPorts == null) { - vlanPorts = Collections.newSetFromMap( - new ConcurrentHashMap<PortNumber, Boolean>()); - vlanPorts.add(pnum); - vlan2Port.put(storeVlan, vlanPorts); - } else { - vlanPorts.add(pnum); - } - // create rest of flowrule - selector.matchInPort(pnum); - FlowRule rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(DEFAULT_PRIORITY) - .fromApp(applicationId) - .makePermanent() - .forTable(VLAN_TABLE).build(); - rules.add(rule); - } - return rules; - } - - /* - * Cpqd emulation does not handle vlan tags and mpls labels correctly. - * Workaround requires popping off the VLAN tags in the TMAC table. - * - * (non-Javadoc) - * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processEthDstFilter - */ - @Override - protected List<FlowRule> processEthDstFilter(PortCriterion portCriterion, - EthCriterion ethCriterion, - VlanIdCriterion vidCriterion, - VlanId assignedVlan, - ApplicationId applicationId) { - //handling untagged packets via assigned VLAN - if (vidCriterion.vlanId() == VlanId.NONE) { - vidCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan); - } - // ofdpa cannot match on ALL portnumber, so we need to use separate - // rules for each port. - List<PortNumber> portnums = new ArrayList<PortNumber>(); - if (portCriterion.port() == PortNumber.ALL) { - for (Port port : deviceService.getPorts(deviceId)) { - if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) { - portnums.add(port.number()); - } - } - } else { - portnums.add(portCriterion.port()); - } - - List<FlowRule> rules = new ArrayList<FlowRule>(); - for (PortNumber pnum : portnums) { - // for unicast IP packets - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); - selector.matchInPort(pnum); - selector.matchVlanId(vidCriterion.vlanId()); - selector.matchEthType(Ethernet.TYPE_IPV4); - selector.matchEthDst(ethCriterion.mac()); - /* - * Note: CpqD switches do not handle MPLS-related operation properly - * for a packet with VLAN tag. We pop VLAN here as a workaround. - * Side effect: HostService learns redundant hosts with same MAC but - * different VLAN. No known side effect on the network reachability. - */ - treatment.popVlan(); - treatment.transition(UNICAST_ROUTING_TABLE); - FlowRule rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(DEFAULT_PRIORITY) - .fromApp(applicationId) - .makePermanent() - .forTable(TMAC_TABLE).build(); - rules.add(rule); - //for MPLS packets - selector = DefaultTrafficSelector.builder(); - treatment = DefaultTrafficTreatment.builder(); - selector.matchInPort(pnum); - selector.matchVlanId(vidCriterion.vlanId()); - selector.matchEthType(Ethernet.MPLS_UNICAST); - selector.matchEthDst(ethCriterion.mac()); - // workaround here again - treatment.popVlan(); - treatment.transition(MPLS_TABLE_0); - rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(DEFAULT_PRIORITY) - .fromApp(applicationId) - .makePermanent() - .forTable(TMAC_TABLE).build(); - rules.add(rule); - } - return rules; - } - - /* - * Cpqd emulation allows MPLS ecmp. - * - * (non-Javadoc) - * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processEthTypeSpecific - */ - @Override - protected Collection<FlowRule> processEthTypeSpecific(ForwardingObjective fwd) { - TrafficSelector selector = fwd.selector(); - EthTypeCriterion ethType = - (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE); - if ((ethType == null) || - (ethType.ethType().toShort() != Ethernet.TYPE_IPV4) && - (ethType.ethType().toShort() != Ethernet.MPLS_UNICAST)) { - log.warn("processSpecific: Unsupported forwarding objective criteria" - + "ethType:{} in dev:{}", ethType, deviceId); - fail(fwd, ObjectiveError.UNSUPPORTED); - return Collections.emptySet(); - } - - int forTableId = -1; - TrafficSelector.Builder filteredSelector = DefaultTrafficSelector.builder(); - if (ethType.ethType().toShort() == Ethernet.TYPE_IPV4) { - filteredSelector.matchEthType(Ethernet.TYPE_IPV4) - .matchIPDst(((IPCriterion) - selector.getCriterion(Criterion.Type.IPV4_DST)).ip()); - forTableId = UNICAST_ROUTING_TABLE; - log.debug("processing IPv4 specific forwarding objective {} -> next:{}" - + " in dev:{}", fwd.id(), fwd.nextId(), deviceId); - } else { - filteredSelector - .matchEthType(Ethernet.MPLS_UNICAST) - .matchMplsLabel(((MplsCriterion) - selector.getCriterion(Criterion.Type.MPLS_LABEL)).label()); - MplsBosCriterion bos = (MplsBosCriterion) selector - .getCriterion(Criterion.Type.MPLS_BOS); - if (bos != null) { - filteredSelector.matchMplsBos(bos.mplsBos()); - } - forTableId = MPLS_TABLE_1; - log.debug("processing MPLS specific forwarding objective {} -> next:{}" - + " in dev {}", fwd.id(), fwd.nextId(), deviceId); - } - - TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder(); - if (fwd.treatment() != null) { - for (Instruction i : fwd.treatment().allInstructions()) { - tb.add(i); - } - } - - if (fwd.nextId() != null) { - NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId()); - List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data()); - // we only need the top level group's key to point the flow to it - Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst()); - if (group == null) { - log.warn("The group left!"); - fail(fwd, ObjectiveError.GROUPMISSING); - return Collections.emptySet(); - } - tb.deferred().group(group.id()); - } - tb.transition(ACL_TABLE); - FlowRule.Builder ruleBuilder = DefaultFlowRule.builder() - .fromApp(fwd.appId()) - .withPriority(fwd.priority()) - .forDevice(deviceId) - .withSelector(filteredSelector.build()) - .withTreatment(tb.build()) - .forTable(forTableId); - - if (fwd.permanent()) { - ruleBuilder.makePermanent(); - } else { - ruleBuilder.makeTemporary(fwd.timeout()); - } - - return Collections.singletonList(ruleBuilder.build()); - } - - @Override - protected void initializePipeline() { - processPortTable(); - // vlan table processing not required, as default is to drop packets - // which can be accomplished without a table-miss-entry. - processTmacTable(); - processIpTable(); - processMplsTable(); - processBridgingTable(); - processAclTable(); - } - - protected void processPortTable() { - FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); - treatment.transition(VLAN_TABLE); - FlowRule tmisse = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(LOWEST_PRIORITY) - .fromApp(driverId) - .makePermanent() - .forTable(PORT_TABLE).build(); - ops = ops.add(tmisse); - - flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - log.info("Initialized port table"); - } - - @Override - public void onError(FlowRuleOperations ops) { - log.info("Failed to initialize port table"); - } - })); - } - - protected void processTmacTable() { - //table miss entry - FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); - selector = DefaultTrafficSelector.builder(); - treatment = DefaultTrafficTreatment.builder(); - treatment.transition(BRIDGING_TABLE); - FlowRule rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(LOWEST_PRIORITY) - .fromApp(driverId) - .makePermanent() - .forTable(TMAC_TABLE).build(); - ops = ops.add(rule); - flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - log.info("Initialized tmac table"); - } - - @Override - public void onError(FlowRuleOperations ops) { - log.info("Failed to initialize tmac table"); - } - })); - } - - protected void processIpTable() { - //table miss entry - FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); - selector = DefaultTrafficSelector.builder(); - treatment = DefaultTrafficTreatment.builder(); - treatment.deferred().setOutput(PortNumber.CONTROLLER); - treatment.transition(ACL_TABLE); - FlowRule rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(LOWEST_PRIORITY) - .fromApp(driverId) - .makePermanent() - .forTable(UNICAST_ROUTING_TABLE).build(); - ops = ops.add(rule); - flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - log.info("Initialized IP table"); - } - - @Override - public void onError(FlowRuleOperations ops) { - log.info("Failed to initialize unicast IP table"); - } - })); - } - - protected void processMplsTable() { - //table miss entry - FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); - selector = DefaultTrafficSelector.builder(); - treatment = DefaultTrafficTreatment.builder(); - treatment.transition(MPLS_TABLE_1); - FlowRule rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(LOWEST_PRIORITY) - .fromApp(driverId) - .makePermanent() - .forTable(MPLS_TABLE_0).build(); - ops = ops.add(rule); - - treatment.transition(ACL_TABLE); - rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(LOWEST_PRIORITY) - .fromApp(driverId) - .makePermanent() - .forTable(MPLS_TABLE_1).build(); - ops = ops.add(rule); - - flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - log.info("Initialized MPLS tables"); - } - - @Override - public void onError(FlowRuleOperations ops) { - log.info("Failed to initialize MPLS tables"); - } - })); - } - - private void processBridgingTable() { - //table miss entry - FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); - selector = DefaultTrafficSelector.builder(); - treatment = DefaultTrafficTreatment.builder(); - treatment.transition(ACL_TABLE); - FlowRule rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(LOWEST_PRIORITY) - .fromApp(driverId) - .makePermanent() - .forTable(BRIDGING_TABLE).build(); - ops = ops.add(rule); - flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - log.info("Initialized Bridging table"); - } - - @Override - public void onError(FlowRuleOperations ops) { - log.info("Failed to initialize Bridging table"); - } - })); - } - - protected void processAclTable() { - //table miss entry - catch all to executed action-set - FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); - selector = DefaultTrafficSelector.builder(); - treatment = DefaultTrafficTreatment.builder(); - FlowRule rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(LOWEST_PRIORITY) - .fromApp(driverId) - .makePermanent() - .forTable(ACL_TABLE).build(); - ops = ops.add(rule); - flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - log.info("Initialized Acl table"); - } - - @Override - public void onError(FlowRuleOperations ops) { - log.info("Failed to initialize Acl table"); - } - })); - } - -} diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/DefaultSingleTablePipeline.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/DefaultSingleTablePipeline.java deleted file mode 100644 index d42650f5..00000000 --- a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/DefaultSingleTablePipeline.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * 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.onosproject.net.DeviceId; -import org.onosproject.net.behaviour.Pipeliner; -import org.onosproject.net.behaviour.PipelinerContext; -import org.onosproject.net.driver.AbstractHandlerBehaviour; -import org.onosproject.net.flow.DefaultFlowRule; -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.instructions.Instructions; -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.slf4j.Logger; - -import static org.slf4j.LoggerFactory.getLogger; - -/** - * Simple single table pipeline abstraction. - */ -public class DefaultSingleTablePipeline extends AbstractHandlerBehaviour implements Pipeliner { - - private final Logger log = getLogger(getClass()); - - private ServiceDirectory serviceDirectory; - private FlowRuleService flowRuleService; - private DeviceId deviceId; - - @Override - public void init(DeviceId deviceId, PipelinerContext context) { - this.serviceDirectory = context.directory(); - this.deviceId = deviceId; - - flowRuleService = serviceDirectory.get(FlowRuleService.class); - } - - @Override - public void filter(FilteringObjective filter) {} - - @Override - public void forward(ForwardingObjective fwd) { - FlowRuleOperations.Builder flowBuilder = FlowRuleOperations.builder(); - - if (fwd.flag() != ForwardingObjective.Flag.VERSATILE) { - throw new UnsupportedOperationException( - "Only VERSATILE is supported."); - } - - TrafficSelector selector = fwd.selector(); - TrafficTreatment treatment = fwd.treatment(); - if ((fwd.treatment().deferred().size() == 0) && - (fwd.treatment().immediate().size() == 0) && - (fwd.treatment().tableTransition() == null) && - (!fwd.treatment().clearedDeferred())) { - TrafficTreatment.Builder flowTreatment = DefaultTrafficTreatment.builder(); - flowTreatment.add(Instructions.createDrop()); - treatment = flowTreatment.build(); - } - - FlowRule.Builder ruleBuilder = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector) - .withTreatment(treatment) - .fromApp(fwd.appId()) - .withPriority(fwd.priority()); - - if (fwd.permanent()) { - ruleBuilder.makePermanent(); - } else { - ruleBuilder.makeTemporary(fwd.timeout()); - } - - - switch (fwd.op()) { - - case ADD: - flowBuilder.add(ruleBuilder.build()); - break; - case REMOVE: - flowBuilder.remove(ruleBuilder.build()); - break; - default: - log.warn("Unknown operation {}", fwd.op()); - } - - flowRuleService.apply(flowBuilder.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - if (fwd.context().isPresent()) { - fwd.context().get().onSuccess(fwd); - } - } - - @Override - public void onError(FlowRuleOperations ops) { - if (fwd.context().isPresent()) { - fwd.context().get().onError(fwd, ObjectiveError.FLOWINSTALLATIONFAILED); - } - } - })); - - } - - @Override - public void next(NextObjective nextObjective) {} - -} diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/OFDPA2Pipeline.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/OFDPA2Pipeline.java deleted file mode 100644 index 5f84b43a..00000000 --- a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/OFDPA2Pipeline.java +++ /dev/null @@ -1,1792 +0,0 @@ -/* - * 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 static org.onlab.util.Tools.groupedThreads; -import static org.slf4j.LoggerFactory.getLogger; - -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Deque; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.Collectors; - -import org.onlab.osgi.ServiceDirectory; -import org.onlab.packet.Ethernet; -import org.onlab.packet.MacAddress; -import org.onlab.packet.MplsLabel; -import org.onlab.packet.VlanId; -import org.onlab.util.KryoNamespace; -import org.onosproject.core.ApplicationId; -import org.onosproject.core.CoreService; -import org.onosproject.core.DefaultGroupId; -import org.onosproject.net.DeviceId; -import org.onosproject.net.Port; -import org.onosproject.net.PortNumber; -import org.onosproject.net.behaviour.NextGroup; -import org.onosproject.net.behaviour.Pipeliner; -import org.onosproject.net.behaviour.PipelinerContext; -import org.onosproject.net.device.DeviceService; -import org.onosproject.net.driver.AbstractHandlerBehaviour; -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.Criteria; -import org.onosproject.net.flow.criteria.Criterion; -import org.onosproject.net.flow.criteria.Criterion.Type; -import org.onosproject.net.flow.criteria.EthCriterion; -import org.onosproject.net.flow.criteria.EthTypeCriterion; -import org.onosproject.net.flow.criteria.IPCriterion; -import org.onosproject.net.flow.criteria.MplsBosCriterion; -import org.onosproject.net.flow.criteria.MplsCriterion; -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.Instructions.OutputInstruction; -import org.onosproject.net.flow.instructions.L2ModificationInstruction; -import org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType; -import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction; -import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModMplsLabelInstruction; -import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction; -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.onosproject.net.group.DefaultGroupBucket; -import org.onosproject.net.group.DefaultGroupDescription; -import org.onosproject.net.group.DefaultGroupKey; -import org.onosproject.net.group.Group; -import org.onosproject.net.group.GroupBucket; -import org.onosproject.net.group.GroupBuckets; -import org.onosproject.net.group.GroupDescription; -import org.onosproject.net.group.GroupEvent; -import org.onosproject.net.group.GroupKey; -import org.onosproject.net.group.GroupListener; -import org.onosproject.net.group.GroupService; -import org.onosproject.net.packet.PacketService; -import org.onosproject.store.serializers.KryoNamespaces; -import org.slf4j.Logger; - -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.RemovalCause; -import com.google.common.cache.RemovalNotification; - -/** - * Driver for Broadcom's OF-DPA v2.0 TTP. - * - */ -public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeliner { - - protected static final int PORT_TABLE = 0; - protected static final int VLAN_TABLE = 10; - protected static final int TMAC_TABLE = 20; - protected static final int UNICAST_ROUTING_TABLE = 30; - protected static final int MULTICAST_ROUTING_TABLE = 40; - protected static final int MPLS_TABLE_0 = 23; - protected static final int MPLS_TABLE_1 = 24; - protected static final int BRIDGING_TABLE = 50; - protected static final int ACL_TABLE = 60; - protected static final int MAC_LEARNING_TABLE = 254; - protected static final long OFPP_MAX = 0xffffff00L; - - private static final int HIGHEST_PRIORITY = 0xffff; - protected static final int DEFAULT_PRIORITY = 0x8000; - protected static final int LOWEST_PRIORITY = 0x0; - - /* - * OFDPA requires group-id's to have a certain form. - * L2 Interface Groups have <4bits-0><12bits-vlanid><16bits-portid> - * L3 Unicast Groups have <4bits-2><28bits-index> - * MPLS Interface Groups have <4bits-9><4bits:0><24bits-index> - * L3 ECMP Groups have <4bits-7><28bits-index> - * L2 Flood Groups have <4bits-4><12bits-vlanid><16bits-index> - * L3 VPN Groups have <4bits-9><4bits-2><24bits-index> - */ - private static final int L2INTERFACEMASK = 0x0; - private static final int L3UNICASTMASK = 0x20000000; - private static final int MPLSINTERFACEMASK = 0x90000000; - private static final int L3ECMPMASK = 0x70000000; - private static final int L2FLOODMASK = 0x40000000; - private static final int L3VPNMASK = 0x92000000; - - private final Logger log = getLogger(getClass()); - private ServiceDirectory serviceDirectory; - protected FlowRuleService flowRuleService; - private CoreService coreService; - protected GroupService groupService; - protected FlowObjectiveStore flowObjectiveStore; - protected DeviceId deviceId; - protected ApplicationId driverId; - protected PacketService packetService; - protected DeviceService deviceService; - protected KryoNamespace appKryo = new KryoNamespace.Builder() - .register(KryoNamespaces.API) - .register(GroupKey.class) - .register(DefaultGroupKey.class) - .register(OfdpaNextGroup.class) - .register(byte[].class) - .register(ArrayDeque.class) - .build(); - - private Cache<GroupKey, List<OfdpaNextGroup>> pendingNextObjectives; - private ConcurrentHashMap<GroupKey, Set<GroupChainElem>> pendingGroups; - - private ScheduledExecutorService groupChecker = - Executors.newScheduledThreadPool(2, groupedThreads("onos/pipeliner", - "ofdpa2-%d")); - private Set<IPCriterion> sentIpFilters = Collections.newSetFromMap( - new ConcurrentHashMap<IPCriterion, Boolean>()); - - // local stores for port-vlan mapping - Map<PortNumber, VlanId> port2Vlan = new ConcurrentHashMap<PortNumber, VlanId>(); - Map<VlanId, Set<PortNumber>> vlan2Port = new ConcurrentHashMap<VlanId, - Set<PortNumber>>(); - - // index number for group creation - AtomicInteger l3vpnindex = new AtomicInteger(0); - - - @Override - public void init(DeviceId deviceId, PipelinerContext context) { - this.serviceDirectory = context.directory(); - this.deviceId = deviceId; - - pendingNextObjectives = CacheBuilder.newBuilder() - .expireAfterWrite(20, TimeUnit.SECONDS) - .removalListener(( - RemovalNotification<GroupKey, List<OfdpaNextGroup>> notification) -> { - if (notification.getCause() == RemovalCause.EXPIRED) { - notification.getValue().forEach(ofdpaNextGrp -> - fail(ofdpaNextGrp.nextObj, - ObjectiveError.GROUPINSTALLATIONFAILED)); - - } - }).build(); - - groupChecker.scheduleAtFixedRate(new GroupChecker(), 0, 500, TimeUnit.MILLISECONDS); - pendingGroups = new ConcurrentHashMap<GroupKey, Set<GroupChainElem>>(); - - coreService = serviceDirectory.get(CoreService.class); - flowRuleService = serviceDirectory.get(FlowRuleService.class); - groupService = serviceDirectory.get(GroupService.class); - flowObjectiveStore = context.store(); - packetService = serviceDirectory.get(PacketService.class); - deviceService = serviceDirectory.get(DeviceService.class); - groupService.addListener(new InnerGroupListener()); - - driverId = coreService.registerApplication( - "org.onosproject.driver.OFDPA2Pipeline"); - - // OF-DPA does not require initializing the pipeline as it puts default - // rules automatically in the hardware. However emulation of OFDPA in - // software switches does require table-miss-entries. - initializePipeline(); - - } - - protected void initializePipeline() { - - } - - ////////////////////////////////////// - // Flow Objectives - ////////////////////////////////////// - - @Override - public void filter(FilteringObjective filteringObjective) { - if (filteringObjective.type() == FilteringObjective.Type.PERMIT) { - processFilter(filteringObjective, - filteringObjective.op() == Objective.Operation.ADD, - filteringObjective.appId()); - } else { - // Note that packets that don't match the PERMIT filter are - // automatically denied. The DENY filter is used to deny packets - // that are otherwise permitted by the PERMIT filter. - // Use ACL table flow rules here for DENY filtering objectives - log.debug("filter objective other than PERMIT currently not supported"); - fail(filteringObjective, ObjectiveError.UNSUPPORTED); - } - } - - @Override - public void forward(ForwardingObjective fwd) { - Collection<FlowRule> rules; - FlowRuleOperations.Builder flowOpsBuilder = FlowRuleOperations.builder(); - - rules = processForward(fwd); - switch (fwd.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(fwd, ObjectiveError.UNKNOWN); - log.warn("Unknown forwarding type {}", fwd.op()); - } - - flowRuleService.apply(flowOpsBuilder.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - pass(fwd); - } - - @Override - public void onError(FlowRuleOperations ops) { - fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED); - } - })); - } - - @Override - public void next(NextObjective nextObjective) { - NextGroup nextGroup = flowObjectiveStore.getNextGroup(nextObjective.id()); - switch (nextObjective.op()) { - case ADD: - if (nextGroup != null) { - log.warn("Cannot add next {} that already exists in device {}", - nextObjective.id(), deviceId); - return; - } - log.debug("Processing NextObjective id{} in dev{} - add group", - nextObjective.id(), deviceId); - addGroup(nextObjective); - break; - case ADD_TO_EXISTING: - if (nextGroup != null) { - log.debug("Processing NextObjective id{} in dev{} - add bucket", - nextObjective.id(), deviceId); - addBucketToGroup(nextObjective); - } else { - // it is possible that group-chain has not been fully created yet - waitToAddBucketToGroup(nextObjective); - } - break; - case REMOVE: - if (nextGroup == null) { - log.warn("Cannot remove next {} that does not exist in device {}", - nextObjective.id(), deviceId); - return; - } - log.debug("Processing NextObjective id{} in dev{} - remove group", - nextObjective.id(), deviceId); - removeGroup(nextObjective); - break; - case REMOVE_FROM_EXISTING: - if (nextGroup == null) { - log.warn("Cannot remove from next {} that does not exist in device {}", - nextObjective.id(), deviceId); - return; - } - log.debug("Processing NextObjective id{} in dev{} - remove bucket", - nextObjective.id(), deviceId); - removeBucketFromGroup(nextObjective); - break; - default: - log.warn("Unsupported operation {}", nextObjective.op()); - } - } - - ////////////////////////////////////// - // Flow handling - ////////////////////////////////////// - - /** - * As per OFDPA 2.0 TTP, filtering of VLAN ids, MAC addresses (for routing) - * and IP addresses configured on switch ports happen in different tables. - * Note that IP filtering rules need to be added to the ACL table, as there - * is no mechanism to send to controller via IP table. - * - * @param filt the filtering objective - * @param install indicates whether to add or remove the objective - * @param applicationId the application that sent this objective - */ - private void processFilter(FilteringObjective filt, - boolean install, ApplicationId applicationId) { - // This driver only processes filtering criteria defined with switch - // ports as the key - PortCriterion portCriterion = null; - EthCriterion ethCriterion = null; - VlanIdCriterion vidCriterion = null; - Collection<IPCriterion> ips = new ArrayList<IPCriterion>(); - if (!filt.key().equals(Criteria.dummy()) && - filt.key().type() == Criterion.Type.IN_PORT) { - portCriterion = (PortCriterion) filt.key(); - } else { - log.warn("No key defined in filtering objective from app: {}. Not" - + "processing filtering objective", applicationId); - fail(filt, ObjectiveError.UNKNOWN); - return; - } - // convert filtering conditions for switch-intfs into flowrules - FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); - for (Criterion criterion : filt.conditions()) { - if (criterion.type() == Criterion.Type.ETH_DST) { - ethCriterion = (EthCriterion) criterion; - } else if (criterion.type() == Criterion.Type.VLAN_VID) { - vidCriterion = (VlanIdCriterion) criterion; - } else if (criterion.type() == Criterion.Type.IPV4_DST) { - ips.add((IPCriterion) criterion); - } else { - log.error("Unsupported filter {}", criterion); - fail(filt, ObjectiveError.UNSUPPORTED); - return; - } - } - - VlanId assignedVlan = null; - if (vidCriterion != null && vidCriterion.vlanId() == VlanId.NONE) { - // untagged packets are assigned vlans in OF-DPA - if (filt.meta() == null) { - log.error("Missing metadata in filtering objective required " - + "for vlan assignment in dev {}", deviceId); - fail(filt, ObjectiveError.BADPARAMS); - return; - } - for (Instruction i : filt.meta().allInstructions()) { - if (i instanceof ModVlanIdInstruction) { - assignedVlan = ((ModVlanIdInstruction) i).vlanId(); - } - } - if (assignedVlan == null) { - log.error("Driver requires an assigned vlan-id to tag incoming " - + "untagged packets. Not processing vlan filters on " - + "device {}", deviceId); - fail(filt, ObjectiveError.BADPARAMS); - return; - } - } - - if (ethCriterion == null) { - log.debug("filtering objective missing dstMac, cannot program TMAC table"); - } else { - for (FlowRule tmacRule : processEthDstFilter(portCriterion, ethCriterion, - vidCriterion, assignedVlan, - applicationId)) { - log.debug("adding MAC filtering rules in TMAC table: {} for dev: {}", - tmacRule, deviceId); - ops = install ? ops.add(tmacRule) : ops.remove(tmacRule); - } - } - - if (ethCriterion == null || vidCriterion == null) { - log.debug("filtering objective missing dstMac or vlan, cannot program" - + "Vlan Table"); - } else { - for (FlowRule vlanRule : processVlanIdFilter(portCriterion, vidCriterion, - assignedVlan, - applicationId)) { - log.debug("adding VLAN filtering rule in VLAN table: {} for dev: {}", - vlanRule, deviceId); - ops = install ? ops.add(vlanRule) : ops.remove(vlanRule); - } - } - - for (IPCriterion ipaddr : ips) { - // since we ignore port information for IP rules, and the same (gateway) IP - // can be configured on multiple ports, we make sure that we send - // only a single rule to the switch. - if (!sentIpFilters.contains(ipaddr)) { - sentIpFilters.add(ipaddr); - log.debug("adding IP filtering rules in ACL table {} for dev: {}", - ipaddr, deviceId); - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); - selector.matchEthType(Ethernet.TYPE_IPV4); - selector.matchIPDst(ipaddr.ip()); - treatment.setOutput(PortNumber.CONTROLLER); - FlowRule rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(HIGHEST_PRIORITY) - .fromApp(applicationId) - .makePermanent() - .forTable(ACL_TABLE).build(); - ops = install ? ops.add(rule) : ops.remove(rule); - } - } - - // apply filtering flow rules - flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - log.info("Applied {} filtering rules in device {}", - ops.stages().get(0).size(), deviceId); - pass(filt); - } - - @Override - public void onError(FlowRuleOperations ops) { - log.info("Failed to apply all filtering rules in dev {}", deviceId); - fail(filt, ObjectiveError.FLOWINSTALLATIONFAILED); - } - })); - - } - - /** - * Allows untagged packets into pipeline by assigning a vlan id. - * Vlan assignment is done by the application. - * Allows tagged packets into pipeline as per configured port-vlan info. - * - * @param portCriterion port on device for which this filter is programmed - * @param vidCriterion vlan assigned to port, or NONE for untagged - * @param assignedVlan assigned vlan-id for untagged packets - * @param applicationId for application programming this filter - * @return list of FlowRule for port-vlan filters - */ - protected List<FlowRule> processVlanIdFilter(PortCriterion portCriterion, - VlanIdCriterion vidCriterion, - VlanId assignedVlan, - ApplicationId applicationId) { - List<FlowRule> rules = new ArrayList<FlowRule>(); - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); - selector.matchVlanId(vidCriterion.vlanId()); - treatment.transition(TMAC_TABLE); - - VlanId storeVlan = null; - if (vidCriterion.vlanId() == VlanId.NONE) { - // untagged packets are assigned vlans - treatment.pushVlan().setVlanId(assignedVlan); - // XXX ofdpa will require an additional vlan match on the assigned vlan - // and it may not require the push. This is not in compliance with OF - // standard. Waiting on what the exact flows are going to look like. - storeVlan = assignedVlan; - } else { - storeVlan = vidCriterion.vlanId(); - } - - // ofdpa cannot match on ALL portnumber, so we need to use separate - // rules for each port. - List<PortNumber> portnums = new ArrayList<PortNumber>(); - if (portCriterion.port() == PortNumber.ALL) { - for (Port port : deviceService.getPorts(deviceId)) { - if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) { - portnums.add(port.number()); - } - } - } else { - portnums.add(portCriterion.port()); - } - - for (PortNumber pnum : portnums) { - // update storage - port2Vlan.put(pnum, storeVlan); - Set<PortNumber> vlanPorts = vlan2Port.get(storeVlan); - if (vlanPorts == null) { - vlanPorts = Collections.newSetFromMap( - new ConcurrentHashMap<PortNumber, Boolean>()); - vlanPorts.add(pnum); - vlan2Port.put(storeVlan, vlanPorts); - } else { - vlanPorts.add(pnum); - } - // create rest of flowrule - selector.matchInPort(pnum); - FlowRule rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(DEFAULT_PRIORITY) - .fromApp(applicationId) - .makePermanent() - .forTable(VLAN_TABLE).build(); - rules.add(rule); - } - return rules; - } - - /** - * Allows routed packets with correct destination MAC to be directed - * to unicast-IP routing table or MPLS forwarding table. - * - * @param portCriterion port on device for which this filter is programmed - * @param ethCriterion dstMac of device for which is filter is programmed - * @param vidCriterion vlan assigned to port, or NONE for untagged - * @param assignedVlan assigned vlan-id for untagged packets - * @param applicationId for application programming this filter - * @return list of FlowRule for port-vlan filters - - */ - protected List<FlowRule> processEthDstFilter(PortCriterion portCriterion, - EthCriterion ethCriterion, - VlanIdCriterion vidCriterion, - VlanId assignedVlan, - ApplicationId applicationId) { - //handling untagged packets via assigned VLAN - if (vidCriterion.vlanId() == VlanId.NONE) { - vidCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan); - } - // ofdpa cannot match on ALL portnumber, so we need to use separate - // rules for each port. - List<PortNumber> portnums = new ArrayList<PortNumber>(); - if (portCriterion.port() == PortNumber.ALL) { - for (Port port : deviceService.getPorts(deviceId)) { - if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) { - portnums.add(port.number()); - } - } - } else { - portnums.add(portCriterion.port()); - } - - List<FlowRule> rules = new ArrayList<FlowRule>(); - for (PortNumber pnum : portnums) { - // for unicast IP packets - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); - selector.matchInPort(pnum); - selector.matchVlanId(vidCriterion.vlanId()); - selector.matchEthType(Ethernet.TYPE_IPV4); - selector.matchEthDst(ethCriterion.mac()); - treatment.transition(UNICAST_ROUTING_TABLE); - FlowRule rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(DEFAULT_PRIORITY) - .fromApp(applicationId) - .makePermanent() - .forTable(TMAC_TABLE).build(); - rules.add(rule); - //for MPLS packets - selector = DefaultTrafficSelector.builder(); - treatment = DefaultTrafficTreatment.builder(); - selector.matchInPort(pnum); - selector.matchVlanId(vidCriterion.vlanId()); - selector.matchEthType(Ethernet.MPLS_UNICAST); - selector.matchEthDst(ethCriterion.mac()); - treatment.transition(MPLS_TABLE_0); - rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(DEFAULT_PRIORITY) - .fromApp(applicationId) - .makePermanent() - .forTable(TMAC_TABLE).build(); - rules.add(rule); - } - return rules; - } - - private Collection<FlowRule> processForward(ForwardingObjective fwd) { - switch (fwd.flag()) { - case SPECIFIC: - return processSpecific(fwd); - case VERSATILE: - return processVersatile(fwd); - default: - fail(fwd, ObjectiveError.UNKNOWN); - log.warn("Unknown forwarding flag {}", fwd.flag()); - } - return Collections.emptySet(); - } - - /** - * In the OF-DPA 2.0 pipeline, versatile forwarding objectives go to the - * ACL table. - * @param fwd the forwarding objective of type 'versatile' - * @return a collection of flow rules to be sent to the switch. An empty - * collection may be returned if there is a problem in processing - * the flow rule - */ - private Collection<FlowRule> processVersatile(ForwardingObjective fwd) { - log.info("Processing versatile forwarding objective"); - TrafficSelector selector = fwd.selector(); - - EthTypeCriterion ethType = - (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE); - if (ethType == null) { - log.error("Versatile forwarding objective must include ethType"); - fail(fwd, ObjectiveError.BADPARAMS); - return Collections.emptySet(); - } - if (fwd.nextId() == null && fwd.treatment() == null) { - log.error("Forwarding objective {} from {} must contain " - + "nextId or Treatment", fwd.selector(), fwd.appId()); - return Collections.emptySet(); - } - // XXX driver does not currently do type checking as per Tables 65-67 in - // OFDPA 2.0 spec. The only allowed treatment is a punt to the controller. - if (fwd.treatment() != null && - fwd.treatment().allInstructions().size() == 1 && - fwd.treatment().allInstructions().get(0).type() == Instruction.Type.OUTPUT) { - OutputInstruction o = (OutputInstruction) fwd.treatment().allInstructions().get(0); - if (o.port() == PortNumber.CONTROLLER) { - FlowRule.Builder ruleBuilder = DefaultFlowRule.builder() - .fromApp(fwd.appId()) - .withPriority(fwd.priority()) - .forDevice(deviceId) - .withSelector(fwd.selector()) - .withTreatment(fwd.treatment()) - .makePermanent() - .forTable(ACL_TABLE); - return Collections.singletonList(ruleBuilder.build()); - } else { - log.warn("Only allowed treatments in versatile forwarding " - + "objectives are punts to the controller"); - return Collections.emptySet(); - } - } - - if (fwd.nextId() != null) { - // XXX overide case - log.warn("versatile objective --> next Id not yet implemeted"); - } - return Collections.emptySet(); - } - - /** - * In the OF-DPA 2.0 pipeline, specific forwarding refers to the IP table - * (unicast or multicast) or the L2 table (mac + vlan) or the MPLS table. - * - * @param fwd the forwarding objective of type 'specific' - * @return a collection of flow rules. Typically there will be only one - * for this type of forwarding objective. An empty set may be - * returned if there is an issue in processing the objective. - */ - protected Collection<FlowRule> processSpecific(ForwardingObjective fwd) { - log.trace("Processing specific fwd objective:{} in dev:{} with next:{}", - fwd.id(), deviceId, fwd.nextId()); - boolean isEthTypeObj = isSupportedEthTypeObjective(fwd); - boolean isEthDstObj = isSupportedEthDstObjective(fwd); - - if (isEthTypeObj) { - return processEthTypeSpecific(fwd); - } else if (isEthDstObj) { - return processEthDstSpecific(fwd); - } else { - log.warn("processSpecific: Unsupported forwarding objective " - + "criteria fwd:{} in dev:{}", fwd.nextId(), deviceId); - fail(fwd, ObjectiveError.UNSUPPORTED); - return Collections.emptySet(); - } - } - - private boolean isSupportedEthTypeObjective(ForwardingObjective fwd) { - TrafficSelector selector = fwd.selector(); - EthTypeCriterion ethType = (EthTypeCriterion) selector - .getCriterion(Criterion.Type.ETH_TYPE); - if ((ethType == null) || - ((ethType.ethType().toShort() != Ethernet.TYPE_IPV4) && - (ethType.ethType().toShort() != Ethernet.MPLS_UNICAST))) { - return false; - } - return true; - } - - private boolean isSupportedEthDstObjective(ForwardingObjective fwd) { - TrafficSelector selector = fwd.selector(); - EthCriterion ethDst = (EthCriterion) selector - .getCriterion(Criterion.Type.ETH_DST); - VlanIdCriterion vlanId = (VlanIdCriterion) selector - .getCriterion(Criterion.Type.VLAN_VID); - if (ethDst == null && vlanId == null) { - return false; - } - return true; - } - - /** - * Handles forwarding rules to the IP and MPLS tables. - * - * @param fwd the forwarding objective - * @return A collection of flow rules, or an empty set - */ - protected Collection<FlowRule> processEthTypeSpecific(ForwardingObjective fwd) { - TrafficSelector selector = fwd.selector(); - EthTypeCriterion ethType = - (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE); - - int forTableId = -1; - TrafficSelector.Builder filteredSelector = DefaultTrafficSelector.builder(); - if (ethType.ethType().toShort() == Ethernet.TYPE_IPV4) { - filteredSelector.matchEthType(Ethernet.TYPE_IPV4) - .matchIPDst(((IPCriterion) - selector.getCriterion(Criterion.Type.IPV4_DST)).ip()); - forTableId = UNICAST_ROUTING_TABLE; - log.debug("processing IPv4 specific forwarding objective {} -> next:{}" - + " in dev:{}", fwd.id(), fwd.nextId(), deviceId); - } else { - filteredSelector - .matchEthType(Ethernet.MPLS_UNICAST) - .matchMplsLabel(((MplsCriterion) - selector.getCriterion(Criterion.Type.MPLS_LABEL)).label()); - MplsBosCriterion bos = (MplsBosCriterion) selector - .getCriterion(Criterion.Type.MPLS_BOS); - if (bos != null) { - filteredSelector.matchMplsBos(bos.mplsBos()); - } - forTableId = MPLS_TABLE_1; - log.debug("processing MPLS specific forwarding objective {} -> next:{}" - + " in dev {}", fwd.id(), fwd.nextId(), deviceId); - } - - TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder(); - boolean popMpls = false; - if (fwd.treatment() != null) { - for (Instruction i : fwd.treatment().allInstructions()) { - tb.add(i); - if (i instanceof L2ModificationInstruction && - ((L2ModificationInstruction) i).subtype() == L2SubType.MPLS_POP) { - popMpls = true; - } - } - } - - if (fwd.nextId() != null) { - if (forTableId == MPLS_TABLE_1 && !popMpls) { - log.warn("SR CONTINUE case cannot be handled as MPLS ECMP " - + "is not implemented in OF-DPA yet. Aborting this flow " - + "in this device {}", deviceId); - // XXX We could convert to forwarding to a single-port, via a - // MPLS interface, or a MPLS SWAP (with-same) but that would - // have to be handled in the next-objective. Also the pop-mpls - // logic used here won't work in non-BoS case. - fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED); - return Collections.emptySet(); - } - - NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId()); - List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data()); - // we only need the top level group's key to point the flow to it - Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst()); - if (group == null) { - log.warn("Group with key:{} for next-id:{} not found in dev:{}", - gkeys.get(0).peekFirst(), fwd.nextId(), deviceId); - fail(fwd, ObjectiveError.GROUPMISSING); - return Collections.emptySet(); - } - tb.deferred().group(group.id()); - } - tb.transition(ACL_TABLE); - FlowRule.Builder ruleBuilder = DefaultFlowRule.builder() - .fromApp(fwd.appId()) - .withPriority(fwd.priority()) - .forDevice(deviceId) - .withSelector(filteredSelector.build()) - .withTreatment(tb.build()) - .forTable(forTableId); - - if (fwd.permanent()) { - ruleBuilder.makePermanent(); - } else { - ruleBuilder.makeTemporary(fwd.timeout()); - } - - return Collections.singletonList(ruleBuilder.build()); - } - - /** - * Handles forwarding rules to the L2 bridging table. Flow actions are not - * allowed in the bridging table - instead we use L2 Interface group or - * L2 flood group - * - * @param fwd the forwarding objective - * @return A collection of flow rules, or an empty set - */ - protected Collection<FlowRule> processEthDstSpecific(ForwardingObjective fwd) { - List<FlowRule> rules = new ArrayList<>(); - - // Build filtered selector - TrafficSelector selector = fwd.selector(); - EthCriterion ethCriterion = (EthCriterion) selector - .getCriterion(Criterion.Type.ETH_DST); - VlanIdCriterion vlanIdCriterion = (VlanIdCriterion) selector - .getCriterion(Criterion.Type.VLAN_VID); - - if (vlanIdCriterion == null) { - log.warn("Forwarding objective for bridging requires vlan. Not " - + "installing fwd:{} in dev:{}", fwd.id(), deviceId); - fail(fwd, ObjectiveError.BADPARAMS); - return Collections.emptySet(); - } - - TrafficSelector.Builder filteredSelectorBuilder = - DefaultTrafficSelector.builder(); - // Do not match MacAddress for subnet broadcast entry - if (!ethCriterion.mac().equals(MacAddress.NONE)) { - filteredSelectorBuilder.matchEthDst(ethCriterion.mac()); - log.debug("processing L2 forwarding objective:{} -> next:{} in dev:{}", - fwd.id(), fwd.nextId(), deviceId); - } else { - log.debug("processing L2 Broadcast forwarding objective:{} -> next:{} " - + "in dev:{} for vlan:{}", - fwd.id(), fwd.nextId(), deviceId, vlanIdCriterion.vlanId()); - } - filteredSelectorBuilder.matchVlanId(vlanIdCriterion.vlanId()); - TrafficSelector filteredSelector = filteredSelectorBuilder.build(); - - if (fwd.treatment() != null) { - log.warn("Ignoring traffic treatment in fwd rule {} meant for L2 table" - + "for dev:{}. Expecting only nextId", fwd.id(), deviceId); - } - - TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder(); - if (fwd.nextId() != null) { - NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId()); - if (next != null) { - List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data()); - // we only need the top level group's key to point the flow to it - Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst()); - if (group != null) { - treatmentBuilder.deferred().group(group.id()); - } else { - log.warn("Group with key:{} for next-id:{} not found in dev:{}", - gkeys.get(0).peekFirst(), fwd.nextId(), deviceId); - fail(fwd, ObjectiveError.GROUPMISSING); - return Collections.emptySet(); - } - } - } - treatmentBuilder.immediate().transition(ACL_TABLE); - TrafficTreatment filteredTreatment = treatmentBuilder.build(); - - // Build bridging table entries - FlowRule.Builder flowRuleBuilder = DefaultFlowRule.builder(); - flowRuleBuilder.fromApp(fwd.appId()) - .withPriority(fwd.priority()) - .forDevice(deviceId) - .withSelector(filteredSelector) - .withTreatment(filteredTreatment) - .forTable(BRIDGING_TABLE); - if (fwd.permanent()) { - flowRuleBuilder.makePermanent(); - } else { - flowRuleBuilder.makeTemporary(fwd.timeout()); - } - rules.add(flowRuleBuilder.build()); - return rules; - } - - private void pass(Objective obj) { - if (obj.context().isPresent()) { - obj.context().get().onSuccess(obj); - } - } - - protected void fail(Objective obj, ObjectiveError error) { - if (obj.context().isPresent()) { - obj.context().get().onError(obj, error); - } - } - - ////////////////////////////////////// - // Group handling - ////////////////////////////////////// - - private void addGroup(NextObjective nextObjective) { - switch (nextObjective.type()) { - case SIMPLE: - Collection<TrafficTreatment> treatments = nextObjective.next(); - if (treatments.size() != 1) { - log.error("Next Objectives of type Simple should only have a " - + "single Traffic Treatment. Next Objective Id:{}", - nextObjective.id()); - fail(nextObjective, ObjectiveError.BADPARAMS); - return; - } - processSimpleNextObjective(nextObjective); - break; - case BROADCAST: - processBroadcastNextObjective(nextObjective); - break; - case HASHED: - processHashedNextObjective(nextObjective); - break; - case FAILOVER: - fail(nextObjective, ObjectiveError.UNSUPPORTED); - log.warn("Unsupported next objective type {}", nextObjective.type()); - break; - default: - fail(nextObjective, ObjectiveError.UNKNOWN); - log.warn("Unknown next objective type {}", nextObjective.type()); - } - } - - /** - * As per the OFDPA 2.0 TTP, packets are sent out of ports by using - * a chain of groups. The simple Next Objective passed - * in by the application has to be broken up into a group chain - * comprising of an L3 Unicast Group that points to an L2 Interface - * Group which in-turn points to an output port. In some cases, the simple - * next Objective can just be an L2 interface without the need for chaining. - * - * @param nextObj the nextObjective of type SIMPLE - */ - private void processSimpleNextObjective(NextObjective nextObj) { - TrafficTreatment treatment = nextObj.next().iterator().next(); - // determine if plain L2 or L3->L2 - boolean plainL2 = true; - for (Instruction ins : treatment.allInstructions()) { - if (ins.type() == Instruction.Type.L2MODIFICATION) { - L2ModificationInstruction l2ins = (L2ModificationInstruction) ins; - if (l2ins.subtype() == L2SubType.ETH_DST || - l2ins.subtype() == L2SubType.ETH_SRC) { - plainL2 = false; - break; - } - } - } - - if (plainL2) { - createL2InterfaceGroup(nextObj); - return; - } - - // break up simple next objective to GroupChain objects - GroupInfo groupInfo = createL2L3Chain(treatment, nextObj.id(), - nextObj.appId(), false, - nextObj.meta()); - if (groupInfo == null) { - log.error("Could not process nextObj={} in dev:{}", nextObj.id(), deviceId); - return; - } - // create object for local and distributed storage - Deque<GroupKey> gkeyChain = new ArrayDeque<>(); - gkeyChain.addFirst(groupInfo.innerGrpDesc.appCookie()); - gkeyChain.addFirst(groupInfo.outerGrpDesc.appCookie()); - OfdpaNextGroup ofdpaGrp = new OfdpaNextGroup( - Collections.singletonList(gkeyChain), - nextObj); - - // store l3groupkey with the ofdpaNextGroup for the nextObjective that depends on it - updatePendingNextObjective(groupInfo.outerGrpDesc.appCookie(), ofdpaGrp); - - // now we are ready to send the l2 groupDescription (inner), as all the stores - // that will get async replies have been updated. By waiting to update - // the stores, we prevent nasty race conditions. - groupService.addGroup(groupInfo.innerGrpDesc); - } - - private void updatePendingNextObjective(GroupKey key, OfdpaNextGroup value) { - List<OfdpaNextGroup> nextList = new CopyOnWriteArrayList<OfdpaNextGroup>(); - nextList.add(value); - List<OfdpaNextGroup> ret = pendingNextObjectives.asMap() - .putIfAbsent(key, nextList); - if (ret != null) { - ret.add(value); - } - } - - /** - * Creates a simple L2 Interface Group. - * - * @param nextObj the next Objective - */ - private void createL2InterfaceGroup(NextObjective nextObj) { - // only allowed actions are vlan pop and outport - TrafficTreatment.Builder ttb = DefaultTrafficTreatment.builder(); - PortNumber portNum = null; - for (Instruction ins : nextObj.next().iterator().next().allInstructions()) { - if (ins.type() == Instruction.Type.L2MODIFICATION) { - L2ModificationInstruction l2ins = (L2ModificationInstruction) ins; - switch (l2ins.subtype()) { - case VLAN_POP: - ttb.add(l2ins); - break; - default: - break; - } - } else if (ins.type() == Instruction.Type.OUTPUT) { - portNum = ((OutputInstruction) ins).port(); - ttb.add(ins); - } else { - log.warn("Driver does not handle this type of TrafficTreatment" - + " instruction in simple nextObjectives: {}", ins.type()); - } - } - //use the vlanid associated with the port - VlanId vlanid = port2Vlan.get(portNum); - - if (vlanid == null && nextObj.meta() != null) { - // use metadata vlan info if available - Criterion vidCriterion = nextObj.meta().getCriterion(Type.VLAN_VID); - if (vidCriterion != null) { - vlanid = ((VlanIdCriterion) vidCriterion).vlanId(); - } - } - - if (vlanid == null) { - log.error("Driver cannot process an L2/L3 group chain without " - + "egress vlan information for dev: {} port:{}", - deviceId, portNum); - return; - } - - // assemble information for ofdpa l2interface group - Integer l2groupId = L2INTERFACEMASK | (vlanid.toShort() << 16) | (int) portNum.toLong(); - // a globally unique groupkey that is different for ports in the same devices - // but different for the same portnumber on different devices. Also different - // for the various group-types created out of the same next objective. - int l2gk = 0x0ffffff & (deviceId.hashCode() << 8 | (int) portNum.toLong()); - final GroupKey l2groupkey = new DefaultGroupKey(appKryo.serialize(l2gk)); - - // create group description for the l2interfacegroup - GroupBucket l2interfaceGroupBucket = - DefaultGroupBucket.createIndirectGroupBucket(ttb.build()); - GroupDescription l2groupDescription = - new DefaultGroupDescription( - deviceId, - GroupDescription.Type.INDIRECT, - new GroupBuckets(Collections.singletonList( - l2interfaceGroupBucket)), - l2groupkey, - l2groupId, - nextObj.appId()); - log.debug("Trying L2Interface: device:{} gid:{} gkey:{} nextId:{}", - deviceId, Integer.toHexString(l2groupId), - l2groupkey, nextObj.id()); - - // create object for local and distributed storage - Deque<GroupKey> singleKey = new ArrayDeque<>(); - singleKey.addFirst(l2groupkey); - OfdpaNextGroup ofdpaGrp = new OfdpaNextGroup( - Collections.singletonList(singleKey), - nextObj); - - // store l2groupkey for the nextObjective that depends on it - updatePendingNextObjective(l2groupkey, ofdpaGrp); - // send the group description to the group service - groupService.addGroup(l2groupDescription); - } - - /** - * Creates one of two possible group-chains from the treatment - * passed in. Depending on the MPLS boolean, this method either creates - * an L3Unicast Group --> L2Interface Group, if mpls is false; - * or MPLSInterface Group --> L2Interface Group, if mpls is true; - * The returned 'inner' group description is always the L2 Interface group. - * - * @param treatment that needs to be broken up to create the group chain - * @param nextId of the next objective that needs this group chain - * @param appId of the application that sent this next objective - * @param mpls determines if L3Unicast or MPLSInterface group is created - * @param meta metadata passed in by the application as part of the nextObjective - * @return GroupInfo containing the GroupDescription of the - * L2Interface group(inner) and the GroupDescription of the (outer) - * L3Unicast/MPLSInterface group. May return null if there is an - * error in processing the chain - */ - private GroupInfo createL2L3Chain(TrafficTreatment treatment, int nextId, - ApplicationId appId, boolean mpls, - TrafficSelector meta) { - // for the l2interface group, get vlan and port info - // for the outer group, get the src/dst mac, and vlan info - TrafficTreatment.Builder outerTtb = DefaultTrafficTreatment.builder(); - TrafficTreatment.Builder innerTtb = DefaultTrafficTreatment.builder(); - VlanId vlanid = null; - long portNum = 0; - boolean setVlan = false, popVlan = false; - for (Instruction ins : treatment.allInstructions()) { - if (ins.type() == Instruction.Type.L2MODIFICATION) { - L2ModificationInstruction l2ins = (L2ModificationInstruction) ins; - switch (l2ins.subtype()) { - case ETH_DST: - outerTtb.setEthDst(((ModEtherInstruction) l2ins).mac()); - break; - case ETH_SRC: - outerTtb.setEthSrc(((ModEtherInstruction) l2ins).mac()); - break; - case VLAN_ID: - vlanid = ((ModVlanIdInstruction) l2ins).vlanId(); - outerTtb.setVlanId(vlanid); - setVlan = true; - break; - case VLAN_POP: - innerTtb.popVlan(); - popVlan = true; - break; - case DEC_MPLS_TTL: - case MPLS_LABEL: - case MPLS_POP: - case MPLS_PUSH: - case VLAN_PCP: - case VLAN_PUSH: - default: - break; - } - } else if (ins.type() == Instruction.Type.OUTPUT) { - portNum = ((OutputInstruction) ins).port().toLong(); - innerTtb.add(ins); - } else { - log.warn("Driver does not handle this type of TrafficTreatment" - + " instruction in nextObjectives: {}", ins.type()); - } - } - - if (vlanid == null) { - //use the vlanid associated with the port - vlanid = port2Vlan.get(PortNumber.portNumber(portNum)); - } - - if (vlanid == null && meta != null) { - // use metadata if available - Criterion vidCriterion = meta.getCriterion(Type.VLAN_VID); - if (vidCriterion != null) { - vlanid = ((VlanIdCriterion) vidCriterion).vlanId(); - } - } - - if (vlanid == null) { - log.error("Driver cannot process an L2/L3 group chain without " - + "egress vlan information for dev: {} port:{}", - deviceId, portNum); - return null; - } - - if (!setVlan && !popVlan) { - // untagged outgoing port - TrafficTreatment.Builder temp = DefaultTrafficTreatment.builder(); - temp.popVlan(); - innerTtb.build().allInstructions().forEach(i -> temp.add(i)); - innerTtb = temp; - } - - // assemble information for ofdpa l2interface group - Integer l2groupId = L2INTERFACEMASK | (vlanid.toShort() << 16) | (int) portNum; - // a globally unique groupkey that is different for ports in the same devices - // but different for the same portnumber on different devices. Also different - // for the various group-types created out of the same next objective. - int l2gk = 0x0ffffff & (deviceId.hashCode() << 8 | (int) portNum); - final GroupKey l2groupkey = new DefaultGroupKey(appKryo.serialize(l2gk)); - - // assemble information for outer group - GroupDescription outerGrpDesc = null; - if (mpls) { - // outer group is MPLSInteface - Integer mplsgroupId = MPLSINTERFACEMASK | (int) portNum; - // using mplsinterfacemask in groupkey to differentiate from l2interface - int mplsgk = MPLSINTERFACEMASK | (0x0ffffff & (deviceId.hashCode() << 8 | (int) portNum)); - final GroupKey mplsgroupkey = new DefaultGroupKey(appKryo.serialize(mplsgk)); - outerTtb.group(new DefaultGroupId(l2groupId)); - // create the mpls-interface group description to wait for the - // l2 interface group to be processed - GroupBucket mplsinterfaceGroupBucket = - DefaultGroupBucket.createIndirectGroupBucket(outerTtb.build()); - outerGrpDesc = new DefaultGroupDescription( - deviceId, - GroupDescription.Type.INDIRECT, - new GroupBuckets(Collections.singletonList( - mplsinterfaceGroupBucket)), - mplsgroupkey, - mplsgroupId, - appId); - log.debug("Trying MPLS-Interface: device:{} gid:{} gkey:{} nextid:{}", - deviceId, Integer.toHexString(mplsgroupId), - mplsgroupkey, nextId); - } else { - // outer group is L3Unicast - Integer l3groupId = L3UNICASTMASK | (int) portNum; - int l3gk = L3UNICASTMASK | (0x0ffffff & (deviceId.hashCode() << 8 | (int) portNum)); - final GroupKey l3groupkey = new DefaultGroupKey(appKryo.serialize(l3gk)); - outerTtb.group(new DefaultGroupId(l2groupId)); - // create the l3unicast group description to wait for the - // l2 interface group to be processed - GroupBucket l3unicastGroupBucket = - DefaultGroupBucket.createIndirectGroupBucket(outerTtb.build()); - outerGrpDesc = new DefaultGroupDescription( - deviceId, - GroupDescription.Type.INDIRECT, - new GroupBuckets(Collections.singletonList( - l3unicastGroupBucket)), - l3groupkey, - l3groupId, - appId); - log.debug("Trying L3Unicast: device:{} gid:{} gkey:{} nextid:{}", - deviceId, Integer.toHexString(l3groupId), - l3groupkey, nextId); - } - - // store l2groupkey with the groupChainElem for the outer-group that depends on it - GroupChainElem gce = new GroupChainElem(outerGrpDesc, 1); - Set<GroupChainElem> gceSet = Collections.newSetFromMap( - new ConcurrentHashMap<GroupChainElem, Boolean>()); - gceSet.add(gce); - Set<GroupChainElem> retval = pendingGroups.putIfAbsent(l2groupkey, gceSet); - if (retval != null) { - retval.add(gce); - } - - // create group description for the inner l2interfacegroup - GroupBucket l2interfaceGroupBucket = - DefaultGroupBucket.createIndirectGroupBucket(innerTtb.build()); - GroupDescription l2groupDescription = - new DefaultGroupDescription( - deviceId, - GroupDescription.Type.INDIRECT, - new GroupBuckets(Collections.singletonList( - l2interfaceGroupBucket)), - l2groupkey, - l2groupId, - appId); - log.debug("Trying L2Interface: device:{} gid:{} gkey:{} nextId:{}", - deviceId, Integer.toHexString(l2groupId), - l2groupkey, nextId); - return new GroupInfo(l2groupDescription, outerGrpDesc); - - } - - /** - * As per the OFDPA 2.0 TTP, packets are sent out of ports by using - * a chain of groups. The broadcast Next Objective passed in by the application - * has to be broken up into a group chain comprising of an - * L2 Flood group whose buckets point to L2 Interface groups. - * - * @param nextObj the nextObjective of type BROADCAST - */ - private void processBroadcastNextObjective(NextObjective nextObj) { - // break up broadcast next objective to multiple groups - Collection<TrafficTreatment> buckets = nextObj.next(); - - // each treatment is converted to an L2 interface group - VlanId vlanid = null; - List<GroupDescription> l2interfaceGroupDescs = new ArrayList<>(); - List<Deque<GroupKey>> allGroupKeys = new ArrayList<>(); - for (TrafficTreatment treatment : buckets) { - TrafficTreatment.Builder newTreatment = DefaultTrafficTreatment.builder(); - PortNumber portNum = null; - // ensure that the only allowed treatments are pop-vlan and output - for (Instruction ins : treatment.allInstructions()) { - if (ins.type() == Instruction.Type.L2MODIFICATION) { - L2ModificationInstruction l2ins = (L2ModificationInstruction) ins; - switch (l2ins.subtype()) { - case VLAN_POP: - newTreatment.add(l2ins); - break; - default: - log.debug("action {} not permitted for broadcast nextObj", - l2ins.subtype()); - break; - } - } else if (ins.type() == Instruction.Type.OUTPUT) { - portNum = ((OutputInstruction) ins).port(); - newTreatment.add(ins); - } else { - log.debug("TrafficTreatment of type {} not permitted in " - + " broadcast nextObjective", ins.type()); - } - } - - // also ensure that all ports are in the same vlan - // XXX maybe HA issue here? - VlanId thisvlanid = port2Vlan.get(portNum); - if (vlanid == null) { - vlanid = thisvlanid; - } else { - if (!vlanid.equals(thisvlanid)) { - log.error("Driver requires all ports in a broadcast nextObj " - + "to be in the same vlan. Different vlans found " - + "{} and {}. Aborting group creation", vlanid, thisvlanid); - return; - } - } - - // assemble info for l2 interface group - int l2gk = 0x0ffffff & (deviceId.hashCode() << 8 | (int) portNum.toLong()); - final GroupKey l2groupkey = new DefaultGroupKey(appKryo.serialize(l2gk)); - Integer l2groupId = L2INTERFACEMASK | (vlanid.toShort() << 16) | - (int) portNum.toLong(); - GroupBucket l2interfaceGroupBucket = - DefaultGroupBucket.createIndirectGroupBucket(newTreatment.build()); - GroupDescription l2interfaceGroupDescription = - new DefaultGroupDescription( - deviceId, - GroupDescription.Type.INDIRECT, - new GroupBuckets(Collections.singletonList( - l2interfaceGroupBucket)), - l2groupkey, - l2groupId, - nextObj.appId()); - log.debug("Trying L2-Interface: device:{} gid:{} gkey:{} nextid:{}", - deviceId, Integer.toHexString(l2groupId), - l2groupkey, nextObj.id()); - - Deque<GroupKey> gkeyChain = new ArrayDeque<>(); - gkeyChain.addFirst(l2groupkey); - - // store the info needed to create this group - l2interfaceGroupDescs.add(l2interfaceGroupDescription); - allGroupKeys.add(gkeyChain); - } - - // assemble info for l2 flood group - Integer l2floodgroupId = L2FLOODMASK | (vlanid.toShort() << 16) | nextObj.id(); - int l2floodgk = L2FLOODMASK | nextObj.id() << 12; - final GroupKey l2floodgroupkey = new DefaultGroupKey(appKryo.serialize(l2floodgk)); - // collection of group buckets pointing to all the l2 interface groups - List<GroupBucket> l2floodBuckets = new ArrayList<>(); - for (GroupDescription l2intGrpDesc : l2interfaceGroupDescs) { - TrafficTreatment.Builder ttb = DefaultTrafficTreatment.builder(); - ttb.group(new DefaultGroupId(l2intGrpDesc.givenGroupId())); - GroupBucket abucket = DefaultGroupBucket.createAllGroupBucket(ttb.build()); - l2floodBuckets.add(abucket); - } - // create the l2flood group-description to wait for all the - // l2interface groups to be processed - GroupDescription l2floodGroupDescription = - new DefaultGroupDescription( - deviceId, - GroupDescription.Type.ALL, - new GroupBuckets(l2floodBuckets), - l2floodgroupkey, - l2floodgroupId, - nextObj.appId()); - GroupChainElem gce = new GroupChainElem(l2floodGroupDescription, - l2interfaceGroupDescs.size()); - log.debug("Trying L2-Flood: device:{} gid:{} gkey:{} nextid:{}", - deviceId, Integer.toHexString(l2floodgroupId), - l2floodgroupkey, nextObj.id()); - - // create objects for local and distributed storage - allGroupKeys.forEach(gkeyChain -> gkeyChain.addFirst(l2floodgroupkey)); - OfdpaNextGroup ofdpaGrp = new OfdpaNextGroup(allGroupKeys, nextObj); - - // store l2floodgroupkey with the ofdpaGroupChain for the nextObjective - // that depends on it - updatePendingNextObjective(l2floodgroupkey, ofdpaGrp); - - for (GroupDescription l2intGrpDesc : l2interfaceGroupDescs) { - // store all l2groupkeys with the groupChainElem for the l2floodgroup - // that depends on it - Set<GroupChainElem> gceSet = Collections.newSetFromMap( - new ConcurrentHashMap<GroupChainElem, Boolean>()); - gceSet.add(gce); - Set<GroupChainElem> retval = pendingGroups.putIfAbsent( - l2intGrpDesc.appCookie(), gceSet); - if (retval != null) { - retval.add(gce); - } - - // create and send groups for all l2 interface groups - groupService.addGroup(l2intGrpDesc); - } - } - - /** - * Utility class for moving group information around. - * - */ - private class GroupInfo { - private GroupDescription innerGrpDesc; - private GroupDescription outerGrpDesc; - - GroupInfo(GroupDescription innerGrpDesc, GroupDescription outerGrpDesc) { - this.innerGrpDesc = innerGrpDesc; - this.outerGrpDesc = outerGrpDesc; - } - } - - /** - * As per the OFDPA 2.0 TTP, packets are sent out of ports by using - * a chain of groups. The hashed Next Objective passed in by the application - * has to be broken up into a group chain comprising of an - * L3 ECMP group as the top level group. Buckets of this group can point - * to a variety of groups in a group chain, depending on the whether - * MPLS labels are being pushed or not. - * <p> - * NOTE: We do not create MPLS ECMP groups as they are unimplemented in - * OF-DPA 2.0 (even though it is in the spec). Therefore we do not - * check the nextObjective meta. - * - * @param nextObj the nextObjective of type HASHED - */ - private void processHashedNextObjective(NextObjective nextObj) { - // break up hashed next objective to multiple groups - Collection<TrafficTreatment> buckets = nextObj.next(); - - // storage for all group keys in the chain of groups created - List<Deque<GroupKey>> allGroupKeys = new ArrayList<>(); - List<GroupInfo> unsentGroups = new ArrayList<>(); - for (TrafficTreatment bucket : buckets) { - //figure out how many labels are pushed in each bucket - int labelsPushed = 0; - MplsLabel innermostLabel = null; - for (Instruction ins : bucket.allInstructions()) { - if (ins.type() == Instruction.Type.L2MODIFICATION) { - L2ModificationInstruction l2ins = (L2ModificationInstruction) ins; - if (l2ins.subtype() == L2SubType.MPLS_PUSH) { - labelsPushed++; - } - if (l2ins.subtype() == L2SubType.MPLS_LABEL) { - if (innermostLabel == null) { - innermostLabel = ((ModMplsLabelInstruction) l2ins).mplsLabel(); - } - } - } - } - - Deque<GroupKey> gkeyChain = new ArrayDeque<>(); - // XXX we only deal with 0 and 1 label push right now - if (labelsPushed == 0) { - GroupInfo nolabelGroupInfo = createL2L3Chain(bucket, nextObj.id(), - nextObj.appId(), false, - nextObj.meta()); - if (nolabelGroupInfo == null) { - log.error("Could not process nextObj={} in dev:{}", - nextObj.id(), deviceId); - return; - } - gkeyChain.addFirst(nolabelGroupInfo.innerGrpDesc.appCookie()); - gkeyChain.addFirst(nolabelGroupInfo.outerGrpDesc.appCookie()); - - // we can't send the inner group description yet, as we have to - // create the dependent ECMP group first. So we store.. - unsentGroups.add(nolabelGroupInfo); - - } else if (labelsPushed == 1) { - GroupInfo onelabelGroupInfo = createL2L3Chain(bucket, nextObj.id(), - nextObj.appId(), true, - nextObj.meta()); - if (onelabelGroupInfo == null) { - log.error("Could not process nextObj={} in dev:{}", - nextObj.id(), deviceId); - return; - } - // we need to add another group to this chain - the L3VPN group - TrafficTreatment.Builder l3vpnTtb = DefaultTrafficTreatment.builder(); - l3vpnTtb.pushMpls() - .setMpls(innermostLabel) - .setMplsBos(true) - .copyTtlOut() - .group(new DefaultGroupId( - onelabelGroupInfo.outerGrpDesc.givenGroupId())); - GroupBucket l3vpnGrpBkt = - DefaultGroupBucket.createIndirectGroupBucket(l3vpnTtb.build()); - int l3vpngroupId = L3VPNMASK | l3vpnindex.incrementAndGet(); - int l3vpngk = L3VPNMASK | nextObj.id() << 12 | l3vpnindex.get(); - GroupKey l3vpngroupkey = new DefaultGroupKey(appKryo.serialize(l3vpngk)); - GroupDescription l3vpnGroupDesc = - new DefaultGroupDescription( - deviceId, - GroupDescription.Type.INDIRECT, - new GroupBuckets(Collections.singletonList( - l3vpnGrpBkt)), - l3vpngroupkey, - l3vpngroupId, - nextObj.appId()); - GroupChainElem l3vpnGce = new GroupChainElem(l3vpnGroupDesc, 1); - Set<GroupChainElem> gceSet = Collections.newSetFromMap( - new ConcurrentHashMap<GroupChainElem, Boolean>()); - gceSet.add(l3vpnGce); - Set<GroupChainElem> retval = pendingGroups - .putIfAbsent(onelabelGroupInfo.outerGrpDesc.appCookie(), gceSet); - if (retval != null) { - retval.add(l3vpnGce); - } - - gkeyChain.addFirst(onelabelGroupInfo.innerGrpDesc.appCookie()); - gkeyChain.addFirst(onelabelGroupInfo.outerGrpDesc.appCookie()); - gkeyChain.addFirst(l3vpngroupkey); - - //now we can replace the outerGrpDesc with the one we just created - onelabelGroupInfo.outerGrpDesc = l3vpnGroupDesc; - - // we can't send the innermost group yet, as we have to create - // the dependent ECMP group first. So we store ... - unsentGroups.add(onelabelGroupInfo); - - log.debug("Trying L3VPN: device:{} gid:{} gkey:{} nextId:{}", - deviceId, Integer.toHexString(l3vpngroupId), - l3vpngroupkey, nextObj.id()); - - } else { - log.warn("Driver currently does not handle more than 1 MPLS " - + "labels. Not processing nextObjective {}", nextObj); - return; - } - - // all groups in this chain - allGroupKeys.add(gkeyChain); - } - - // now we can create the outermost L3 ECMP group - List<GroupBucket> l3ecmpGroupBuckets = new ArrayList<>(); - for (GroupInfo gi : unsentGroups) { - // create ECMP bucket to point to the outer group - TrafficTreatment.Builder ttb = DefaultTrafficTreatment.builder(); - ttb.group(new DefaultGroupId(gi.outerGrpDesc.givenGroupId())); - GroupBucket sbucket = DefaultGroupBucket - .createSelectGroupBucket(ttb.build()); - l3ecmpGroupBuckets.add(sbucket); - } - int l3ecmpGroupId = L3ECMPMASK | nextObj.id() << 12; - GroupKey l3ecmpGroupKey = new DefaultGroupKey(appKryo.serialize(l3ecmpGroupId)); - GroupDescription l3ecmpGroupDesc = - new DefaultGroupDescription( - deviceId, - GroupDescription.Type.SELECT, - new GroupBuckets(l3ecmpGroupBuckets), - l3ecmpGroupKey, - l3ecmpGroupId, - nextObj.appId()); - GroupChainElem l3ecmpGce = new GroupChainElem(l3ecmpGroupDesc, - l3ecmpGroupBuckets.size()); - - // create objects for local and distributed storage - allGroupKeys.forEach(gkeyChain -> gkeyChain.addFirst(l3ecmpGroupKey)); - OfdpaNextGroup ofdpaGrp = new OfdpaNextGroup(allGroupKeys, nextObj); - - // store l3ecmpGroupKey with the ofdpaGroupChain for the nextObjective - // that depends on it - updatePendingNextObjective(l3ecmpGroupKey, ofdpaGrp); - - log.debug("Trying L3ECMP: device:{} gid:{} gkey:{} nextId:{}", - deviceId, Integer.toHexString(l3ecmpGroupId), - l3ecmpGroupKey, nextObj.id()); - // finally we are ready to send the innermost groups - for (GroupInfo gi : unsentGroups) { - log.debug("Sending innermost group {} in group chain on device {} ", - Integer.toHexString(gi.innerGrpDesc.givenGroupId()), deviceId); - Set<GroupChainElem> gceSet = Collections.newSetFromMap( - new ConcurrentHashMap<GroupChainElem, Boolean>()); - gceSet.add(l3ecmpGce); - Set<GroupChainElem> retval = pendingGroups - .putIfAbsent(gi.outerGrpDesc.appCookie(), gceSet); - if (retval != null) { - retval.add(l3ecmpGce); - } - - groupService.addGroup(gi.innerGrpDesc); - } - - } - - private void addBucketToGroup(NextObjective nextObjective) { - // TODO Auto-generated method stub - } - - private void waitToAddBucketToGroup(NextObjective nextObjective) { - // TODO Auto-generated method stub - } - - private void removeBucketFromGroup(NextObjective nextObjective) { - // TODO Auto-generated method stub - } - - private void removeGroup(NextObjective nextObjective) { - // TODO Auto-generated method stub - } - - /** - * Processes next element of a group chain. Assumption is that if this - * group points to another group, the latter has already been created - * and this driver has received notification for it. A second assumption is - * that if there is another group waiting for this group then the appropriate - * stores already have the information to act upon the notification for the - * creating of this group. - * <p> - * The processing of the GroupChainElement depends on the number of groups - * this element is waiting on. For all group types other than SIMPLE, a - * GroupChainElement could be waiting on multiple groups. - * - * @param gce the group chain element to be processed next - */ - private void processGroupChain(GroupChainElem gce) { - int waitOnGroups = gce.decrementAndGetGroupsWaitedOn(); - if (waitOnGroups != 0) { - log.debug("GCE: {} not ready to be processed", gce); - return; - } - log.debug("GCE: {} ready to be processed", gce); - groupService.addGroup(gce.groupDescription); - } - - private class GroupChecker implements Runnable { - @Override - public void run() { - Set<GroupKey> keys = pendingGroups.keySet().stream() - .filter(key -> groupService.getGroup(deviceId, key) != null) - .collect(Collectors.toSet()); - Set<GroupKey> otherkeys = pendingNextObjectives.asMap().keySet().stream() - .filter(otherkey -> groupService.getGroup(deviceId, otherkey) != null) - .collect(Collectors.toSet()); - keys.addAll(otherkeys); - - keys.stream().forEach(key -> { - //first check for group chain - Set<GroupChainElem> gceSet = pendingGroups.remove(key); - if (gceSet != null) { - for (GroupChainElem gce : gceSet) { - log.info("Group service processed group key {} in device {}. " - + "Processing next group in group chain with group id {}", - key, deviceId, - Integer.toHexString(gce.groupDescription.givenGroupId())); - processGroupChain(gce); - } - } else { - List<OfdpaNextGroup> objList = pendingNextObjectives.getIfPresent(key); - if (objList != null) { - pendingNextObjectives.invalidate(key); - objList.forEach(obj -> { - log.info("Group service processed group key {} in device:{}. " - + "Done implementing next objective: {} <<-->> gid:{}", - key, deviceId, obj.nextObjective().id(), - Integer.toHexString(groupService.getGroup(deviceId, key) - .givenGroupId())); - pass(obj.nextObjective()); - flowObjectiveStore.putNextGroup(obj.nextObjective().id(), obj); - }); - } - } - }); - } - } - - private class InnerGroupListener implements GroupListener { - @Override - public void event(GroupEvent event) { - log.trace("received group event of type {}", event.type()); - if (event.type() == GroupEvent.Type.GROUP_ADDED) { - GroupKey key = event.subject().appCookie(); - // first check for group chain - Set<GroupChainElem> gceSet = pendingGroups.remove(key); - if (gceSet != null) { - for (GroupChainElem gce : gceSet) { - log.info("group ADDED with group key {} .. " - + "Processing next group in group chain with group key {}", - key, - gce.groupDescription.appCookie()); - processGroupChain(gce); - } - } else { - List<OfdpaNextGroup> objList = pendingNextObjectives.getIfPresent(key); - if (objList != null) { - pendingNextObjectives.invalidate(key); - objList.forEach(obj -> { - log.info("group ADDED with key {} in dev {}.. Done implementing next " - + "objective: {} <<-->> gid:{}", - key, deviceId, obj.nextObjective().id(), - Integer.toHexString(groupService.getGroup(deviceId, key) - .givenGroupId())); - pass(obj.nextObjective()); - flowObjectiveStore.putNextGroup(obj.nextObjective().id(), obj); - }); - } - } - } - } - } - - /** - * Represents an entire group-chain that implements a Next-Objective from - * the application. The objective is represented as a list of deques, where - * each deque can is a separate chain of groups. - * <p> - * For example, an ECMP group with 3 buckets, where each bucket points to - * a group chain of L3 Unicast and L2 interface groups will look like this: - * <ul> - * <li>List[0] is a Deque of GroupKeyECMP(first)-GroupKeyL3(middle)-GroupKeyL2(last) - * <li>List[1] is a Deque of GroupKeyECMP(first)-GroupKeyL3(middle)-GroupKeyL2(last) - * <li>List[2] is a Deque of GroupKeyECMP(first)-GroupKeyL3(middle)-GroupKeyL2(last) - * </ul> - * where the first element of each deque is the same, representing the - * top level ECMP group, while every other element represents a unique groupKey. - * <p> - * Also includes information about the next objective that - * resulted in this group-chain. - * - */ - private class OfdpaNextGroup implements NextGroup { - private final NextObjective nextObj; - private final List<Deque<GroupKey>> gkeys; - - public OfdpaNextGroup(List<Deque<GroupKey>> gkeys, NextObjective nextObj) { - this.gkeys = gkeys; - this.nextObj = nextObj; - } - - @SuppressWarnings("unused") - public List<Deque<GroupKey>> groupKey() { - return gkeys; - } - - public NextObjective nextObjective() { - return nextObj; - } - - @Override - public byte[] data() { - return appKryo.serialize(gkeys); - } - - } - - /** - * Represents a group element that is part of a chain of groups. - * Stores enough information to create a Group Description to add the group - * to the switch by requesting the Group Service. Objects instantiating this - * class are meant to be temporary and live as long as it is needed to wait for - * preceding groups in the group chain to be created. - */ - private class GroupChainElem { - private GroupDescription groupDescription; - private AtomicInteger waitOnGroups; - - GroupChainElem(GroupDescription groupDescription, int waitOnGroups) { - this.groupDescription = groupDescription; - this.waitOnGroups = new AtomicInteger(waitOnGroups); - } - - /** - * This methods atomically decrements the counter for the number of - * groups this GroupChainElement is waiting on, for notifications from - * the Group Service. When this method returns a value of 0, this - * GroupChainElement is ready to be processed. - * - * @return integer indication of the number of notifications being waited on - */ - int decrementAndGetGroupsWaitedOn() { - return waitOnGroups.decrementAndGet(); - } - - @Override - public String toString() { - return (Integer.toHexString(groupDescription.givenGroupId()) + - " groupKey: " + groupDescription.appCookie() + - " waiting-on-groups: " + waitOnGroups.get() + - " device: " + deviceId); - } - } - -} diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/OVSCorsaPipeline.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/OVSCorsaPipeline.java deleted file mode 100644 index 5993d96e..00000000 --- a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/OVSCorsaPipeline.java +++ /dev/null @@ -1,829 +0,0 @@ -/* - * 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 com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.RemovalCause; -import com.google.common.cache.RemovalNotification; - -import org.onlab.osgi.ServiceDirectory; -import org.onlab.packet.Ethernet; -import org.onlab.packet.IPv4; -import org.onlab.packet.MacAddress; -import org.onlab.packet.VlanId; -import org.onlab.util.KryoNamespace; -import org.onosproject.core.ApplicationId; -import org.onosproject.core.CoreService; -import org.onosproject.net.DeviceId; -import org.onosproject.net.behaviour.NextGroup; -import org.onosproject.net.behaviour.Pipeliner; -import org.onosproject.net.behaviour.PipelinerContext; -import org.onosproject.net.driver.AbstractHandlerBehaviour; -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.Criteria; -import org.onosproject.net.flow.criteria.Criterion; -import org.onosproject.net.flow.criteria.EthCriterion; -import org.onosproject.net.flow.criteria.EthTypeCriterion; -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.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.onosproject.net.group.DefaultGroupBucket; -import org.onosproject.net.group.DefaultGroupDescription; -import org.onosproject.net.group.DefaultGroupKey; -import org.onosproject.net.group.Group; -import org.onosproject.net.group.GroupBucket; -import org.onosproject.net.group.GroupBuckets; -import org.onosproject.net.group.GroupDescription; -import org.onosproject.net.group.GroupEvent; -import org.onosproject.net.group.GroupKey; -import org.onosproject.net.group.GroupListener; -import org.onosproject.net.group.GroupService; -import org.slf4j.Logger; - -import java.util.Collection; -import java.util.Collections; -import java.util.Set; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; - -import static org.onlab.util.Tools.groupedThreads; -import static org.slf4j.LoggerFactory.getLogger; - -/** - * OpenvSwitch emulation of the Corsa pipeline handler. - */ -public class OVSCorsaPipeline extends AbstractHandlerBehaviour implements Pipeliner { - - 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; - - - protected static final int CONTROLLER_PRIORITY = 255; - private static final int DROP_PRIORITY = 0; - private static final int HIGHEST_PRIORITY = 0xffff; - - private final Logger log = getLogger(getClass()); - - private ServiceDirectory serviceDirectory; - protected FlowRuleService flowRuleService; - private CoreService coreService; - private GroupService groupService; - private FlowObjectiveStore flowObjectiveStore; - protected DeviceId deviceId; - protected ApplicationId appId; - - private KryoNamespace appKryo = new KryoNamespace.Builder() - .register(GroupKey.class) - .register(DefaultGroupKey.class) - .register(CorsaGroup.class) - .register(byte[].class) - .build(); - - private Cache<GroupKey, NextObjective> pendingGroups; - - private ScheduledExecutorService groupChecker = - Executors.newScheduledThreadPool(2, groupedThreads("onos/pipeliner", - "ovs-corsa-%d")); - - @Override - public void init(DeviceId deviceId, PipelinerContext context) { - this.serviceDirectory = context.directory(); - this.deviceId = deviceId; - - pendingGroups = CacheBuilder.newBuilder() - .expireAfterWrite(20, TimeUnit.SECONDS) - .removalListener((RemovalNotification<GroupKey, NextObjective> notification) -> { - if (notification.getCause() == RemovalCause.EXPIRED) { - fail(notification.getValue(), ObjectiveError.GROUPINSTALLATIONFAILED); - } - }).build(); - - groupChecker.scheduleAtFixedRate(new GroupChecker(), 0, 500, TimeUnit.MILLISECONDS); - - coreService = serviceDirectory.get(CoreService.class); - flowRuleService = serviceDirectory.get(FlowRuleService.class); - groupService = serviceDirectory.get(GroupService.class); - flowObjectiveStore = context.store(); - - groupService.addListener(new InnerGroupListener()); - - appId = coreService.registerApplication( - "org.onosproject.driver.OVSCorsaPipeline"); - - initializePipeline(); - } - - @Override - public void filter(FilteringObjective filteringObjective) { - if (filteringObjective.type() == FilteringObjective.Type.PERMIT) { - processFilter(filteringObjective, - filteringObjective.op() == Objective.Operation.ADD, - filteringObjective.appId()); - } else { - fail(filteringObjective, ObjectiveError.UNSUPPORTED); - } - } - - @Override - public void forward(ForwardingObjective fwd) { - Collection<FlowRule> rules; - FlowRuleOperations.Builder flowBuilder = FlowRuleOperations.builder(); - - rules = processForward(fwd); - switch (fwd.op()) { - case ADD: - rules.stream() - .filter(rule -> rule != null) - .forEach(flowBuilder::add); - break; - case REMOVE: - rules.stream() - .filter(rule -> rule != null) - .forEach(flowBuilder::remove); - break; - default: - fail(fwd, ObjectiveError.UNKNOWN); - log.warn("Unknown forwarding type {}", fwd.op()); - } - - - flowRuleService.apply(flowBuilder.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - pass(fwd); - } - - @Override - public void onError(FlowRuleOperations ops) { - fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED); - } - })); - - } - - @Override - public void next(NextObjective nextObjective) { - switch (nextObjective.type()) { - case SIMPLE: - Collection<TrafficTreatment> treatments = nextObjective.next(); - if (treatments.size() == 1) { - TrafficTreatment treatment = treatments.iterator().next(); - GroupBucket bucket = - DefaultGroupBucket.createIndirectGroupBucket(treatment); - final GroupKey key = new DefaultGroupKey(appKryo.serialize(nextObjective.id())); - GroupDescription groupDescription - = new DefaultGroupDescription(deviceId, - GroupDescription.Type.INDIRECT, - new GroupBuckets(Collections - .singletonList(bucket)), - key, - null, // let group service determine group id - nextObjective.appId()); - groupService.addGroup(groupDescription); - pendingGroups.put(key, nextObjective); - } - break; - case HASHED: - case BROADCAST: - case FAILOVER: - fail(nextObjective, ObjectiveError.UNSUPPORTED); - log.warn("Unsupported next objective type {}", nextObjective.type()); - break; - default: - fail(nextObjective, ObjectiveError.UNKNOWN); - log.warn("Unknown next objective type {}", nextObjective.type()); - } - - } - - private Collection<FlowRule> processForward(ForwardingObjective fwd) { - switch (fwd.flag()) { - case SPECIFIC: - return processSpecific(fwd); - case VERSATILE: - return processVersatile(fwd); - default: - fail(fwd, ObjectiveError.UNKNOWN); - log.warn("Unknown forwarding flag {}", fwd.flag()); - } - return Collections.emptySet(); - } - - private Collection<FlowRule> processVersatile(ForwardingObjective fwd) { - log.debug("Processing versatile forwarding objective"); - TrafficSelector selector = fwd.selector(); - - EthTypeCriterion ethType = - (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE); - if (ethType == null) { - log.error("Versatile forwarding objective must include ethType"); - fail(fwd, ObjectiveError.UNKNOWN); - return Collections.emptySet(); - } - if (ethType.ethType().toShort() == Ethernet.TYPE_ARP) { - log.warn("Driver automatically handles ARP packets by punting to controller " - + " from ETHER table"); - pass(fwd); - return Collections.emptySet(); - } else if (ethType.ethType().toShort() == Ethernet.TYPE_LLDP || - ethType.ethType().toShort() == Ethernet.TYPE_BSN) { - log.warn("Driver currently does not currently handle LLDP packets"); - fail(fwd, ObjectiveError.UNSUPPORTED); - return Collections.emptySet(); - } else if (ethType.ethType().toShort() == Ethernet.TYPE_IPV4) { - IPCriterion ipSrc = (IPCriterion) selector - .getCriterion(Criterion.Type.IPV4_SRC); - IPCriterion ipDst = (IPCriterion) selector - .getCriterion(Criterion.Type.IPV4_DST); - IPProtocolCriterion ipProto = (IPProtocolCriterion) selector - .getCriterion(Criterion.Type.IP_PROTO); - if (ipSrc != null) { - log.warn("Driver does not currently handle matching Src IP"); - fail(fwd, ObjectiveError.UNSUPPORTED); - return Collections.emptySet(); - } - if (ipDst != null) { - log.error("Driver handles Dst IP matching as specific forwarding " - + "objective, not versatile"); - fail(fwd, ObjectiveError.UNSUPPORTED); - return Collections.emptySet(); - } - 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(); - } - } - - log.warn("Driver does not support given versatile forwarding objective"); - fail(fwd, ObjectiveError.UNSUPPORTED); - return Collections.emptySet(); - } - - private Collection<FlowRule> processSpecific(ForwardingObjective fwd) { - log.debug("Processing specific forwarding objective"); - TrafficSelector selector = fwd.selector(); - EthTypeCriterion ethType = - (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE); - if (ethType == null || ethType.ethType().toShort() != Ethernet.TYPE_IPV4) { - fail(fwd, ObjectiveError.UNSUPPORTED); - return Collections.emptySet(); - } - - TrafficSelector filteredSelector = - DefaultTrafficSelector.builder() - .matchEthType(Ethernet.TYPE_IPV4) - .matchIPDst( - ((IPCriterion) - selector.getCriterion(Criterion.Type.IPV4_DST)).ip()) - .build(); - - TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder(); - - if (fwd.nextId() != null) { - NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId()); - GroupKey key = appKryo.deserialize(next.data()); - Group group = groupService.getGroup(deviceId, key); - if (group == null) { - log.warn("The group left!"); - fail(fwd, ObjectiveError.GROUPMISSING); - return Collections.emptySet(); - } - tb.group(group.id()); - } - - FlowRule.Builder ruleBuilder = DefaultFlowRule.builder() - .fromApp(fwd.appId()) - .withPriority(fwd.priority()) - .forDevice(deviceId) - .withSelector(filteredSelector) - .withTreatment(tb.build()); - - if (fwd.permanent()) { - ruleBuilder.makePermanent(); - } else { - ruleBuilder.makeTemporary(fwd.timeout()); - } - - ruleBuilder.forTable(FIB_TABLE); - - - return Collections.singletonList(ruleBuilder.build()); - - } - - private void processFilter(FilteringObjective filt, boolean install, - ApplicationId applicationId) { - // This driver only processes filtering criteria defined with switch - // ports as the key - PortCriterion p; - if (!filt.key().equals(Criteria.dummy()) && - filt.key().type() == Criterion.Type.IN_PORT) { - p = (PortCriterion) filt.key(); - } else { - log.warn("No key defined in filtering objective from app: {}. Not" - + "processing filtering objective", applicationId); - fail(filt, ObjectiveError.UNKNOWN); - return; - } - // convert filtering conditions for switch-intfs into flowrules - FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); - for (Criterion c : filt.conditions()) { - if (c.type() == Criterion.Type.ETH_DST) { - EthCriterion e = (EthCriterion) c; - log.debug("adding rule for MAC: {}", e.mac()); - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); - selector.matchEthDst(e.mac()); - treatment.transition(VLAN_MPLS_TABLE); - FlowRule rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(CONTROLLER_PRIORITY) - .fromApp(applicationId) - .makePermanent() - .forTable(MAC_TABLE).build(); - ops = install ? ops.add(rule) : ops.remove(rule); - } else if (c.type() == Criterion.Type.VLAN_VID) { - VlanIdCriterion v = (VlanIdCriterion) c; - log.debug("adding rule for VLAN: {}", v.vlanId()); - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); - selector.matchVlanId(v.vlanId()); - selector.matchInPort(p.port()); - treatment.transition(ETHER_TABLE); - treatment.deferred().popVlan(); - FlowRule rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(CONTROLLER_PRIORITY) - .fromApp(applicationId) - .makePermanent() - .forTable(VLAN_TABLE).build(); - ops = install ? ops.add(rule) : ops.remove(rule); - } else if (c.type() == Criterion.Type.IPV4_DST) { - IPCriterion ip = (IPCriterion) c; - 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); - FlowRule rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(HIGHEST_PRIORITY) - .fromApp(applicationId) - .makePermanent() - .forTable(FIB_TABLE).build(); - - ops = install ? ops.add(rule) : ops.remove(rule); - } else { - log.warn("Driver does not currently process filtering condition" - + " of type: {}", c.type()); - fail(filt, ObjectiveError.UNSUPPORTED); - } - } - // apply filtering flow rules - flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - pass(filt); - log.info("Applied filtering rules"); - } - - @Override - public void onError(FlowRuleOperations ops) { - fail(filt, ObjectiveError.FLOWINSTALLATIONFAILED); - log.info("Failed to apply filtering rules"); - } - })); - } - - 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); - } - } - - private 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(); - - - FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); - - ops = install ? ops.add(rule) : ops.remove(rule); - - - //Drop rule - selector = DefaultTrafficSelector.builder(); - treatment = DefaultTrafficTreatment.builder(); - - treatment.drop(); - - rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(DROP_PRIORITY) - .fromApp(appId) - .makePermanent() - .forTable(MAC_TABLE).build(); - - - ops = install ? ops.add(rule) : ops.remove(rule); - - flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - log.info("Provisioned mac table"); - } - - @Override - public void onError(FlowRuleOperations ops) { - log.info("Failed to provision mac table"); - } - })); - - } - - 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(); - - - ops = install ? ops.add(rule) : ops.remove(rule); - - flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - log.info("Provisioned vlan/mpls table"); - } - - @Override - public void onError(FlowRuleOperations ops) { - log.info( - "Failed to provision vlan/mpls table"); - } - })); - - } - - private void processVlanTable(boolean install) { - TrafficSelector.Builder selector; - TrafficTreatment.Builder treatment; - FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); - FlowRule rule; - - - //Drop rule - selector = DefaultTrafficSelector.builder(); - treatment = DefaultTrafficTreatment.builder(); - - treatment.drop(); - - rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(DROP_PRIORITY) - .fromApp(appId) - .makePermanent() - .forTable(VLAN_TABLE).build(); - - ops = install ? ops.add(rule) : ops.remove(rule); - - flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - log.info("Provisioned vlan table"); - } - - @Override - public void onError(FlowRuleOperations ops) { - log.info("Failed to provision vlan table"); - } - })); - } - - private void processEtherTable(boolean install) { - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); - TrafficTreatment.Builder treatment = DefaultTrafficTreatment - .builder(); - FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); - FlowRule rule; - - selector.matchEthType(Ethernet.TYPE_ARP); - treatment.punt(); - - rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(CONTROLLER_PRIORITY) - .fromApp(appId) - .makePermanent() - .forTable(ETHER_TABLE).build(); - - ops = install ? ops.add(rule) : ops.remove(rule); - - selector = DefaultTrafficSelector.builder(); - treatment = DefaultTrafficTreatment.builder(); - - selector.matchEthType(Ethernet.TYPE_IPV4); - treatment.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(); - - ops = install ? ops.add(rule) : ops.remove(rule); - - //Drop rule - selector = DefaultTrafficSelector.builder(); - treatment = DefaultTrafficTreatment.builder(); - - treatment.drop(); - - rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(DROP_PRIORITY) - .fromApp(appId) - .makePermanent() - .forTable(ETHER_TABLE).build(); - - - ops = install ? ops.add(rule) : ops.remove(rule); - - flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - log.info("Provisioned ether table"); - } - - @Override - public void onError(FlowRuleOperations ops) { - log.info("Failed to provision ether table"); - } - })); - - } - - private void processCosTable(boolean install) { - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); - TrafficTreatment.Builder treatment = DefaultTrafficTreatment - .builder(); - FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); - FlowRule rule; - - treatment.transition(FIB_TABLE); - - rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(DROP_PRIORITY) - .fromApp(appId) - .makePermanent() - .forTable(COS_MAP_TABLE).build(); - - ops = install ? ops.add(rule) : ops.remove(rule); - - flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - log.info("Provisioned cos table"); - } - - @Override - public void onError(FlowRuleOperations ops) { - log.info("Failed to provision cos table"); - } - })); - - } - - private void processFibTable(boolean install) { - TrafficSelector.Builder selector; - TrafficTreatment.Builder treatment; - FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); - FlowRule rule; - - //Drop rule - selector = DefaultTrafficSelector.builder(); - treatment = DefaultTrafficTreatment.builder(); - - treatment.drop(); - - rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(DROP_PRIORITY) - .fromApp(appId) - .makePermanent() - .forTable(FIB_TABLE).build(); - - ops = install ? ops.add(rule) : ops.remove(rule); - - flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - log.info("Provisioned FIB table"); - } - - @Override - public void onError(FlowRuleOperations ops) { - log.info("Failed to provision FIB table"); - } - })); - } - - private void processLocalTable(boolean install) { - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); - TrafficTreatment.Builder treatment = DefaultTrafficTreatment - .builder(); - FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); - FlowRule rule; - - treatment.punt(); - - rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(CONTROLLER_PRIORITY) - .fromApp(appId) - .makePermanent() - .forTable(LOCAL_TABLE).build(); - - ops = install ? ops.add(rule) : ops.remove(rule); - - flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - log.info("Provisioned Local table"); - } - - @Override - public void onError(FlowRuleOperations ops) { - log.info("Failed to provision Local table"); - } - })); - } - - private class InnerGroupListener implements GroupListener { - @Override - public void event(GroupEvent event) { - if (event.type() == GroupEvent.Type.GROUP_ADDED) { - GroupKey key = event.subject().appCookie(); - - NextObjective obj = pendingGroups.getIfPresent(key); - if (obj != null) { - flowObjectiveStore.putNextGroup(obj.id(), new CorsaGroup(key)); - pass(obj); - pendingGroups.invalidate(key); - } - } - } - } - - - private class GroupChecker implements Runnable { - - @Override - public void run() { - Set<GroupKey> keys = pendingGroups.asMap().keySet().stream() - .filter(key -> groupService.getGroup(deviceId, key) != null) - .collect(Collectors.toSet()); - - keys.stream().forEach(key -> { - NextObjective obj = pendingGroups.getIfPresent(key); - if (obj == null) { - return; - } - pass(obj); - pendingGroups.invalidate(key); - log.info("Heard back from group service for group {}. " - + "Applying pending forwarding objectives", obj.id()); - flowObjectiveStore.putNextGroup(obj.id(), new CorsaGroup(key)); - }); - } - } - - private class CorsaGroup implements NextGroup { - - private final GroupKey key; - - public CorsaGroup(GroupKey key) { - this.key = key; - } - - @SuppressWarnings("unused") - public GroupKey key() { - return key; - } - - @Override - public byte[] data() { - return appKryo.serialize(key); - } - - } -} diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/OltPipeline.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/OltPipeline.java deleted file mode 100644 index 8a7b22b8..00000000 --- a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/OltPipeline.java +++ /dev/null @@ -1,238 +0,0 @@ -/* - * 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.EthType; -import org.onosproject.core.ApplicationId; -import org.onosproject.core.CoreService; -import org.onosproject.net.DefaultAnnotations; -import org.onosproject.net.Device; -import org.onosproject.net.DeviceId; -import org.onosproject.net.MastershipRole; -import org.onosproject.net.PortNumber; -import org.onosproject.net.behaviour.Pipeliner; -import org.onosproject.net.behaviour.PipelinerContext; -import org.onosproject.net.device.DefaultDeviceDescription; -import org.onosproject.net.device.DeviceDescription; -import org.onosproject.net.device.DeviceProvider; -import org.onosproject.net.device.DeviceProviderRegistry; -import org.onosproject.net.device.DeviceService; -import org.onosproject.net.driver.AbstractHandlerBehaviour; -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.instructions.Instructions; -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.packet.PacketPriority; -import org.onosproject.net.provider.AbstractProvider; -import org.onosproject.net.provider.ProviderId; -import org.slf4j.Logger; - -import static com.google.common.base.Preconditions.checkNotNull; -import static org.slf4j.LoggerFactory.getLogger; - -/** - * Pipeliner for OLT device. - */ -public class OltPipeline extends AbstractHandlerBehaviour implements Pipeliner { - - private final Logger log = getLogger(getClass()); - - static final ProviderId PID = new ProviderId("olt", "org.onosproject.olt", true); - - static final String DEVICE = "isAccess"; - static final String OLT = "true"; - - private ServiceDirectory serviceDirectory; - private FlowRuleService flowRuleService; - private DeviceId deviceId; - private CoreService coreService; - - private ApplicationId appId; - - private DeviceProvider provider = new AnnotationProvider(); - - - @Override - public void init(DeviceId deviceId, PipelinerContext context) { - this.serviceDirectory = context.directory(); - this.deviceId = deviceId; - DeviceProviderRegistry registry = - serviceDirectory.get(DeviceProviderRegistry.class); - flowRuleService = serviceDirectory.get(FlowRuleService.class); - coreService = serviceDirectory.get(CoreService.class); - - /*try { - DeviceProviderService providerService = registry.register(provider); - providerService.deviceConnected(deviceId, - description(deviceId, DEVICE, OLT)); - } finally { - registry.unregister(provider); - }*/ - - appId = coreService.registerApplication( - "org.onosproject.driver.OLTPipeline"); - - TrafficSelector selector = DefaultTrafficSelector.builder() - .matchEthType(EthType.EtherType.EAPOL.ethType().toShort()) - .build(); - - TrafficTreatment treatment = DefaultTrafficTreatment.builder() - .punt() - .build(); - - FlowRule flowRule = new DefaultFlowRule(deviceId, selector, treatment, - PacketPriority.CONTROL.priorityValue(), - appId, 0, true, null); - - //flowRuleService.applyFlowRules(flowRule); - } - - @Override - public void filter(FilteringObjective filter) { - throw new UnsupportedOperationException("OLT does not filter."); - } - - @Override - public void forward(ForwardingObjective fwd) { - FlowRuleOperations.Builder flowBuilder = FlowRuleOperations.builder(); - - if (fwd.flag() != ForwardingObjective.Flag.VERSATILE) { - throw new UnsupportedOperationException( - "Only VERSATILE is supported."); - } - - boolean isPunt = fwd.treatment().immediate().stream().anyMatch(i -> { - if (i instanceof Instructions.OutputInstruction) { - Instructions.OutputInstruction out = (Instructions.OutputInstruction) i; - return out.port().equals(PortNumber.CONTROLLER); - } - return false; - }); - - if (isPunt) { - return; - } - - TrafficSelector selector = fwd.selector(); - TrafficTreatment treatment = fwd.treatment(); - - FlowRule.Builder ruleBuilder = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector) - .withTreatment(treatment) - .fromApp(fwd.appId()) - .withPriority(fwd.priority()); - - if (fwd.permanent()) { - ruleBuilder.makePermanent(); - } else { - ruleBuilder.makeTemporary(fwd.timeout()); - } - - switch (fwd.op()) { - case ADD: - flowBuilder.add(ruleBuilder.build()); - break; - case REMOVE: - flowBuilder.remove(ruleBuilder.build()); - break; - default: - log.warn("Unknown operation {}", fwd.op()); - } - - flowRuleService.apply(flowBuilder.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - if (fwd.context().isPresent()) { - fwd.context().get().onSuccess(fwd); - } - } - - @Override - public void onError(FlowRuleOperations ops) { - if (fwd.context().isPresent()) { - fwd.context().get().onError(fwd, ObjectiveError.FLOWINSTALLATIONFAILED); - } - } - })); - } - - @Override - public void next(NextObjective nextObjective) { - throw new UnsupportedOperationException("OLT does not next hop."); - } - - /** - * Build a device description. - * - * @param deviceId a deviceId - * @param key the key of the annotation - * @param value the value for the annotation - * @return a device description - */ - private DeviceDescription description(DeviceId deviceId, String key, String value) { - DeviceService deviceService = serviceDirectory.get(DeviceService.class); - Device device = deviceService.getDevice(deviceId); - - checkNotNull(device, "Device not found in device service."); - - DefaultAnnotations.Builder builder = DefaultAnnotations.builder(); - if (value != null) { - builder.set(key, value); - } else { - builder.remove(key); - } - return new DefaultDeviceDescription(device.id().uri(), device.type(), - device.manufacturer(), device.hwVersion(), - device.swVersion(), device.serialNumber(), - device.chassisId(), builder.build()); - } - - /** - * Simple ancillary provider used to annotate device. - */ - private static final class AnnotationProvider - extends AbstractProvider implements DeviceProvider { - private AnnotationProvider() { - super(PID); - } - - @Override - public void triggerProbe(DeviceId deviceId) { - } - - @Override - public void roleChanged(DeviceId deviceId, MastershipRole newRole) { - } - - @Override - public boolean isReachable(DeviceId deviceId) { - return false; - } - } - -} diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/OpenVSwitchPipeline.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/OpenVSwitchPipeline.java deleted file mode 100644 index 5d098390..00000000 --- a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/OpenVSwitchPipeline.java +++ /dev/null @@ -1,241 +0,0 @@ -/* - * 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 static org.slf4j.LoggerFactory.getLogger; - -import java.util.Collection; -import java.util.Collections; - -import org.onlab.osgi.ServiceDirectory; -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.device.DeviceService; -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.Type; -import org.onosproject.net.flow.instructions.Instructions; -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; - -/** - * Driver for standard OpenVSwitch. - */ -public class OpenVSwitchPipeline extends DefaultSingleTablePipeline - implements Pipeliner { - - private static final String VTN_APP_ID = "org.onosproject.app.vtn"; - 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 DeviceService deviceService; - private static final int TIME_OUT = 0; - private static final int CLASSIFIER_TABLE = 0; - private static final int MAC_TABLE = 50; - private static final int TABLE_MISS_PRIORITY = 0; - - @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.OpenVSwitchPipeline"); - initializePipeline(); - } - - @Override - public void filter(FilteringObjective filteringObjective) { - super.filter(filteringObjective); - } - - @Override - public void forward(ForwardingObjective fwd) { - if (!VTN_APP_ID.equals(fwd.appId().name())) { - super.forward(fwd); - return; - } - Collection<FlowRule> rules; - FlowRuleOperations.Builder flowOpsBuilder = FlowRuleOperations - .builder(); - - rules = processForward(fwd); - switch (fwd.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(fwd, ObjectiveError.UNKNOWN); - log.warn("Unknown forwarding type {}", fwd.op()); - } - - flowRuleService.apply(flowOpsBuilder - .build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - pass(fwd); - } - - @Override - public void onError(FlowRuleOperations ops) { - fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED); - } - })); - } - - @Override - public void next(NextObjective nextObjective) { - super.next(nextObjective); - } - - private void initializePipeline() { - processClassifierTable(true); - processMacTable(true); - } - - private void processClassifierTable(boolean install) { - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); - - treatment.transition(MAC_TABLE); - - FlowRule rule; - rule = DefaultFlowRule.builder().forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(TABLE_MISS_PRIORITY).fromApp(appId) - .makePermanent().forTable(CLASSIFIER_TABLE).build(); - - applyRules(install, rule); - } - - private void processMacTable(boolean install) { - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); - - treatment.drop(); - - FlowRule rule; - rule = DefaultFlowRule.builder().forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(TABLE_MISS_PRIORITY).fromApp(appId) - .makePermanent().forTable(MAC_TABLE).build(); - - applyRules(install, rule); - } - - private void applyRules(boolean install, FlowRule rule) { - FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); - - ops = install ? ops.add(rule) : ops.remove(rule); - flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - log.info("ONOSW provisioned " + rule.tableId() + " table"); - } - - @Override - public void onError(FlowRuleOperations ops) { - log.info("ONOSW failed to provision " + rule.tableId() + " table"); - } - })); - } - - private Collection<FlowRule> processForward(ForwardingObjective fwd) { - switch (fwd.flag()) { - case SPECIFIC: - return processSpecific(fwd); - case VERSATILE: - return processVersatile(fwd); - default: - fail(fwd, ObjectiveError.UNKNOWN); - log.warn("Unknown forwarding flag {}", fwd.flag()); - } - return Collections.emptySet(); - } - - private Collection<FlowRule> processVersatile(ForwardingObjective fwd) { - log.debug("Processing versatile forwarding objective"); - return Collections.emptyList(); - } - - private Collection<FlowRule> processSpecific(ForwardingObjective fwd) { - log.debug("Processing specific forwarding objective"); - TrafficSelector selector = fwd.selector(); - TrafficTreatment tb = fwd.treatment(); - FlowRule.Builder ruleBuilder = DefaultFlowRule.builder() - .fromApp(fwd.appId()).withPriority(fwd.priority()) - .forDevice(deviceId).withSelector(selector) - .withTreatment(tb).makeTemporary(TIME_OUT); - ruleBuilder.withPriority(fwd.priority()); - if (fwd.permanent()) { - ruleBuilder.makePermanent(); - } - if (selector.getCriterion(Type.ETH_DST) != null - || tb.allInstructions().contains(Instructions.createDrop())) { - ruleBuilder.withTreatment(tb); - ruleBuilder.forTable(MAC_TABLE); - } else { - TrafficTreatment.Builder newTraffic = DefaultTrafficTreatment.builder(); - tb.allInstructions().forEach(t -> newTraffic.add(t)); - newTraffic.transition(MAC_TABLE); - ruleBuilder.withTreatment(newTraffic.build()); - ruleBuilder.forTable(CLASSIFIER_TABLE); - } - return Collections.singletonList(ruleBuilder.build()); - } - - private void fail(Objective obj, ObjectiveError error) { - if (obj.context().isPresent()) { - obj.context().get().onError(obj, error); - } - } - - private void pass(Objective obj) { - if (obj.context().isPresent()) { - obj.context().get().onSuccess(obj); - } - } -} diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/OpenstackPipeline.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/OpenstackPipeline.java deleted file mode 100644 index 7a92b4fa..00000000 --- a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/OpenstackPipeline.java +++ /dev/null @@ -1,286 +0,0 @@ -/* - * 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<FlowRule> 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<FlowRule> 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<FlowRule> 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<FlowRule> 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); - } - } -} - diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/PicaPipeline.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/PicaPipeline.java deleted file mode 100644 index 69d20835..00000000 --- a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/PicaPipeline.java +++ /dev/null @@ -1,543 +0,0 @@ -/* - * 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.onlab.packet.MacAddress; -import org.onlab.packet.VlanId; -import org.onlab.util.KryoNamespace; -import org.onosproject.core.ApplicationId; -import org.onosproject.core.CoreService; -import org.onosproject.net.DeviceId; -import org.onosproject.net.PortNumber; -import org.onosproject.net.behaviour.NextGroup; -import org.onosproject.net.behaviour.Pipeliner; -import org.onosproject.net.behaviour.PipelinerContext; -import org.onosproject.net.driver.AbstractHandlerBehaviour; -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.Criteria; -import org.onosproject.net.flow.criteria.Criterion; -import org.onosproject.net.flow.criteria.EthCriterion; -import org.onosproject.net.flow.criteria.EthTypeCriterion; -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.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.onosproject.store.serializers.KryoNamespaces; -import org.slf4j.Logger; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.ConcurrentHashMap; - -import static org.slf4j.LoggerFactory.getLogger; - -/** - * Pica pipeline handler. - */ -public class PicaPipeline extends AbstractHandlerBehaviour implements Pipeliner { - - protected static final int IP_UNICAST_TABLE = 252; - protected static final int ACL_TABLE = 0; - - //private static final int CONTROLLER_PRIORITY = 255; - private static final int DROP_PRIORITY = 0; - private static final int HIGHEST_PRIORITY = 0xffff; - - private final Logger log = getLogger(getClass()); - - private ServiceDirectory serviceDirectory; - private FlowRuleService flowRuleService; - private CoreService coreService; - private FlowObjectiveStore flowObjectiveStore; - private DeviceId deviceId; - private ApplicationId appId; - private Collection<Filter> filters; - private Collection<ForwardingObjective> pendingVersatiles; - - private KryoNamespace appKryo = new KryoNamespace.Builder() - .register(KryoNamespaces.API) - .register(PicaGroup.class) - .register(byte[].class) - .build(); - - @Override - public void init(DeviceId deviceId, PipelinerContext context) { - this.serviceDirectory = context.directory(); - this.deviceId = deviceId; - - coreService = serviceDirectory.get(CoreService.class); - flowRuleService = serviceDirectory.get(FlowRuleService.class); - flowObjectiveStore = context.store(); - filters = Collections.newSetFromMap(new ConcurrentHashMap<Filter, Boolean>()); - pendingVersatiles = Collections.newSetFromMap( - new ConcurrentHashMap<ForwardingObjective, Boolean>()); - appId = coreService.registerApplication( - "org.onosproject.driver.OVSPicaPipeline"); - - initializePipeline(); - } - - @Override - public void filter(FilteringObjective filteringObjective) { - if (filteringObjective.type() == FilteringObjective.Type.PERMIT) { - processFilter(filteringObjective, - filteringObjective.op() == Objective.Operation.ADD, - filteringObjective.appId()); - } else { - fail(filteringObjective, ObjectiveError.UNSUPPORTED); - } - } - - @Override - public void forward(ForwardingObjective fwd) { - Collection<FlowRule> rules; - FlowRuleOperations.Builder flowBuilder = FlowRuleOperations.builder(); - - rules = processForward(fwd); - switch (fwd.op()) { - case ADD: - rules.stream() - .filter(rule -> rule != null) - .forEach(flowBuilder::add); - break; - case REMOVE: - rules.stream() - .filter(rule -> rule != null) - .forEach(flowBuilder::remove); - break; - default: - fail(fwd, ObjectiveError.UNKNOWN); - log.warn("Unknown forwarding type {}", fwd.op()); - } - - - flowRuleService.apply(flowBuilder.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - pass(fwd); - } - - @Override - public void onError(FlowRuleOperations ops) { - fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED); - } - })); - - } - - @Override - public void next(NextObjective nextObjective) { - switch (nextObjective.type()) { - case SIMPLE: - Collection<TrafficTreatment> treatments = nextObjective.next(); - if (treatments.size() != 1) { - log.error("Next Objectives of type Simple should only have a " - + "single Traffic Treatment. Next Objective Id:{}", nextObjective.id()); - fail(nextObjective, ObjectiveError.BADPARAMS); - return; - } - TrafficTreatment treatment = treatments.iterator().next(); - TrafficTreatment.Builder filteredTreatment = DefaultTrafficTreatment.builder(); - VlanId modVlanId; - for (Instruction ins : treatment.allInstructions()) { - if (ins.type() == Instruction.Type.L2MODIFICATION) { - L2ModificationInstruction l2ins = (L2ModificationInstruction) ins; - switch (l2ins.subtype()) { - case ETH_DST: - filteredTreatment.setEthDst( - ((L2ModificationInstruction.ModEtherInstruction) l2ins).mac()); - break; - case ETH_SRC: - filteredTreatment.setEthSrc( - ((L2ModificationInstruction.ModEtherInstruction) l2ins).mac()); - break; - case VLAN_ID: - modVlanId = ((L2ModificationInstruction.ModVlanIdInstruction) l2ins).vlanId(); - filteredTreatment.setVlanId(modVlanId); - break; - default: - break; - } - } else if (ins.type() == Instruction.Type.OUTPUT) { - //long portNum = ((Instructions.OutputInstruction) ins).port().toLong(); - filteredTreatment.add(ins); - } else { - // Ignore the vlan_pcp action since it's does matter much. - log.warn("Driver does not handle this type of TrafficTreatment" - + " instruction in nextObjectives: {}", ins.type()); - } - } - // store for future use - flowObjectiveStore.putNextGroup(nextObjective.id(), - new PicaGroup(filteredTreatment.build())); - break; - case HASHED: - case BROADCAST: - case FAILOVER: - fail(nextObjective, ObjectiveError.UNSUPPORTED); - log.warn("Unsupported next objective type {}", nextObjective.type()); - break; - default: - fail(nextObjective, ObjectiveError.UNKNOWN); - log.warn("Unknown next objective type {}", nextObjective.type()); - } - - } - - private Collection<FlowRule> processForward(ForwardingObjective fwd) { - switch (fwd.flag()) { - case SPECIFIC: - return processSpecific(fwd); - case VERSATILE: - return processVersatile(fwd); - default: - fail(fwd, ObjectiveError.UNKNOWN); - log.warn("Unknown forwarding flag {}", fwd.flag()); - } - return Collections.emptySet(); - } - - private Collection<FlowRule> processVersatile(ForwardingObjective fwd) { - log.debug("Processing versatile forwarding objective"); - TrafficSelector selector = fwd.selector(); - TrafficTreatment treatment = fwd.treatment(); - Collection<FlowRule> flowrules = new ArrayList<FlowRule>(); - - // first add this rule for basic single-table operation - // or non-ARP related multi-table operation - FlowRule rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector) - .withTreatment(treatment) - .withPriority(fwd.priority()) - .fromApp(fwd.appId()) - .makePermanent() - .forTable(ACL_TABLE).build(); - flowrules.add(rule); - - EthTypeCriterion ethType = - (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE); - if (ethType == null) { - log.warn("No ethType in versatile forwarding obj. Not processing further."); - return flowrules; - } - - // now deal with possible mix of ARP with filtering objectives - // in multi-table scenarios - if (ethType.ethType().toShort() == Ethernet.TYPE_ARP) { - if (filters.isEmpty()) { - pendingVersatiles.add(fwd); - return flowrules; - } - for (Filter filter : filters) { - flowrules.addAll(processVersatilesWithFilters(filter, fwd)); - } - } - return flowrules; - } - - private Collection<FlowRule> processVersatilesWithFilters( - Filter filt, ForwardingObjective fwd) { - Collection<FlowRule> flows = new ArrayList<FlowRule>(); - - // rule for ARP replies - log.debug("adding ARP rule in ACL table"); - TrafficSelector.Builder sel = DefaultTrafficSelector.builder(); - TrafficTreatment.Builder treat = DefaultTrafficTreatment.builder(); - sel.matchInPort(filt.port()); - sel.matchVlanId(filt.vlanId()); - sel.matchEthDst(filt.mac()); - sel.matchEthType(Ethernet.TYPE_ARP); - treat.setOutput(PortNumber.CONTROLLER); - FlowRule rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(sel.build()) - .withTreatment(treat.build()) - .withPriority(HIGHEST_PRIORITY) - .fromApp(appId) - .makePermanent() - .forTable(ACL_TABLE).build(); - flows.add(rule); - - // rule for ARP Broadcast - sel = DefaultTrafficSelector.builder(); - treat = DefaultTrafficTreatment.builder(); - sel.matchInPort(filt.port()); - sel.matchVlanId(filt.vlanId()); - sel.matchEthDst(MacAddress.BROADCAST); - sel.matchEthType(Ethernet.TYPE_ARP); - treat.setOutput(PortNumber.CONTROLLER); - rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(sel.build()) - .withTreatment(treat.build()) - .withPriority(HIGHEST_PRIORITY) - .fromApp(appId) - .makePermanent() - .forTable(ACL_TABLE).build(); - flows.add(rule); - - return flows; - } - - - private Collection<FlowRule> processSpecific(ForwardingObjective fwd) { - log.debug("Processing specific forwarding objective"); - TrafficSelector selector = fwd.selector(); - EthTypeCriterion ethType = - (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE); - if (ethType == null || ethType.ethType().toShort() != Ethernet.TYPE_IPV4) { - fail(fwd, ObjectiveError.UNSUPPORTED); - return Collections.emptySet(); - } - - List<FlowRule> ipflows = new ArrayList<FlowRule>(); - for (Filter f: filters) { - TrafficSelector filteredSelector = - DefaultTrafficSelector.builder() - .matchEthType(Ethernet.TYPE_IPV4) - .matchIPDst( - ((IPCriterion) - selector.getCriterion(Criterion.Type.IPV4_DST)).ip()) - .matchEthDst(f.mac()) - .matchVlanId(f.vlanId()) - .build(); - TrafficTreatment tt = null; - if (fwd.nextId() != null) { - NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId()); - if (next == null) { - log.error("next-id {} does not exist in store", fwd.nextId()); - return Collections.emptySet(); - } - tt = appKryo.deserialize(next.data()); - if (tt == null) { - log.error("Error in deserializing next-id {}", fwd.nextId()); - return Collections.emptySet(); - } - } - - FlowRule.Builder ruleBuilder = DefaultFlowRule.builder() - .fromApp(fwd.appId()) - .withPriority(fwd.priority()) - .forDevice(deviceId) - .withSelector(filteredSelector) - .withTreatment(tt); - if (fwd.permanent()) { - ruleBuilder.makePermanent(); - } else { - ruleBuilder.makeTemporary(fwd.timeout()); - } - ruleBuilder.forTable(IP_UNICAST_TABLE); - ipflows.add(ruleBuilder.build()); - } - - return ipflows; - } - - private void processFilter(FilteringObjective filt, boolean install, - ApplicationId applicationId) { - // This driver only processes filtering criteria defined with switch - // ports as the key - PortCriterion p; - if (!filt.key().equals(Criteria.dummy()) && - filt.key().type() == Criterion.Type.IN_PORT) { - p = (PortCriterion) filt.key(); - } else { - log.warn("No key defined in filtering objective from app: {}. Not" - + "processing filtering objective", applicationId); - fail(filt, ObjectiveError.UNKNOWN); - return; - } - - EthCriterion e = null; VlanIdCriterion v = null; - Collection<IPCriterion> ips = new ArrayList<IPCriterion>(); - // convert filtering conditions for switch-intfs into flowrules - FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); - for (Criterion c : filt.conditions()) { - if (c.type() == Criterion.Type.ETH_DST) { - e = (EthCriterion) c; - } else if (c.type() == Criterion.Type.VLAN_VID) { - v = (VlanIdCriterion) c; - } else if (c.type() == Criterion.Type.IPV4_DST) { - ips.add((IPCriterion) c); - } else { - log.error("Unsupported filter {}", c); - fail(filt, ObjectiveError.UNSUPPORTED); - return; - } - } - - // cache for later use - Filter filter = new Filter(p, e, v, ips); - filters.add(filter); - - // apply any pending versatile forwarding objectives - for (ForwardingObjective fwd : pendingVersatiles) { - Collection<FlowRule> ret = processVersatilesWithFilters(filter, fwd); - for (FlowRule fr : ret) { - ops.add(fr); - } - } - - for (IPCriterion ipaddr : ips) { - log.debug("adding IP filtering rules in ACL table: {}", ipaddr.ip()); - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); - selector.matchInPort(p.port()); - selector.matchVlanId(v.vlanId()); - selector.matchEthDst(e.mac()); - selector.matchEthType(Ethernet.TYPE_IPV4); - selector.matchIPDst(ipaddr.ip()); // router IPs to the controller - treatment.setOutput(PortNumber.CONTROLLER); - FlowRule rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(HIGHEST_PRIORITY) - .fromApp(applicationId) - .makePermanent() - .forTable(ACL_TABLE).build(); - ops = ops.add(rule); - } - - // apply filtering flow rules - flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - pass(filt); - log.info("Applied filtering rules"); - } - - @Override - public void onError(FlowRuleOperations ops) { - fail(filt, ObjectiveError.FLOWINSTALLATIONFAILED); - log.info("Failed to apply filtering rules"); - } - })); - } - - 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); - } - } - - private void initializePipeline() { - //processIpUnicastTable(true); - processAclTable(true); - } - - private void processAclTable(boolean install) { - TrafficSelector.Builder selector; - TrafficTreatment.Builder treatment; - FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); - FlowRule rule; - - //Drop rule - selector = DefaultTrafficSelector.builder(); - treatment = DefaultTrafficTreatment.builder(); - - rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(DROP_PRIORITY) - .fromApp(appId) - .makePermanent() - .forTable(ACL_TABLE).build(); - - ops = install ? ops.add(rule) : ops.remove(rule); - - flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - log.info("Provisioned ACL table"); - } - - @Override - public void onError(FlowRuleOperations ops) { - log.info("Failed to provision ACL table"); - } - })); - } - - private class Filter { - private PortCriterion port; - private VlanIdCriterion vlan; - private EthCriterion eth; - - @SuppressWarnings("unused") - private Collection<IPCriterion> ips; - - public Filter(PortCriterion p, EthCriterion e, VlanIdCriterion v, - Collection<IPCriterion> ips) { - this.eth = e; - this.port = p; - this.vlan = v; - this.ips = ips; - } - - public PortNumber port() { - return port.port(); - } - - public VlanId vlanId() { - return vlan.vlanId(); - } - - public MacAddress mac() { - return eth.mac(); - } - } - - private class PicaGroup implements NextGroup { - TrafficTreatment nextActions; - - public PicaGroup(TrafficTreatment next) { - this.nextActions = next; - } - - @Override - public byte[] data() { - return appKryo.serialize(nextActions); - } - } -} diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/SoftRouterPipeline.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/SoftRouterPipeline.java deleted file mode 100644 index bd49e688..00000000 --- a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/SoftRouterPipeline.java +++ /dev/null @@ -1,544 +0,0 @@ -/* - * 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.onlab.packet.MacAddress; -import org.onlab.packet.VlanId; -import org.onlab.util.KryoNamespace; -import org.onosproject.core.ApplicationId; -import org.onosproject.core.CoreService; -import org.onosproject.net.DeviceId; -import org.onosproject.net.PortNumber; -import org.onosproject.net.behaviour.NextGroup; -import org.onosproject.net.behaviour.Pipeliner; -import org.onosproject.net.behaviour.PipelinerContext; -import org.onosproject.net.driver.AbstractHandlerBehaviour; -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.Criteria; -import org.onosproject.net.flow.criteria.Criterion; -import org.onosproject.net.flow.criteria.EthCriterion; -import org.onosproject.net.flow.criteria.EthTypeCriterion; -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.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.onosproject.store.serializers.KryoNamespaces; -import org.slf4j.Logger; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.concurrent.ConcurrentHashMap; - -import static org.slf4j.LoggerFactory.getLogger; - -/** - * Simple 2-Table Pipeline for Software/NPU based routers. This pipeline - * does not forward IP traffic to next-hop groups. Instead it forwards traffic - * using OF FlowMod actions. - */ -public class SoftRouterPipeline extends AbstractHandlerBehaviour implements Pipeliner { - - protected static final int FILTER_TABLE = 0; - protected static final int FIB_TABLE = 1; - - private static final int DROP_PRIORITY = 0; - private static final int DEFAULT_PRIORITY = 0x8000; - private static final int HIGHEST_PRIORITY = 0xffff; - - private ServiceDirectory serviceDirectory; - protected FlowRuleService flowRuleService; - private CoreService coreService; - private FlowObjectiveStore flowObjectiveStore; - protected DeviceId deviceId; - protected ApplicationId appId; - private ApplicationId driverId; - private Collection<Filter> filters; - private Collection<ForwardingObjective> pendingVersatiles; - - private KryoNamespace appKryo = new KryoNamespace.Builder() - .register(DummyGroup.class) - .register(KryoNamespaces.API) - .register(byte[].class) - .build(); - - private final Logger log = getLogger(getClass()); - - @Override - public void init(DeviceId deviceId, PipelinerContext context) { - this.serviceDirectory = context.directory(); - this.deviceId = deviceId; - coreService = serviceDirectory.get(CoreService.class); - flowRuleService = serviceDirectory.get(FlowRuleService.class); - flowObjectiveStore = context.store(); - driverId = coreService.registerApplication( - "org.onosproject.driver.SoftRouterPipeline"); - filters = Collections.newSetFromMap(new ConcurrentHashMap<Filter, Boolean>()); - pendingVersatiles = Collections.newSetFromMap( - new ConcurrentHashMap<ForwardingObjective, Boolean>()); - initializePipeline(); - } - - @Override - public void filter(FilteringObjective filteringObjective) { - if (filteringObjective.type() == FilteringObjective.Type.PERMIT) { - processFilter(filteringObjective, - filteringObjective.op() == Objective.Operation.ADD, - filteringObjective.appId()); - } else { - fail(filteringObjective, ObjectiveError.UNSUPPORTED); - } - } - - @Override - public void forward(ForwardingObjective fwd) { - Collection<FlowRule> rules; - FlowRuleOperations.Builder flowOpsBuilder = FlowRuleOperations.builder(); - - rules = processForward(fwd); - switch (fwd.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(fwd, ObjectiveError.UNKNOWN); - log.warn("Unknown forwarding type {}", fwd.op()); - } - - - flowRuleService.apply(flowOpsBuilder.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - pass(fwd); - } - - @Override - public void onError(FlowRuleOperations ops) { - fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED); - } - })); - - } - - @Override - public void next(NextObjective nextObjective) { - switch (nextObjective.type()) { - case SIMPLE: - Collection<TrafficTreatment> treatments = nextObjective.next(); - if (treatments.size() != 1) { - log.error("Next Objectives of type Simple should only have a " - + "single Traffic Treatment. Next Objective Id:{}", nextObjective.id()); - fail(nextObjective, ObjectiveError.BADPARAMS); - return; - } - processSimpleNextObjective(nextObjective); - break; - case HASHED: - case BROADCAST: - case FAILOVER: - fail(nextObjective, ObjectiveError.UNSUPPORTED); - log.warn("Unsupported next objective type {}", nextObjective.type()); - break; - default: - fail(nextObjective, ObjectiveError.UNKNOWN); - log.warn("Unknown next objective type {}", nextObjective.type()); - } - } - - 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); - } - } - - - private void initializePipeline() { - //Drop rules for both tables - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); - FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); - - treatment.drop(); - - FlowRule rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(DROP_PRIORITY) - .fromApp(driverId) - .makePermanent() - .forTable(FILTER_TABLE) - .build(); - ops = ops.add(rule); - - rule = DefaultFlowRule.builder().forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(DROP_PRIORITY) - .fromApp(driverId) - .makePermanent() - .forTable(FIB_TABLE) - .build(); - ops = ops.add(rule); - - flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - log.info("Provisioned drop rules in both tables"); - } - - @Override - public void onError(FlowRuleOperations ops) { - log.info("Failed to provision drop rules"); - } - })); - } - - private void processFilter(FilteringObjective filt, boolean install, - ApplicationId applicationId) { - // This driver only processes filtering criteria defined with switch - // ports as the key - PortCriterion p; EthCriterion e = null; VlanIdCriterion v = null; - Collection<IPCriterion> ips = new ArrayList<IPCriterion>(); - if (!filt.key().equals(Criteria.dummy()) && - filt.key().type() == Criterion.Type.IN_PORT) { - p = (PortCriterion) filt.key(); - } else { - log.warn("No key defined in filtering objective from app: {}. Not" - + "processing filtering objective", applicationId); - fail(filt, ObjectiveError.UNKNOWN); - return; - } - - // convert filtering conditions for switch-intfs into flowrules - FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); - for (Criterion c : filt.conditions()) { - if (c.type() == Criterion.Type.ETH_DST) { - e = (EthCriterion) c; - } else if (c.type() == Criterion.Type.VLAN_VID) { - v = (VlanIdCriterion) c; - } else if (c.type() == Criterion.Type.IPV4_DST) { - ips.add((IPCriterion) c); - } else { - log.error("Unsupported filter {}", c); - fail(filt, ObjectiveError.UNSUPPORTED); - return; - } - } - - log.debug("adding Port/VLAN/MAC filtering rules in filter table: {}/{}/{}", - p.port(), v.vlanId(), e.mac()); - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); - selector.matchInPort(p.port()); - selector.matchVlanId(v.vlanId()); - selector.matchEthDst(e.mac()); - selector.matchEthType(Ethernet.TYPE_IPV4); - treatment.popVlan(); - treatment.transition(FIB_TABLE); // all other IPs to the FIB table - FlowRule rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(DEFAULT_PRIORITY) - .fromApp(applicationId) - .makePermanent() - .forTable(FILTER_TABLE).build(); - ops = ops.add(rule); - - for (IPCriterion ipaddr : ips) { - log.debug("adding IP filtering rules in FILTER table: {}", ipaddr.ip()); - selector = DefaultTrafficSelector.builder(); - treatment = DefaultTrafficTreatment.builder(); - selector.matchInPort(p.port()); - selector.matchVlanId(v.vlanId()); - selector.matchEthDst(e.mac()); - selector.matchEthType(Ethernet.TYPE_IPV4); - selector.matchIPDst(ipaddr.ip()); // router IPs to the controller - treatment.setOutput(PortNumber.CONTROLLER); - rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(HIGHEST_PRIORITY) - .fromApp(applicationId) - .makePermanent() - .forTable(FILTER_TABLE).build(); - ops = ops.add(rule); - } - - // cache for later use - Filter filter = new Filter(p, e, v, ips); - filters.add(filter); - // apply any pending versatile forwarding objectives - for (ForwardingObjective fwd : pendingVersatiles) { - Collection<FlowRule> ret = processVersatilesWithFilters(filter, fwd); - for (FlowRule fr : ret) { - ops.add(fr); - } - } - - ops = install ? ops.add(rule) : ops.remove(rule); - // apply filtering flow rules - flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - log.info("Applied filtering rules"); - pass(filt); - } - - @Override - public void onError(FlowRuleOperations ops) { - log.info("Failed to apply filtering rules"); - fail(filt, ObjectiveError.FLOWINSTALLATIONFAILED); - } - })); - } - - private Collection<FlowRule> processForward(ForwardingObjective fwd) { - switch (fwd.flag()) { - case SPECIFIC: - return processSpecific(fwd); - case VERSATILE: - return processVersatile(fwd); - default: - fail(fwd, ObjectiveError.UNKNOWN); - log.warn("Unknown forwarding flag {}", fwd.flag()); - } - return Collections.emptySet(); - } - - /** - * SoftRouter has a single versatile table - the filter table. All versatile - * flow rules must include the filtering rules. - * - * @param fwd The forwarding objective of type versatile - * @return A collection of flow rules meant to be delivered to the flowrule - * subsystem. May return empty collection in case of failures. - */ - private Collection<FlowRule> processVersatile(ForwardingObjective fwd) { - if (filters.isEmpty()) { - pendingVersatiles.add(fwd); - return Collections.emptySet(); - } - Collection<FlowRule> flowrules = new ArrayList<FlowRule>(); - for (Filter filter : filters) { - flowrules.addAll(processVersatilesWithFilters(filter, fwd)); - } - return flowrules; - } - - private Collection<FlowRule> processVersatilesWithFilters( - Filter filt, ForwardingObjective fwd) { - log.info("Processing versatile forwarding objective"); - Collection<FlowRule> flows = new ArrayList<FlowRule>(); - TrafficSelector match = fwd.selector(); - EthTypeCriterion ethType = - (EthTypeCriterion) match.getCriterion(Criterion.Type.ETH_TYPE); - if (ethType == null) { - log.error("Versatile forwarding objective must include ethType"); - fail(fwd, ObjectiveError.UNKNOWN); - return Collections.emptySet(); - } - - if (ethType.ethType().toShort() == Ethernet.TYPE_ARP) { - // need to install ARP request & reply flow rules for each interface filter - - // rule for ARP replies - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); - selector.matchInPort(filt.port()); - selector.matchVlanId(filt.vlanId()); - selector.matchEthDst(filt.mac()); - selector.matchEthType(Ethernet.TYPE_ARP); - FlowRule.Builder ruleBuilder = DefaultFlowRule.builder() - .fromApp(fwd.appId()) - .withPriority(fwd.priority()) - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(fwd.treatment()) - .makePermanent() - .forTable(FILTER_TABLE); - flows.add(ruleBuilder.build()); - - //rule for ARP requests - selector = DefaultTrafficSelector.builder(); - selector.matchInPort(filt.port()); - selector.matchVlanId(filt.vlanId()); - selector.matchEthDst(MacAddress.BROADCAST); - selector.matchEthType(Ethernet.TYPE_ARP); - ruleBuilder = DefaultFlowRule.builder() - .fromApp(fwd.appId()) - .withPriority(fwd.priority()) - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(fwd.treatment()) - .makePermanent() - .forTable(FILTER_TABLE); - flows.add(ruleBuilder.build()); - - return flows; - } - // not handling other versatile flows - return Collections.emptySet(); - } - - /** - * SoftRouter has a single specific table - the FIB Table. It emulates - * LPM matching of dstIP by using higher priority flows for longer prefixes. - * Flows are forwarded using flow-actions - * - * @param fwd The forwarding objective of type simple - * @return A collection of flow rules meant to be delivered to the flowrule - * subsystem. Typically the returned collection has a single flowrule. - * May return empty collection in case of failures. - * - */ - private Collection<FlowRule> processSpecific(ForwardingObjective fwd) { - log.debug("Processing specific forwarding objective"); - TrafficSelector selector = fwd.selector(); - EthTypeCriterion ethType = - (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE); - // XXX currently supporting only the L3 unicast table - if (ethType == null || ethType.ethType().toShort() != Ethernet.TYPE_IPV4) { - fail(fwd, ObjectiveError.UNSUPPORTED); - return Collections.emptySet(); - } - - TrafficSelector filteredSelector = - DefaultTrafficSelector.builder() - .matchEthType(Ethernet.TYPE_IPV4) - .matchIPDst(((IPCriterion) - selector.getCriterion(Criterion.Type.IPV4_DST)).ip()) - .build(); - - TrafficTreatment tt = null; - if (fwd.nextId() != null) { - NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId()); - if (next == null) { - log.error("next-id {} does not exist in store", fwd.nextId()); - return Collections.emptySet(); - } - tt = appKryo.deserialize(next.data()); - if (tt == null) { - log.error("Error in deserializing next-id {}", fwd.nextId()); - return Collections.emptySet(); - } - } - - FlowRule.Builder ruleBuilder = DefaultFlowRule.builder() - .fromApp(fwd.appId()) - .withPriority(fwd.priority()) - .forDevice(deviceId) - .withSelector(filteredSelector) - .withTreatment(tt); - - if (fwd.permanent()) { - ruleBuilder.makePermanent(); - } else { - ruleBuilder.makeTemporary(fwd.timeout()); - } - - ruleBuilder.forTable(FIB_TABLE); - return Collections.singletonList(ruleBuilder.build()); - } - - /** - * Next Objectives are stored as dummy groups for retrieval later - * when Forwarding Objectives reference the next objective id. At that point - * the dummy group is fetched from the distributed store and the enclosed - * treatment is applied as a flow rule action. - * - * @param nextObj the next objective of type simple - */ - private void processSimpleNextObjective(NextObjective nextObj) { - // Simple next objective has a single treatment (not a collection) - TrafficTreatment treatment = nextObj.next().iterator().next(); - flowObjectiveStore.putNextGroup(nextObj.id(), - new DummyGroup(treatment)); - } - - private class Filter { - private PortCriterion port; - private VlanIdCriterion vlan; - private EthCriterion eth; - - @SuppressWarnings("unused") - private Collection<IPCriterion> ips; - - public Filter(PortCriterion p, EthCriterion e, VlanIdCriterion v, - Collection<IPCriterion> ips) { - this.eth = e; - this.port = p; - this.vlan = v; - this.ips = ips; - } - - public PortNumber port() { - return port.port(); - } - - public VlanId vlanId() { - return vlan.vlanId(); - } - - public MacAddress mac() { - return eth.mac(); - } - } - - private class DummyGroup implements NextGroup { - TrafficTreatment nextActions; - - public DummyGroup(TrafficTreatment next) { - this.nextActions = next; - } - - @Override - public byte[] data() { - return appKryo.serialize(nextActions); - } - - } - -} diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java deleted file mode 100644 index dba4557a..00000000 --- a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java +++ /dev/null @@ -1,1101 +0,0 @@ -/* - * 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 static org.onlab.util.Tools.groupedThreads; -import static org.slf4j.LoggerFactory.getLogger; - -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.RemovalCause; -import com.google.common.cache.RemovalNotification; - -import org.onlab.osgi.ServiceDirectory; -import org.onlab.packet.Ethernet; -import org.onlab.packet.MacAddress; -import org.onlab.packet.VlanId; -import org.onlab.util.KryoNamespace; -import org.onosproject.core.ApplicationId; -import org.onosproject.core.CoreService; -import org.onosproject.net.DeviceId; -import org.onosproject.net.PortNumber; -import org.onosproject.net.behaviour.NextGroup; -import org.onosproject.net.behaviour.Pipeliner; -import org.onosproject.net.behaviour.PipelinerContext; -import org.onosproject.net.driver.AbstractHandlerBehaviour; -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.Criteria; -import org.onosproject.net.flow.criteria.Criterion; -import org.onosproject.net.flow.criteria.Criterion.Type; -import org.onosproject.net.flow.criteria.EthCriterion; -import org.onosproject.net.flow.criteria.EthTypeCriterion; -import org.onosproject.net.flow.criteria.IPCriterion; -import org.onosproject.net.flow.criteria.MplsCriterion; -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.Instructions.OutputInstruction; -import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction; -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.onosproject.net.group.DefaultGroupBucket; -import org.onosproject.net.group.DefaultGroupDescription; -import org.onosproject.net.group.DefaultGroupKey; -import org.onosproject.net.group.Group; -import org.onosproject.net.group.GroupBucket; -import org.onosproject.net.group.GroupBuckets; -import org.onosproject.net.group.GroupDescription; -import org.onosproject.net.group.GroupEvent; -import org.onosproject.net.group.GroupKey; -import org.onosproject.net.group.GroupListener; -import org.onosproject.net.group.GroupService; -import org.onosproject.store.serializers.KryoNamespaces; -import org.slf4j.Logger; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Set; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; - -/** - * Driver for SPRING-OPEN pipeline. - */ -public class SpringOpenTTP extends AbstractHandlerBehaviour - implements Pipeliner { - - // Default table ID - compatible with CpqD switch - private static final int TABLE_VLAN = 0; - private static final int TABLE_TMAC = 1; - private static final int TABLE_IPV4_UNICAST = 2; - private static final int TABLE_MPLS = 3; - private static final int TABLE_DMAC = 4; - private static final int TABLE_ACL = 5; - private static final int TABLE_SMAC = 6; - - /** - * Set the default values. These variables will get overwritten based on the - * switch vendor type - */ - protected int vlanTableId = TABLE_VLAN; - protected int tmacTableId = TABLE_TMAC; - protected int ipv4UnicastTableId = TABLE_IPV4_UNICAST; - protected int mplsTableId = TABLE_MPLS; - protected int dstMacTableId = TABLE_DMAC; - protected int aclTableId = TABLE_ACL; - protected int srcMacTableId = TABLE_SMAC; - - protected final Logger log = getLogger(getClass()); - - private ServiceDirectory serviceDirectory; - private FlowRuleService flowRuleService; - private CoreService coreService; - protected GroupService groupService; - protected FlowObjectiveStore flowObjectiveStore; - protected DeviceId deviceId; - private ApplicationId appId; - - private Cache<GroupKey, NextObjective> pendingGroups; - - private ScheduledExecutorService groupChecker = Executors - .newScheduledThreadPool(2, - groupedThreads("onos/pipeliner", - "spring-open-%d")); - protected KryoNamespace appKryo = new KryoNamespace.Builder() - .register(KryoNamespaces.API) - .register(GroupKey.class) - .register(DefaultGroupKey.class) - .register(TrafficTreatment.class) - .register(SpringOpenGroup.class) - .register(byte[].class) - .build(); - - @Override - public void init(DeviceId deviceId, PipelinerContext context) { - this.serviceDirectory = context.directory(); - this.deviceId = deviceId; - - pendingGroups = CacheBuilder - .newBuilder() - .expireAfterWrite(20, TimeUnit.SECONDS) - .removalListener((RemovalNotification<GroupKey, NextObjective> notification) -> { - if (notification.getCause() == RemovalCause.EXPIRED) { - fail(notification.getValue(), - ObjectiveError.GROUPINSTALLATIONFAILED); - } - }).build(); - - groupChecker.scheduleAtFixedRate(new GroupChecker(), 0, 500, - TimeUnit.MILLISECONDS); - - coreService = serviceDirectory.get(CoreService.class); - flowRuleService = serviceDirectory.get(FlowRuleService.class); - groupService = serviceDirectory.get(GroupService.class); - flowObjectiveStore = context.store(); - - groupService.addListener(new InnerGroupListener()); - - appId = coreService - .registerApplication("org.onosproject.driver.SpringOpenTTP"); - - setTableMissEntries(); - log.info("Spring Open TTP driver initialized"); - } - - @Override - public void filter(FilteringObjective filteringObjective) { - if (filteringObjective.type() == FilteringObjective.Type.PERMIT) { - log.debug("processing PERMIT filter objective"); - processFilter(filteringObjective, - filteringObjective.op() == Objective.Operation.ADD, - filteringObjective.appId()); - } else { - log.debug("filter objective other than PERMIT not supported"); - fail(filteringObjective, ObjectiveError.UNSUPPORTED); - } - } - - @Override - public void forward(ForwardingObjective fwd) { - Collection<FlowRule> rules; - FlowRuleOperations.Builder flowBuilder = FlowRuleOperations.builder(); - - rules = processForward(fwd); - switch (fwd.op()) { - case ADD: - rules.stream().filter(rule -> rule != null) - .forEach(flowBuilder::add); - break; - case REMOVE: - rules.stream().filter(rule -> rule != null) - .forEach(flowBuilder::remove); - break; - default: - fail(fwd, ObjectiveError.UNKNOWN); - log.warn("Unknown forwarding type {}", fwd.op()); - } - - flowRuleService.apply(flowBuilder - .build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - pass(fwd); - log.debug("Provisioned tables in {} successfully with " - + "forwarding rules", deviceId); - } - - @Override - public void onError(FlowRuleOperations ops) { - fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED); - log.warn("Failed to provision tables in {} with " - + "forwarding rules", deviceId); - } - })); - - } - - @Override - public void next(NextObjective nextObjective) { - NextGroup nextGroup = flowObjectiveStore.getNextGroup(nextObjective.id()); - switch (nextObjective.op()) { - case ADD: - if (nextGroup != null) { - log.warn("Cannot add next {} that already exists in device {}", - nextObjective.id(), deviceId); - return; - } - log.debug("Processing NextObjective id{} in dev{} - add group", - nextObjective.id(), deviceId); - addGroup(nextObjective); - break; - case ADD_TO_EXISTING: - if (nextGroup != null) { - log.debug("Processing NextObjective id{} in dev{} - add bucket", - nextObjective.id(), deviceId); - addBucketToGroup(nextObjective); - } else { - log.warn("Cannot add to group that does not exist"); - } - break; - case REMOVE: - if (nextGroup == null) { - log.warn("Cannot remove next {} that does not exist in device {}", - nextObjective.id(), deviceId); - return; - } - log.debug("Processing NextObjective id{} in dev{} - remove group", - nextObjective.id(), deviceId); - removeGroup(nextObjective); - break; - case REMOVE_FROM_EXISTING: - if (nextGroup == null) { - log.warn("Cannot remove from next {} that does not exist in device {}", - nextObjective.id(), deviceId); - return; - } - log.debug("Processing NextObjective id{} in dev{} - remove bucket", - nextObjective.id(), deviceId); - removeBucketFromGroup(nextObjective); - break; - default: - log.warn("Unsupported operation {}", nextObjective.op()); - } - } - - private void removeGroup(NextObjective nextObjective) { - log.debug("removeGroup in {}: for next objective id {}", - deviceId, nextObjective.id()); - final GroupKey key = new DefaultGroupKey( - appKryo.serialize(nextObjective.id())); - groupService.removeGroup(deviceId, key, appId); - } - - private void addGroup(NextObjective nextObjective) { - log.debug("addGroup with type{} for nextObjective id {}", - nextObjective.type(), nextObjective.id()); - List<GroupBucket> buckets; - switch (nextObjective.type()) { - case SIMPLE: - Collection<TrafficTreatment> treatments = nextObjective.next(); - if (treatments.size() == 1) { - // Spring Open TTP converts simple nextObjective to flow-actions - // in a dummy group - TrafficTreatment treatment = nextObjective.next().iterator().next(); - log.debug("Converting SIMPLE group for next objective id {} " + - "to {} flow-actions in device:{}", nextObjective.id(), - treatment.allInstructions().size(), deviceId); - flowObjectiveStore.putNextGroup(nextObjective.id(), - new SpringOpenGroup(null, treatment)); - } - break; - case HASHED: - // we convert MPLS ECMP groups to flow-actions for a single - // bucket(output port). - boolean mplsEcmp = false; - if (nextObjective.meta() != null) { - for (Criterion c : nextObjective.meta().criteria()) { - if (c.type() == Type.MPLS_LABEL) { - mplsEcmp = true; - } - } - } - if (mplsEcmp) { - // covert to flow-actions in a dummy group by choosing the first bucket - log.debug("Converting HASHED group for next objective id {} " + - "to flow-actions in device:{}", nextObjective.id(), - deviceId); - TrafficTreatment treatment = nextObjective.next().iterator().next(); - flowObjectiveStore.putNextGroup(nextObjective.id(), - new SpringOpenGroup(null, treatment)); - } else { - // process as ECMP group - buckets = nextObjective - .next() - .stream() - .map((treatment) -> DefaultGroupBucket - .createSelectGroupBucket(treatment)) - .collect(Collectors.toList()); - if (!buckets.isEmpty()) { - final GroupKey key = new DefaultGroupKey( - appKryo.serialize(nextObjective.id())); - GroupDescription groupDescription = new DefaultGroupDescription( - deviceId, - GroupDescription.Type.SELECT, - new GroupBuckets(buckets), - key, - null, - nextObjective.appId()); - log.debug("Creating HASHED group for next objective id {}" - + " in dev:{}", nextObjective.id(), deviceId); - pendingGroups.put(key, nextObjective); - groupService.addGroup(groupDescription); - } - } - break; - case BROADCAST: - buckets = nextObjective - .next() - .stream() - .map((treatment) -> DefaultGroupBucket - .createAllGroupBucket(treatment)) - .collect(Collectors.toList()); - if (!buckets.isEmpty()) { - final GroupKey key = new DefaultGroupKey( - appKryo.serialize(nextObjective - .id())); - GroupDescription groupDescription = new DefaultGroupDescription( - deviceId, - GroupDescription.Type.ALL, - new GroupBuckets(buckets), - key, - null, - nextObjective.appId()); - log.debug("Creating BROADCAST group for next objective id {} " - + "in device {}", nextObjective.id(), deviceId); - pendingGroups.put(key, nextObjective); - groupService.addGroup(groupDescription); - } - break; - case FAILOVER: - log.debug("FAILOVER next objectives not supported"); - fail(nextObjective, ObjectiveError.UNSUPPORTED); - log.warn("Unsupported next objective type {}", nextObjective.type()); - break; - default: - fail(nextObjective, ObjectiveError.UNKNOWN); - log.warn("Unknown next objective type {}", nextObjective.type()); - } - } - - private void addBucketToGroup(NextObjective nextObjective) { - log.debug("addBucketToGroup in {}: for next objective id {}", - deviceId, nextObjective.id()); - Collection<TrafficTreatment> treatments = nextObjective.next(); - TrafficTreatment treatment = treatments.iterator().next(); - final GroupKey key = new DefaultGroupKey( - appKryo.serialize(nextObjective - .id())); - Group group = groupService.getGroup(deviceId, key); - if (group == null) { - log.warn("Group is not found in {} for {}", deviceId, key); - return; - } - GroupBucket bucket; - if (group.type() == GroupDescription.Type.INDIRECT) { - bucket = DefaultGroupBucket.createIndirectGroupBucket(treatment); - } else if (group.type() == GroupDescription.Type.SELECT) { - bucket = DefaultGroupBucket.createSelectGroupBucket(treatment); - } else if (group.type() == GroupDescription.Type.ALL) { - bucket = DefaultGroupBucket.createAllGroupBucket(treatment); - } else { - log.warn("Unsupported Group type {}", group.type()); - return; - } - GroupBuckets bucketsToAdd = new GroupBuckets(Collections.singletonList(bucket)); - log.debug("Adding buckets to group id {} of next objective id {} in device {}", - group.id(), nextObjective.id(), deviceId); - groupService.addBucketsToGroup(deviceId, key, bucketsToAdd, key, appId); - } - - private void removeBucketFromGroup(NextObjective nextObjective) { - log.debug("removeBucketFromGroup in {}: for next objective id {}", - deviceId, nextObjective.id()); - NextGroup nextGroup = flowObjectiveStore.getNextGroup(nextObjective.id()); - if (nextGroup != null) { - Collection<TrafficTreatment> treatments = nextObjective.next(); - TrafficTreatment treatment = treatments.iterator().next(); - final GroupKey key = new DefaultGroupKey( - appKryo.serialize(nextObjective - .id())); - Group group = groupService.getGroup(deviceId, key); - if (group == null) { - log.warn("Group is not found in {} for {}", deviceId, key); - return; - } - GroupBucket bucket; - if (group.type() == GroupDescription.Type.INDIRECT) { - bucket = DefaultGroupBucket.createIndirectGroupBucket(treatment); - } else if (group.type() == GroupDescription.Type.SELECT) { - bucket = DefaultGroupBucket.createSelectGroupBucket(treatment); - } else if (group.type() == GroupDescription.Type.ALL) { - bucket = DefaultGroupBucket.createAllGroupBucket(treatment); - } else { - log.warn("Unsupported Group type {}", group.type()); - return; - } - GroupBuckets removeBuckets = new GroupBuckets(Collections.singletonList(bucket)); - log.debug("Removing buckets from group id {} of next objective id {} in device {}", - group.id(), nextObjective.id(), deviceId); - groupService.removeBucketsFromGroup(deviceId, key, removeBuckets, key, appId); - } - } - - private Collection<FlowRule> processForward(ForwardingObjective fwd) { - switch (fwd.flag()) { - case SPECIFIC: - return processSpecific(fwd); - case VERSATILE: - return processVersatile(fwd); - default: - fail(fwd, ObjectiveError.UNKNOWN); - log.warn("Unknown forwarding flag {}", fwd.flag()); - } - return Collections.emptySet(); - } - - private Collection<FlowRule> processVersatile(ForwardingObjective fwd) { - log.debug("Processing versatile forwarding objective in dev:{}", deviceId); - TrafficSelector selector = fwd.selector(); - EthTypeCriterion ethType = - (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE); - if (ethType == null) { - log.error("Versatile forwarding objective must include ethType"); - fail(fwd, ObjectiveError.UNKNOWN); - return Collections.emptySet(); - } - - if (fwd.treatment() == null && fwd.nextId() == null) { - log.error("VERSATILE forwarding objective needs next objective ID " - + "or treatment."); - return Collections.emptySet(); - } - // emulation of ACL table (for versatile fwd objective) requires - // overriding any previous instructions - TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment - .builder(); - treatmentBuilder.wipeDeferred(); - - if (fwd.nextId() != null) { - NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId()); - if (next != null) { - SpringOpenGroup soGroup = appKryo.deserialize(next.data()); - if (soGroup.dummy) { - // need to convert to flow-actions - for (Instruction ins : soGroup.treatment.allInstructions()) { - treatmentBuilder.add(ins); - } - } else { - GroupKey key = soGroup.key; - Group group = groupService.getGroup(deviceId, key); - if (group == null) { - log.warn("The group left!"); - fail(fwd, ObjectiveError.GROUPMISSING); - return Collections.emptySet(); - } - treatmentBuilder.deferred().group(group.id()); - log.debug("Adding OUTGROUP action"); - } - } - } - - if (fwd.treatment() != null) { - if (fwd.treatment().allInstructions().size() == 1 && - fwd.treatment().allInstructions().get(0).type() == Instruction.Type.OUTPUT) { - OutputInstruction o = (OutputInstruction) fwd.treatment().allInstructions().get(0); - if (o.port() == PortNumber.CONTROLLER) { - treatmentBuilder.punt(); - } else { - treatmentBuilder.add(o); - } - } else { - for (Instruction ins : fwd.treatment().allInstructions()) { - treatmentBuilder.add(ins); - } - } - } - - FlowRule.Builder ruleBuilder = DefaultFlowRule.builder() - .fromApp(fwd.appId()).withPriority(fwd.priority()) - .forDevice(deviceId).withSelector(fwd.selector()) - .withTreatment(treatmentBuilder.build()); - - if (fwd.permanent()) { - ruleBuilder.makePermanent(); - } else { - ruleBuilder.makeTemporary(fwd.timeout()); - } - - ruleBuilder.forTable(aclTableId); - return Collections.singletonList(ruleBuilder.build()); - } - - private boolean isSupportedEthTypeObjective(ForwardingObjective fwd) { - TrafficSelector selector = fwd.selector(); - EthTypeCriterion ethType = (EthTypeCriterion) selector - .getCriterion(Criterion.Type.ETH_TYPE); - if ((ethType == null) || - ((ethType.ethType().toShort() != Ethernet.TYPE_IPV4) && - (ethType.ethType().toShort() != Ethernet.MPLS_UNICAST))) { - return false; - } - return true; - } - - private boolean isSupportedEthDstObjective(ForwardingObjective fwd) { - TrafficSelector selector = fwd.selector(); - EthCriterion ethDst = (EthCriterion) selector - .getCriterion(Criterion.Type.ETH_DST); - VlanIdCriterion vlanId = (VlanIdCriterion) selector - .getCriterion(Criterion.Type.VLAN_VID); - if (ethDst == null && vlanId == null) { - return false; - } - return true; - } - - protected Collection<FlowRule> processSpecific(ForwardingObjective fwd) { - log.debug("Processing specific fwd objective:{} in dev:{} with next:{}", - fwd.id(), deviceId, fwd.nextId()); - boolean isEthTypeObj = isSupportedEthTypeObjective(fwd); - boolean isEthDstObj = isSupportedEthDstObjective(fwd); - - if (isEthTypeObj) { - return processEthTypeSpecificObjective(fwd); - } else if (isEthDstObj) { - return processEthDstSpecificObjective(fwd); - } else { - log.warn("processSpecific: Unsupported " - + "forwarding objective criteria"); - fail(fwd, ObjectiveError.UNSUPPORTED); - return Collections.emptySet(); - } - } - - protected Collection<FlowRule> - processEthTypeSpecificObjective(ForwardingObjective fwd) { - TrafficSelector selector = fwd.selector(); - EthTypeCriterion ethType = (EthTypeCriterion) selector - .getCriterion(Criterion.Type.ETH_TYPE); - - TrafficSelector.Builder filteredSelectorBuilder = - DefaultTrafficSelector.builder(); - int forTableId = -1; - if (ethType.ethType().toShort() == Ethernet.TYPE_IPV4) { - filteredSelectorBuilder = filteredSelectorBuilder - .matchEthType(Ethernet.TYPE_IPV4) - .matchIPDst(((IPCriterion) selector - .getCriterion(Criterion.Type.IPV4_DST)) - .ip()); - forTableId = ipv4UnicastTableId; - log.debug("processing IPv4 specific forwarding objective:{} in dev:{}", - fwd.id(), deviceId); - } else { - filteredSelectorBuilder = filteredSelectorBuilder - .matchEthType(Ethernet.MPLS_UNICAST) - .matchMplsLabel(((MplsCriterion) - selector.getCriterion(Criterion.Type.MPLS_LABEL)).label()); - //TODO: Add Match for BoS - //if (selector.getCriterion(Criterion.Type.MPLS_BOS) != null) { - //} - forTableId = mplsTableId; - log.debug("processing MPLS specific forwarding objective:{} in dev:{}", - fwd.id(), deviceId); - } - - TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment - .builder(); - if (fwd.treatment() != null) { - for (Instruction i : fwd.treatment().allInstructions()) { - treatmentBuilder.add(i); - } - } - - if (fwd.nextId() != null) { - NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId()); - if (next != null) { - SpringOpenGroup soGroup = appKryo.deserialize(next.data()); - if (soGroup.dummy) { - log.debug("Adding {} flow-actions for fwd. obj. {} -> next:{} " - + "in dev: {}", soGroup.treatment.allInstructions().size(), - fwd.id(), fwd.nextId(), deviceId); - for (Instruction ins : soGroup.treatment.allInstructions()) { - treatmentBuilder.add(ins); - } - } else { - GroupKey key = soGroup.key; - Group group = groupService.getGroup(deviceId, key); - if (group == null) { - log.warn("The group left!"); - fail(fwd, ObjectiveError.GROUPMISSING); - return Collections.emptySet(); - } - treatmentBuilder.deferred().group(group.id()); - log.debug("Adding OUTGROUP action to group:{} for fwd. obj. {} " - + "for next:{} in dev: {}", group.id(), fwd.id(), - fwd.nextId(), deviceId); - } - } else { - log.warn("processSpecific: No associated next objective object"); - fail(fwd, ObjectiveError.GROUPMISSING); - return Collections.emptySet(); - } - } - - TrafficSelector filteredSelector = filteredSelectorBuilder.build(); - TrafficTreatment treatment = treatmentBuilder.transition(aclTableId) - .build(); - - FlowRule.Builder ruleBuilder = DefaultFlowRule.builder() - .fromApp(fwd.appId()).withPriority(fwd.priority()) - .forDevice(deviceId).withSelector(filteredSelector) - .withTreatment(treatment); - - if (fwd.permanent()) { - ruleBuilder.makePermanent(); - } else { - ruleBuilder.makeTemporary(fwd.timeout()); - } - - ruleBuilder.forTable(forTableId); - return Collections.singletonList(ruleBuilder.build()); - - } - - protected Collection<FlowRule> - processEthDstSpecificObjective(ForwardingObjective fwd) { - List<FlowRule> rules = new ArrayList<>(); - - // Build filtered selector - TrafficSelector selector = fwd.selector(); - EthCriterion ethCriterion = (EthCriterion) selector - .getCriterion(Criterion.Type.ETH_DST); - VlanIdCriterion vlanIdCriterion = (VlanIdCriterion) selector - .getCriterion(Criterion.Type.VLAN_VID); - TrafficSelector.Builder filteredSelectorBuilder = - DefaultTrafficSelector.builder(); - // Do not match MacAddress for subnet broadcast entry - if (!ethCriterion.mac().equals(MacAddress.NONE)) { - filteredSelectorBuilder.matchEthDst(ethCriterion.mac()); - log.debug("processing L2 forwarding objective:{} in dev:{}", - fwd.id(), deviceId); - } else { - log.debug("processing L2 Broadcast forwarding objective:{} " - + "in dev:{} for vlan:{}", - fwd.id(), deviceId, vlanIdCriterion.vlanId()); - } - filteredSelectorBuilder.matchVlanId(vlanIdCriterion.vlanId()); - TrafficSelector filteredSelector = filteredSelectorBuilder.build(); - - // Build filtered treatment - TrafficTreatment.Builder treatmentBuilder = - DefaultTrafficTreatment.builder(); - if (fwd.treatment() != null) { - treatmentBuilder.deferred(); - fwd.treatment().allInstructions().forEach(treatmentBuilder::add); - } - if (fwd.nextId() != null) { - NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId()); - if (next != null) { - SpringOpenGroup soGrp = appKryo.deserialize(next.data()); - if (soGrp.dummy) { - log.debug("Adding {} flow-actions for fwd. obj. {} " - + "in dev: {}", soGrp.treatment.allInstructions().size(), - fwd.id(), deviceId); - for (Instruction ins : soGrp.treatment.allInstructions()) { - treatmentBuilder.deferred().add(ins); - } - } else { - GroupKey key = soGrp.key; - Group group = groupService.getGroup(deviceId, key); - if (group == null) { - log.warn("The group left!"); - fail(fwd, ObjectiveError.GROUPMISSING); - return Collections.emptySet(); - } - treatmentBuilder.deferred().group(group.id()); - log.debug("Adding OUTGROUP action to group:{} for fwd. obj. {} " - + "in dev: {}", group.id(), fwd.id(), deviceId); - } - } - } - treatmentBuilder.immediate().transition(aclTableId); - TrafficTreatment filteredTreatment = treatmentBuilder.build(); - - // Build bridging table entries - FlowRule.Builder flowRuleBuilder = DefaultFlowRule.builder(); - flowRuleBuilder.fromApp(fwd.appId()) - .withPriority(fwd.priority()) - .forDevice(deviceId) - .withSelector(filteredSelector) - .withTreatment(filteredTreatment) - .forTable(dstMacTableId); - if (fwd.permanent()) { - flowRuleBuilder.makePermanent(); - } else { - flowRuleBuilder.makeTemporary(fwd.timeout()); - } - rules.add(flowRuleBuilder.build()); - - /* - // TODO Emulate source MAC table behavior - // Do not install source MAC table entry for subnet broadcast - if (!ethCriterion.mac().equals(MacAddress.NONE)) { - // Build filtered selector - selector = fwd.selector(); - ethCriterion = (EthCriterion) selector.getCriterion(Criterion.Type.ETH_DST); - filteredSelectorBuilder = DefaultTrafficSelector.builder(); - filteredSelectorBuilder.matchEthSrc(ethCriterion.mac()); - filteredSelector = filteredSelectorBuilder.build(); - - // Build empty treatment. Apply existing instruction if match. - treatmentBuilder = DefaultTrafficTreatment.builder(); - filteredTreatment = treatmentBuilder.build(); - - // Build bridging table entries - flowRuleBuilder = DefaultFlowRule.builder(); - flowRuleBuilder.fromApp(fwd.appId()) - .withPriority(fwd.priority()) - .forDevice(deviceId) - .withSelector(filteredSelector) - .withTreatment(filteredTreatment) - .forTable(srcMacTableId) - .makePermanent(); - rules.add(flowRuleBuilder.build()); - } - */ - - return rules; - } - - /* - * Note: CpqD switches do not handle MPLS-related operation properly - * for a packet with VLAN tag. We pop VLAN here as a workaround. - * Side effect: HostService learns redundant hosts with same MAC but - * different VLAN. No known side effect on the network reachability. - */ - protected List<FlowRule> processEthDstFilter(EthCriterion ethCriterion, - VlanIdCriterion vlanIdCriterion, - FilteringObjective filt, - VlanId assignedVlan, - ApplicationId applicationId) { - //handling untagged packets via assigned VLAN - if (vlanIdCriterion.vlanId() == VlanId.NONE) { - vlanIdCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan); - } - - List<FlowRule> rules = new ArrayList<>(); - TrafficSelector.Builder selectorIp = DefaultTrafficSelector - .builder(); - TrafficTreatment.Builder treatmentIp = DefaultTrafficTreatment - .builder(); - selectorIp.matchEthDst(ethCriterion.mac()); - selectorIp.matchEthType(Ethernet.TYPE_IPV4); - selectorIp.matchVlanId(vlanIdCriterion.vlanId()); - treatmentIp.popVlan(); - treatmentIp.transition(ipv4UnicastTableId); - FlowRule ruleIp = DefaultFlowRule.builder().forDevice(deviceId) - .withSelector(selectorIp.build()) - .withTreatment(treatmentIp.build()) - .withPriority(filt.priority()).fromApp(applicationId) - .makePermanent().forTable(tmacTableId).build(); - log.debug("adding IP ETH rule for MAC: {}", ethCriterion.mac()); - rules.add(ruleIp); - - TrafficSelector.Builder selectorMpls = DefaultTrafficSelector - .builder(); - TrafficTreatment.Builder treatmentMpls = DefaultTrafficTreatment - .builder(); - selectorMpls.matchEthDst(ethCriterion.mac()); - selectorMpls.matchEthType(Ethernet.MPLS_UNICAST); - selectorMpls.matchVlanId(vlanIdCriterion.vlanId()); - treatmentMpls.popVlan(); - treatmentMpls.transition(mplsTableId); - FlowRule ruleMpls = DefaultFlowRule.builder() - .forDevice(deviceId).withSelector(selectorMpls.build()) - .withTreatment(treatmentMpls.build()) - .withPriority(filt.priority()).fromApp(applicationId) - .makePermanent().forTable(tmacTableId).build(); - log.debug("adding MPLS ETH rule for MAC: {}", ethCriterion.mac()); - rules.add(ruleMpls); - - return rules; - } - - protected List<FlowRule> processVlanIdFilter(VlanIdCriterion vlanIdCriterion, - FilteringObjective filt, - VlanId assignedVlan, - ApplicationId applicationId) { - List<FlowRule> rules = new ArrayList<>(); - log.debug("adding rule for VLAN: {}", vlanIdCriterion.vlanId()); - TrafficSelector.Builder selector = DefaultTrafficSelector - .builder(); - TrafficTreatment.Builder treatment = DefaultTrafficTreatment - .builder(); - PortCriterion p = (PortCriterion) filt.key(); - if (vlanIdCriterion.vlanId() != VlanId.NONE) { - selector.matchVlanId(vlanIdCriterion.vlanId()); - selector.matchInPort(p.port()); - treatment.deferred().popVlan(); - } else { - selector.matchInPort(p.port()); - treatment.immediate().pushVlan().setVlanId(assignedVlan); - } - treatment.transition(tmacTableId); - FlowRule rule = DefaultFlowRule.builder().forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(filt.priority()).fromApp(applicationId) - .makePermanent().forTable(vlanTableId).build(); - rules.add(rule); - - return rules; - } - - private void processFilter(FilteringObjective filt, boolean install, - ApplicationId applicationId) { - // This driver only processes filtering criteria defined with switch - // ports as the key - if (filt.key().equals(Criteria.dummy()) - || filt.key().type() != Criterion.Type.IN_PORT) { - log.warn("No key defined in filtering objective from app: {}. Not" - + "processing filtering objective", applicationId); - fail(filt, ObjectiveError.UNKNOWN); - return; - } - - EthCriterion ethCriterion = null; - VlanIdCriterion vlanIdCriterion = null; - - // convert filtering conditions for switch-intfs into flowrules - FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); - - for (Criterion criterion : filt.conditions()) { - if (criterion.type() == Criterion.Type.ETH_DST) { - ethCriterion = (EthCriterion) criterion; - } else if (criterion.type() == Criterion.Type.VLAN_VID) { - vlanIdCriterion = (VlanIdCriterion) criterion; - } else if (criterion.type() == Criterion.Type.IPV4_DST) { - log.debug("driver does not process IP filtering rules as it " + - "sends all misses in the IP table to the controller"); - } else { - log.warn("Driver does not currently process filtering condition" - + " of type: {}", criterion.type()); - fail(filt, ObjectiveError.UNSUPPORTED); - } - } - - VlanId assignedVlan = null; - if (vlanIdCriterion != null && vlanIdCriterion.vlanId() == VlanId.NONE) { - // Assign a VLAN ID to untagged packets - if (filt.meta() == null) { - log.error("Missing metadata in filtering objective required " - + "for vlan assignment in dev {}", deviceId); - fail(filt, ObjectiveError.BADPARAMS); - return; - } - for (Instruction i : filt.meta().allInstructions()) { - if (i instanceof ModVlanIdInstruction) { - assignedVlan = ((ModVlanIdInstruction) i).vlanId(); - } - } - if (assignedVlan == null) { - log.error("Driver requires an assigned vlan-id to tag incoming " - + "untagged packets. Not processing vlan filters on " - + "device {}", deviceId); - fail(filt, ObjectiveError.BADPARAMS); - return; - } - } - - if (ethCriterion == null) { - log.debug("filtering objective missing dstMac, cannot program TMAC table"); - } else { - for (FlowRule tmacRule : processEthDstFilter(ethCriterion, - vlanIdCriterion, - filt, - assignedVlan, - applicationId)) { - log.debug("adding MAC filtering rules in TMAC table: {} for dev: {}", - tmacRule, deviceId); - ops = install ? ops.add(tmacRule) : ops.remove(tmacRule); - } - } - - if (ethCriterion == null || vlanIdCriterion == null) { - log.debug("filtering objective missing dstMac or vlan, cannot program" - + "Vlan Table"); - } else { - for (FlowRule vlanRule : processVlanIdFilter(vlanIdCriterion, - filt, - assignedVlan, - applicationId)) { - log.debug("adding VLAN filtering rule in VLAN table: {} for dev: {}", - vlanRule, deviceId); - ops = install ? ops.add(vlanRule) : ops.remove(vlanRule); - } - } - - // apply filtering flow rules - flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - pass(filt); - log.debug("Provisioned tables in {} with fitering " - + "rules", deviceId); - } - - @Override - public void onError(FlowRuleOperations ops) { - fail(filt, ObjectiveError.FLOWINSTALLATIONFAILED); - log.warn("Failed to provision tables in {} with " - + "fitering rules", deviceId); - } - })); - } - - protected void setTableMissEntries() { - // set all table-miss-entries - populateTableMissEntry(vlanTableId, true, false, false, -1); - populateTableMissEntry(tmacTableId, false, false, true, dstMacTableId); - populateTableMissEntry(ipv4UnicastTableId, false, true, true, aclTableId); - populateTableMissEntry(mplsTableId, false, true, true, aclTableId); - populateTableMissEntry(dstMacTableId, false, false, true, aclTableId); - populateTableMissEntry(aclTableId, false, false, false, -1); - } - - protected void populateTableMissEntry(int tableToAdd, - boolean toControllerNow, - boolean toControllerWrite, - boolean toTable, int tableToSend) { - TrafficSelector selector = DefaultTrafficSelector.builder().build(); - TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder(); - - if (toControllerNow) { - tBuilder.setOutput(PortNumber.CONTROLLER); - } - - if (toControllerWrite) { - tBuilder.deferred().setOutput(PortNumber.CONTROLLER); - } - - if (toTable) { - tBuilder.transition(tableToSend); - } - - FlowRule flow = DefaultFlowRule.builder().forDevice(deviceId) - .withSelector(selector).withTreatment(tBuilder.build()) - .withPriority(0).fromApp(appId).makePermanent() - .forTable(tableToAdd).build(); - - flowRuleService.applyFlowRules(flow); - } - - private void pass(Objective obj) { - if (obj.context().isPresent()) { - obj.context().get().onSuccess(obj); - } - } - - protected void fail(Objective obj, ObjectiveError error) { - if (obj.context().isPresent()) { - obj.context().get().onError(obj, error); - } - } - - private class InnerGroupListener implements GroupListener { - @Override - public void event(GroupEvent event) { - if (event.type() == GroupEvent.Type.GROUP_ADDED) { - log.trace("InnerGroupListener: Group ADDED " - + "event received in device {}", deviceId); - GroupKey key = event.subject().appCookie(); - - NextObjective obj = pendingGroups.getIfPresent(key); - if (obj != null) { - log.debug("Group verified: dev:{} gid:{} <<->> nextId:{}", - deviceId, event.subject().id(), obj.id()); - flowObjectiveStore - .putNextGroup(obj.id(), - new SpringOpenGroup(key, null)); - pass(obj); - pendingGroups.invalidate(key); - } - } else if (event.type() == GroupEvent.Type.GROUP_ADD_FAILED) { - log.warn("InnerGroupListener: Group ADD " - + "failed event received in device {}", deviceId); - } - } - } - - private class GroupChecker implements Runnable { - - @Override - public void run() { - Set<GroupKey> keys = pendingGroups - .asMap() - .keySet() - .stream() - .filter(key -> groupService.getGroup(deviceId, key) != null) - .collect(Collectors.toSet()); - - keys.stream() - .forEach(key -> { - NextObjective obj = pendingGroups - .getIfPresent(key); - if (obj == null) { - return; - } - log.debug("Group verified: dev:{} gid:{} <<->> nextId:{}", - deviceId, - groupService.getGroup(deviceId, key).id(), - obj.id()); - pass(obj); - pendingGroups.invalidate(key); - flowObjectiveStore.putNextGroup( - obj.id(), - new SpringOpenGroup(key, null)); - }); - } - } - - /** - * SpringOpenGroup can either serve as storage for a GroupKey which can be - * used to fetch the group from the Group Service, or it can be serve as storage - * for Traffic Treatments which can be used as flow actions. In the latter - * case, we refer to this as a dummy group. - * - */ - private class SpringOpenGroup implements NextGroup { - private final boolean dummy; - private final GroupKey key; - private final TrafficTreatment treatment; - - /** - * Storage for a GroupKey or a TrafficTreatment. One of the params - * to this constructor must be null. - * @param key represents a GroupKey - * @param treatment represents flow actions in a dummy group - */ - public SpringOpenGroup(GroupKey key, TrafficTreatment treatment) { - if (key == null) { - this.key = new DefaultGroupKey(new byte[]{0}); - this.treatment = treatment; - this.dummy = true; - } else { - this.key = key; - this.treatment = DefaultTrafficTreatment.builder().build(); - this.dummy = false; - } - } - - @SuppressWarnings("unused") - public GroupKey key() { - return key; - } - - @Override - public byte[] data() { - return appKryo.serialize(this); - } - - } -} diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTPDell.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTPDell.java deleted file mode 100644 index 91f2679c..00000000 --- a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTPDell.java +++ /dev/null @@ -1,204 +0,0 @@ -/* - * 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 java.util.Collection; -import java.util.Collections; -import java.util.List; - -import org.onlab.packet.Ethernet; -import org.onlab.packet.MacAddress; -import org.onlab.packet.VlanId; -import org.onosproject.core.ApplicationId; -import org.onosproject.net.behaviour.NextGroup; -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.EthTypeCriterion; -import org.onosproject.net.flow.criteria.IPCriterion; -import org.onosproject.net.flow.criteria.MplsCriterion; -import org.onosproject.net.flow.criteria.VlanIdCriterion; -import org.onosproject.net.flow.instructions.Instruction; -import org.onosproject.net.flowobjective.FilteringObjective; -import org.onosproject.net.flowobjective.ForwardingObjective; -import org.onosproject.net.flowobjective.ObjectiveError; -import org.onosproject.net.group.Group; -import org.onosproject.net.group.GroupKey; - -/** - * Spring-open driver implementation for Dell hardware switches. - */ -public class SpringOpenTTPDell extends SpringOpenTTP { - - /* Table IDs to be used for Dell Open Segment Routers*/ - private static final int DELL_TABLE_VLAN = 17; - private static final int DELL_TABLE_TMAC = 18; - private static final int DELL_TABLE_IPV4_UNICAST = 30; - private static final int DELL_TABLE_MPLS = 25; - private static final int DELL_TABLE_ACL = 40; - - //TODO: Store this info in the distributed store. - private MacAddress deviceTMac = null; - - public SpringOpenTTPDell() { - super(); - vlanTableId = DELL_TABLE_VLAN; - tmacTableId = DELL_TABLE_TMAC; - ipv4UnicastTableId = DELL_TABLE_IPV4_UNICAST; - mplsTableId = DELL_TABLE_MPLS; - aclTableId = DELL_TABLE_ACL; - } - - @Override - protected void setTableMissEntries() { - // No need to set table-miss-entries in Dell switches - return; - } - - @Override - //Dell switches need ETH_DST based match condition in all IP table entries. - //So this method overrides the default spring-open behavior and adds - //ETH_DST match condition while pushing IP table flow rules - protected Collection<FlowRule> processSpecific(ForwardingObjective fwd) { - log.debug("Processing specific"); - TrafficSelector selector = fwd.selector(); - EthTypeCriterion ethType = (EthTypeCriterion) selector - .getCriterion(Criterion.Type.ETH_TYPE); - if ((ethType == null) || - (ethType.ethType().toShort() != Ethernet.TYPE_IPV4) && - (ethType.ethType().toShort() != Ethernet.MPLS_UNICAST)) { - log.debug("processSpecific: Unsupported " - + "forwarding objective criteraia"); - fail(fwd, ObjectiveError.UNSUPPORTED); - return Collections.emptySet(); - } - - TrafficSelector.Builder filteredSelectorBuilder = - DefaultTrafficSelector.builder(); - int forTableId = -1; - if (ethType.ethType().toShort() == Ethernet.TYPE_IPV4) { - if (deviceTMac == null) { - log.debug("processSpecific: ETH_DST filtering " - + "objective is not set which is required " - + "before sending a IPv4 forwarding objective"); - //TODO: Map the error to more appropriate error code. - fail(fwd, ObjectiveError.DEVICEMISSING); - return Collections.emptySet(); - } - filteredSelectorBuilder = filteredSelectorBuilder - .matchEthType(Ethernet.TYPE_IPV4) - .matchEthDst(deviceTMac) - .matchIPDst(((IPCriterion) selector - .getCriterion(Criterion.Type.IPV4_DST)) - .ip()); - forTableId = ipv4UnicastTableId; - log.debug("processing IPv4 specific forwarding objective"); - } else { - filteredSelectorBuilder = filteredSelectorBuilder - .matchEthType(Ethernet.MPLS_UNICAST) - .matchMplsLabel(((MplsCriterion) - selector.getCriterion(Criterion.Type.MPLS_LABEL)).label()); - //TODO: Add Match for BoS - //if (selector.getCriterion(Criterion.Type.MPLS_BOS) != null) { - //} - forTableId = mplsTableId; - log.debug("processing MPLS specific forwarding objective"); - } - - TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment - .builder(); - if (fwd.treatment() != null) { - for (Instruction i : fwd.treatment().allInstructions()) { - treatmentBuilder.add(i); - } - } - - if (fwd.nextId() != null) { - NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId()); - - if (next != null) { - GroupKey key = appKryo.deserialize(next.data()); - - Group group = groupService.getGroup(deviceId, key); - - if (group == null) { - log.warn("The group left!"); - fail(fwd, ObjectiveError.GROUPMISSING); - return Collections.emptySet(); - } - treatmentBuilder.group(group.id()); - log.debug("Adding OUTGROUP action"); - } else { - log.warn("processSpecific: No associated next objective object"); - fail(fwd, ObjectiveError.GROUPMISSING); - return Collections.emptySet(); - } - } - - TrafficSelector filteredSelector = filteredSelectorBuilder.build(); - TrafficTreatment treatment = treatmentBuilder.transition(aclTableId) - .build(); - - FlowRule.Builder ruleBuilder = DefaultFlowRule.builder() - .fromApp(fwd.appId()).withPriority(fwd.priority()) - .forDevice(deviceId).withSelector(filteredSelector) - .withTreatment(treatment); - - if (fwd.permanent()) { - ruleBuilder.makePermanent(); - } else { - ruleBuilder.makeTemporary(fwd.timeout()); - } - - ruleBuilder.forTable(forTableId); - return Collections.singletonList(ruleBuilder.build()); - - } - - @Override - //Dell switches need ETH_DST based match condition in all IP table entries. - //So while processing the ETH_DST based filtering objective, store - //the device MAC to be used locally to use it while pushing the IP rules. - protected List<FlowRule> processEthDstFilter(EthCriterion ethCriterion, - VlanIdCriterion vlanIdCriterion, - FilteringObjective filt, - VlanId assignedVlan, - ApplicationId applicationId) { - // Store device termination Mac to be used in IP flow entries - deviceTMac = ethCriterion.mac(); - - log.debug("For now not adding any TMAC rules " - + "into Dell switches as it is ignoring"); - - return Collections.emptyList(); - } - - @Override - protected List<FlowRule> processVlanIdFilter(VlanIdCriterion vlanIdCriterion, - FilteringObjective filt, - VlanId assignedVlan, - ApplicationId applicationId) { - log.debug("For now not adding any VLAN rules " - + "into Dell switches as it is ignoring"); - - return Collections.emptyList(); - } -}
\ No newline at end of file diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/package-info.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/package-info.java deleted file mode 100644 index 880acf5d..00000000 --- a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * 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. - */ - -/** - * Implementations of the pipeline driver behaviours. - */ -package org.onosproject.driver.pipeline;
\ No newline at end of file |