diff options
author | Ashlee Young <ashlee@wildernessvoice.com> | 2015-11-03 14:08:10 -0800 |
---|---|---|
committer | Ashlee Young <ashlee@wildernessvoice.com> | 2015-11-03 14:08:10 -0800 |
commit | 643ee33289bd2cb9e6afbfb09b4ed72d467ba1c2 (patch) | |
tree | c2c376a44a359544fe3d4c45eb0cc0e2ec4a7080 /framework/src/onos/drivers | |
parent | 46eeb79b54345bdafb6055b8ee4bad4ce8b01274 (diff) |
This updates ONOS src tree to commit id
03fa5e571cabbd001ddb1598847e1150b11c7333
Change-Id: I13b554026d6f902933e35887d29bd5fdb669c0bd
Signed-off-by: Ashlee Young <ashlee@wildernessvoice.com>
Diffstat (limited to 'framework/src/onos/drivers')
9 files changed, 1125 insertions, 368 deletions
diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraExtensionInterpreter.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraExtensionInterpreter.java new file mode 100644 index 00000000..082c5a6d --- /dev/null +++ b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraExtensionInterpreter.java @@ -0,0 +1,84 @@ +/* + * 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.extensions; + +import org.onlab.packet.Ip4Address; +import org.onosproject.net.behaviour.ExtensionResolver; +import org.onosproject.net.driver.AbstractHandlerBehaviour; +import org.onosproject.net.flow.instructions.ExtensionInstruction; +import org.onosproject.net.flow.instructions.ExtensionType; +import org.onosproject.openflow.controller.ExtensionInterpreter; +import org.projectfloodlight.openflow.protocol.OFActionType; +import org.projectfloodlight.openflow.protocol.OFFactory; +import org.projectfloodlight.openflow.protocol.action.OFAction; +import org.projectfloodlight.openflow.protocol.action.OFActionSetField; +import org.projectfloodlight.openflow.protocol.oxm.OFOxm; +import org.projectfloodlight.openflow.protocol.oxm.OFOxmTunnelIpv4Dst; +import org.projectfloodlight.openflow.types.IPv4Address; + +/** + * Interpreter for Nicira OpenFlow extensions. + */ +public class NiciraExtensionInterpreter extends AbstractHandlerBehaviour + implements ExtensionInterpreter, ExtensionResolver { + + @Override + public boolean supported(ExtensionType extensionType) { + if (extensionType.equals(ExtensionType.ExtensionTypes.NICIRA_SET_TUNNEL_DST)) { + return true; + } + + return false; + } + + @Override + public OFAction mapInstruction(OFFactory factory, ExtensionInstruction extensionInstruction) { + ExtensionType type = extensionInstruction.type(); + if (type.equals(ExtensionType.ExtensionTypes.NICIRA_SET_TUNNEL_DST.type())) { + NiciraSetTunnelDst tunnelDst = (NiciraSetTunnelDst) extensionInstruction; + return factory.actions().setField(factory.oxms().tunnelIpv4Dst( + IPv4Address.of(tunnelDst.tunnelDst().toInt()))); + } + return null; + } + + @Override + public ExtensionInstruction mapAction(OFAction action) { + if (action.getType().equals(OFActionType.SET_FIELD)) { + OFActionSetField setFieldAction = (OFActionSetField) action; + OFOxm<?> oxm = setFieldAction.getField(); + switch (oxm.getMatchField().id) { + case TUNNEL_IPV4_DST: + OFOxmTunnelIpv4Dst tunnelIpv4Dst = (OFOxmTunnelIpv4Dst) oxm; + return new NiciraSetTunnelDst(Ip4Address.valueOf(tunnelIpv4Dst.getValue().getInt())); + default: + throw new UnsupportedOperationException( + "Driver does not support extension type " + oxm.getMatchField().id); + } + } + return null; + } + + @Override + public ExtensionInstruction getExtensionInstruction(ExtensionType type) { + if (type.equals(ExtensionType.ExtensionTypes.NICIRA_SET_TUNNEL_DST.type())) { + return new NiciraSetTunnelDst(); + } + throw new UnsupportedOperationException( + "Driver does not support extension type " + type.toString()); + } +} diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraSetTunnelDst.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraSetTunnelDst.java new file mode 100644 index 00000000..16aa1b07 --- /dev/null +++ b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraSetTunnelDst.java @@ -0,0 +1,106 @@ +/* + * 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.extensions; + +import com.google.common.base.MoreObjects; +import org.onlab.packet.Ip4Address; +import org.onlab.util.KryoNamespace; +import org.onosproject.net.flow.instructions.AbstractExtensionInstruction; +import org.onosproject.net.flow.instructions.ExtensionType; +import org.onosproject.store.serializers.Ip4AddressSerializer; + +import java.util.Objects; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Nicira set tunnel destination extension instruction. + */ +public class NiciraSetTunnelDst extends AbstractExtensionInstruction { + + private Ip4Address tunnelDst; + + private final KryoNamespace appKryo = new KryoNamespace.Builder() + .register(new Ip4AddressSerializer(), Ip4Address.class) + .register(byte[].class) + .build(); + + /** + * Creates a new set tunnel destination instruction. + */ + NiciraSetTunnelDst() { + tunnelDst = null; + } + + /** + * Creates a new set tunnel destination instruction with a particular IPv4 + * address. + */ + NiciraSetTunnelDst(Ip4Address tunnelDst) { + checkNotNull(tunnelDst); + this.tunnelDst = tunnelDst; + } + + /** + * Gets the tunnel destination IPv4 address. + * + * @return tunnel destination IPv4 address + */ + public Ip4Address tunnelDst() { + return tunnelDst; + } + + @Override + public ExtensionType type() { + return ExtensionType.ExtensionTypes.NICIRA_SET_TUNNEL_DST.type(); + } + + @Override + public void deserialize(byte[] data) { + tunnelDst = appKryo.deserialize(data); + } + + @Override + public byte[] serialize() { + return appKryo.serialize(tunnelDst); + } + + @Override + public int hashCode() { + return Objects.hash(tunnelDst); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof NiciraSetTunnelDst) { + NiciraSetTunnelDst that = (NiciraSetTunnelDst) obj; + return Objects.equals(tunnelDst, that.tunnelDst); + + } + return false; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("tunnelDst", tunnelDst) + .toString(); + } +} diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/package-info.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/package-info.java new file mode 100644 index 00000000..d9d2460d --- /dev/null +++ b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/package-info.java @@ -0,0 +1,19 @@ +/* + * 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. + */ +/** + * Processing of Nicira extensions. + */ +package org.onosproject.driver.extensions; diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/ovsdb/OvsdbBridgeConfig.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/ovsdb/OvsdbBridgeConfig.java index 524163a1..77b48298 100644 --- a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/ovsdb/OvsdbBridgeConfig.java +++ b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/ovsdb/OvsdbBridgeConfig.java @@ -22,11 +22,13 @@ import java.util.Set; import java.util.stream.Collectors; import org.onlab.packet.IpAddress; +import org.onosproject.net.DefaultAnnotations; import org.onosproject.net.DeviceId; import org.onosproject.net.PortNumber; import org.onosproject.net.behaviour.BridgeConfig; import org.onosproject.net.behaviour.BridgeDescription; import org.onosproject.net.behaviour.BridgeName; +import org.onosproject.net.behaviour.ControllerInfo; import org.onosproject.net.behaviour.DefaultBridgeDescription; import org.onosproject.net.device.DefaultPortDescription; import org.onosproject.net.device.PortDescription; @@ -52,6 +54,13 @@ public class OvsdbBridgeConfig extends AbstractHandlerBehaviour } @Override + public boolean addBridge(BridgeName bridgeName, String dpid, List<ControllerInfo> controllers) { + DriverHandler handler = handler(); + OvsdbClientService clientService = getOvsdbClientService(handler); + return clientService.createBridge(bridgeName.name(), dpid, controllers); + } + + @Override public void deleteBridge(BridgeName bridgeName) { DriverHandler handler = handler(); OvsdbClientService clientService = getOvsdbClientService(handler); @@ -108,22 +117,22 @@ public class OvsdbBridgeConfig extends AbstractHandlerBehaviour return ports.stream() .map(x -> new DefaultPortDescription( PortNumber.portNumber(x.portNumber().value()), - true - ) - ) + true, + DefaultAnnotations.builder() + .set("portName", x.portName().value()) + .build())) .collect(Collectors.toSet()); } - // OvsdbNodeId(IP:port) is used in the adaptor while DeviceId(ovsdb:IP:port) + // OvsdbNodeId(IP) is used in the adaptor while DeviceId(ovsdb:IP) // is used in the core. So DeviceId need be changed to OvsdbNodeId. private OvsdbNodeId changeDeviceIdToNodeId(DeviceId deviceId) { - int lastColon = deviceId.toString().lastIndexOf(":"); - int fistColon = deviceId.toString().indexOf(":"); - String ip = deviceId.toString().substring(fistColon + 1, lastColon); - String port = deviceId.toString().substring(lastColon + 1); - IpAddress ipAddress = IpAddress.valueOf(ip); - long portL = Long.parseLong(port); - return new OvsdbNodeId(ipAddress, portL); + String[] splits = deviceId.toString().split(":"); + if (splits == null || splits.length < 1) { + return null; + } + IpAddress ipAddress = IpAddress.valueOf(splits[1]); + return new OvsdbNodeId(ipAddress, 0); } // Used for getting OvsdbClientService. diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/ovsdb/OvsdbTunnelConfig.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/ovsdb/OvsdbTunnelConfig.java index d32fb6be..a32553ad 100644 --- a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/ovsdb/OvsdbTunnelConfig.java +++ b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/ovsdb/OvsdbTunnelConfig.java @@ -16,12 +16,14 @@ package org.onosproject.driver.ovsdb; import java.util.Collection; - +import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import org.onlab.packet.IpAddress; +import org.onosproject.net.DefaultAnnotations; import org.onosproject.net.DeviceId; +import org.onosproject.net.behaviour.BridgeName; import org.onosproject.net.behaviour.DefaultTunnelDescription; import org.onosproject.net.behaviour.IpTunnelEndPoint; import org.onosproject.net.behaviour.TunnelConfig; @@ -41,6 +43,8 @@ public class OvsdbTunnelConfig extends AbstractHandlerBehaviour implements TunnelConfig { private static final String DEFAULT_ADDRESS = "0.0.0.0"; + private static final String OPTION_LOCAL_IP = "local_ip"; + private static final String OPTION_REMOTE_IP = "remote_ip"; @Override public void createTunnel(TunnelDescription tunnel) { @@ -61,6 +65,22 @@ public class OvsdbTunnelConfig extends AbstractHandlerBehaviour } @Override + public boolean createTunnelInterface(BridgeName bridgeName, TunnelDescription tunnel) { + Map<String, String> options = ((DefaultAnnotations) tunnel.annotations()).asMap(); + if (tunnel.src() != null) { + options.put(OPTION_LOCAL_IP, tunnel.src().toString()); + } + if (tunnel.dst() != null) { + options.put(OPTION_REMOTE_IP, tunnel.dst().toString()); + } + + DriverHandler handler = handler(); + OvsdbClientService ovsdbClient = getOvsdbNode(handler); + return ovsdbClient.createTunnel(bridgeName.name(), tunnel.tunnelName().toString(), + tunnel.type().toString().toLowerCase(), options); + } + + @Override public void removeTunnel(TunnelDescription tunnel) { DriverHandler handler = handler(); OvsdbClientService ovsdbNode = getOvsdbNode(handler); @@ -102,16 +122,15 @@ public class OvsdbTunnelConfig extends AbstractHandlerBehaviour .collect(Collectors.toSet()); } - // OvsdbNodeId(IP:port) is used in the adaptor while DeviceId(ovsdb:IP:port) + // OvsdbNodeId(IP) is used in the adaptor while DeviceId(ovsdb:IP) // is used in the core. So DeviceId need be changed to OvsdbNodeId. private OvsdbNodeId changeDeviceIdToNodeId(DeviceId deviceId) { - int lastColon = deviceId.toString().lastIndexOf(":"); - int fistColon = deviceId.toString().indexOf(":"); - String ip = deviceId.toString().substring(fistColon + 1, lastColon); - String port = deviceId.toString().substring(lastColon + 1); - IpAddress ipAddress = IpAddress.valueOf(ip); - long portL = Long.parseLong(port); - return new OvsdbNodeId(ipAddress, portL); + String[] splits = deviceId.toString().split(":"); + if (splits == null || splits.length < 1) { + return null; + } + IpAddress ipAddress = IpAddress.valueOf(splits[1]); + return new OvsdbNodeId(ipAddress, 0); } private OvsdbClientService getOvsdbNode(DriverHandler handler) { diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/CpqdOFDPA1Pipeline.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/CpqdOFDPA2Pipeline.java index c9ef451e..a830ed49 100644 --- a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/CpqdOFDPA1Pipeline.java +++ b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/CpqdOFDPA2Pipeline.java @@ -29,22 +29,23 @@ import org.slf4j.Logger; /** - * Driver for software switch emulation of the OFDPA 1.0 pipeline. + * Driver for software switch emulation of the OFDPA 2.0 pipeline. * The software switch is the CPqD OF 1.3 switch. */ -public class CpqdOFDPA1Pipeline extends OFDPA1Pipeline { +public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline { private final Logger log = getLogger(getClass()); @Override protected void initializePipeline() { processPortTable(); - //processVlanTable(); processTmacTable(); processIpTable(); - //processMcastTable(); processBridgingTable(); processAclTable(); + // XXX implement table miss entries and default groups + //processVlanTable(); + //processMPLSTable(); //processGroupTable(); } @@ -169,6 +170,7 @@ public class CpqdOFDPA1Pipeline extends OFDPA1Pipeline { })); } + @Override protected void processAclTable() { //table miss entry - catch all to executed action-set FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/OFDPA1Pipeline.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/OFDPA2Pipeline.java index f17309e1..b1a1256a 100644 --- a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/OFDPA1Pipeline.java +++ b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/OFDPA2Pipeline.java @@ -18,6 +18,7 @@ package org.onosproject.driver.pipeline; import static org.onlab.util.Tools.groupedThreads; import static org.slf4j.LoggerFactory.getLogger; +import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -30,18 +31,26 @@ import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import org.onlab.osgi.ServiceDirectory; +import org.onlab.packet.Data; import org.onlab.packet.Ethernet; +import org.onlab.packet.IPv4; +import org.onlab.packet.IpPrefix; +import org.onlab.packet.MPLS; +import org.onlab.packet.MacAddress; import org.onlab.packet.MplsLabel; +import org.onlab.packet.UDP; 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; @@ -81,6 +90,11 @@ 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.DefaultOutboundPacket; +import org.onosproject.net.packet.OutboundPacket; +import org.onosproject.net.packet.PacketContext; +import org.onosproject.net.packet.PacketProcessor; +import org.onosproject.net.packet.PacketService; import org.onosproject.store.serializers.KryoNamespaces; import org.slf4j.Logger; @@ -90,19 +104,22 @@ import com.google.common.cache.RemovalCause; import com.google.common.cache.RemovalNotification; /** - * Driver for Broadcom's OF-DPA v1.0 TTP. + * Driver for Broadcom's OF-DPA v2.0 TTP. * */ -public class OFDPA1Pipeline extends AbstractHandlerBehaviour implements Pipeliner { +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; private static final int DEFAULT_PRIORITY = 0x8000; @@ -128,6 +145,8 @@ public class OFDPA1Pipeline extends AbstractHandlerBehaviour implements Pipeline */ 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 final Logger log = getLogger(getClass()); private ServiceDirectory serviceDirectory; @@ -137,7 +156,9 @@ public class OFDPA1Pipeline extends AbstractHandlerBehaviour implements Pipeline private FlowObjectiveStore flowObjectiveStore; protected DeviceId deviceId; protected ApplicationId driverId; - + protected PacketService packetService; + protected DeviceService deviceService; + private InternalPacketProcessor processor = new InternalPacketProcessor(); private KryoNamespace appKryo = new KryoNamespace.Builder() .register(KryoNamespaces.API) .register(GroupKey.class) @@ -151,7 +172,9 @@ public class OFDPA1Pipeline extends AbstractHandlerBehaviour implements Pipeline private ScheduledExecutorService groupChecker = Executors.newScheduledThreadPool(2, groupedThreads("onos/pipeliner", - "ofdpa1-%d")); + "ofdpa2-%d")); + private Set<IPCriterion> sentIpFilters = Collections.newSetFromMap( + new ConcurrentHashMap<IPCriterion, Boolean>()); @Override public void init(DeviceId deviceId, PipelinerContext context) { @@ -174,16 +197,29 @@ public class OFDPA1Pipeline extends AbstractHandlerBehaviour implements Pipeline flowRuleService = serviceDirectory.get(FlowRuleService.class); groupService = serviceDirectory.get(GroupService.class); flowObjectiveStore = context.store(); - + packetService = serviceDirectory.get(PacketService.class); + deviceService = serviceDirectory.get(DeviceService.class); + packetService.addProcessor(processor, PacketProcessor.director(2)); groupService.addListener(new InnerGroupListener()); driverId = coreService.registerApplication( - "org.onosproject.driver.OFDPA1Pipeline"); + "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) { @@ -191,6 +227,11 @@ public class OFDPA1Pipeline extends AbstractHandlerBehaviour implements Pipeline 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); } } @@ -257,25 +298,31 @@ public class OFDPA1Pipeline extends AbstractHandlerBehaviour implements Pipeline } } + ////////////////////////////////////// + // Flow handling + ////////////////////////////////////// + /** - * As per OFDPA 1.0 TTP, filtering of VLAN ids, MAC addresses (for routing) + * 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 - * @param install - * @param applicationId + * @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 p = null; EthCriterion e = null; VlanIdCriterion v = null; + 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) { - p = (PortCriterion) filt.key(); + portCriterion = (PortCriterion) filt.key(); } else { log.warn("No key defined in filtering objective from app: {}. Not" + "processing filtering objective", applicationId); @@ -284,199 +331,238 @@ public class OFDPA1Pipeline extends AbstractHandlerBehaviour implements Pipeline } // 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); + 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 {}", c); + log.error("Unsupported filter {}", criterion); fail(filt, ObjectiveError.UNSUPPORTED); return; } } - log.debug("adding VLAN filtering rule in VLAN table: {}", e.mac()); - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); - selector.matchInPort(p.port()); - selector.matchVlanId(v.vlanId()); - treatment.transition(TMAC_TABLE); - FlowRule rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(DEFAULT_PRIORITY) - .fromApp(applicationId) - .makePermanent() - .forTable(VLAN_TABLE).build(); - ops = ops.add(rule); + 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; + } + } - log.debug("adding MAC filtering rules in TMAC table: {}", e.mac()); - selector = DefaultTrafficSelector.builder(); - treatment = DefaultTrafficTreatment.builder(); - selector.matchInPort(p.port()); - selector.matchVlanId(v.vlanId()); - selector.matchEthType(Ethernet.TYPE_IPV4); - selector.matchEthDst(e.mac()); - treatment.transition(UNICAST_ROUTING_TABLE); - rule = DefaultFlowRule.builder() - .forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(DEFAULT_PRIORITY) - .fromApp(applicationId) - .makePermanent() - .forTable(TMAC_TABLE).build(); - ops = ops.add(rule); + 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); + } + } - log.debug("adding IP filtering rules in ACL table"); for (IPCriterion ipaddr : ips) { - selector = DefaultTrafficSelector.builder(); - treatment = DefaultTrafficTreatment.builder(); - selector.matchEthType(Ethernet.TYPE_IPV4); - selector.matchIPDst(ipaddr.ip()); - treatment.setOutput(PortNumber.CONTROLLER); - 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); + // 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); + } } - 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"); + 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 filtering rules"); + log.info("Failed to apply all filtering rules in dev {}", deviceId); fail(filt, ObjectiveError.FLOWINSTALLATIONFAILED); } })); } - /** - * As per the OFDPA 1.0 TTP, packets are sent out of ports by using - * a chain of groups, namely an L3 Unicast Group that points to an L2 Interface - * Group which in turns points to an output port. The Next Objective passed - * in by the application has to be broken up into a group chain - * to satisfy this TTP. + * 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 nextObj the nextObjective of type SIMPLE + * @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 */ - private void processSimpleNextObjective(NextObjective nextObj) { - // break up simple next objective to GroupChain objects - TrafficTreatment treatment = nextObj.next().iterator().next(); - // for the l2interface group, get vlan and port info - // for the l3unicast group, get the src/dst mac and vlan info - TrafficTreatment.Builder l3utt = DefaultTrafficTreatment.builder(); - TrafficTreatment.Builder l2itt = DefaultTrafficTreatment.builder(); - VlanId vlanid = null; - long portNum = 0; - for (Instruction ins : treatment.allInstructions()) { - if (ins.type() == Instruction.Type.L2MODIFICATION) { - L2ModificationInstruction l2ins = (L2ModificationInstruction) ins; - switch (l2ins.subtype()) { - case ETH_DST: - l3utt.setEthDst(((ModEtherInstruction) l2ins).mac()); - break; - case ETH_SRC: - l3utt.setEthSrc(((ModEtherInstruction) l2ins).mac()); - break; - case VLAN_ID: - vlanid = ((ModVlanIdInstruction) l2ins).vlanId(); - l3utt.setVlanId(vlanid); - break; - case DEC_MPLS_TTL: - case MPLS_LABEL: - case MPLS_POP: - case MPLS_PUSH: - case VLAN_PCP: - case VLAN_POP: - case VLAN_PUSH: - default: - break; + 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()); + if (vidCriterion.vlanId() == VlanId.NONE) { + // untagged packets are assigned vlans + treatment.pushVlan().setVlanId(assignedVlan); + // XXX ofdpa may require an additional vlan match on the assigned vlan + // and it may not require the push. + } + treatment.transition(TMAC_TABLE); + + // 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 if (ins.type() == Instruction.Type.OUTPUT) { - portNum = ((OutputInstruction) ins).port().toLong(); - l2itt.add(ins); - } else { - log.warn("Driver does not handle this type of TrafficTreatment" - + " instruction in nextObjectives: {}", ins.type()); } + } else { + portnums.add(portCriterion.port()); } - - // assemble information for ofdpa l2interface group - int l2gk = nextObj.id() | GROUP1MASK; - final GroupKey l2groupkey = new DefaultGroupKey(appKryo.serialize(l2gk)); - Integer l2groupId = L2INTERFACEMASK | (vlanid.toShort() << 16) | (int) portNum; - - // assemble information for ofdpa l3unicast group - int l3gk = nextObj.id() | GROUP0MASK; - final GroupKey l3groupkey = new DefaultGroupKey(appKryo.serialize(l3gk)); - Integer l3groupId = L3UNICASTMASK | (int) portNum; - l3utt.group(new DefaultGroupId(l2groupId)); - GroupChainElem gce = new GroupChainElem(l3groupkey, l3groupId, - l3utt.build(), nextObj.appId()); - - // create object for local and distributed storage - List<GroupKey> gkeys = new ArrayList<GroupKey>(); - gkeys.add(l3groupkey); // group0 in chain - gkeys.add(l2groupkey); // group1 in chain - OfdpaGroupChain ofdpaGrp = new OfdpaGroupChain(gkeys, nextObj); - - // store l2groupkey with the groupChainElem for the l3group that depends on it - pendingGroups.put(l2groupkey, gce); - - // store l3groupkey with the ofdpaGroupChain for the nextObjective that depends on it - pendingNextObjectives.put(l3groupkey, ofdpaGrp); - - // create group description for the ofdpa l2interfacegroup and send to groupservice - GroupBucket bucket = - DefaultGroupBucket.createIndirectGroupBucket(l2itt.build()); - GroupDescription groupDescription = new DefaultGroupDescription(deviceId, - GroupDescription.Type.INDIRECT, - new GroupBuckets(Collections.singletonList(bucket)), - l2groupkey, - l2groupId, - nextObj.appId()); - groupService.addGroup(groupDescription); + for (PortNumber pnum : portnums) { + 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; } /** - * 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. + * Allows routed packets with correct destination MAC to be directed + * to unicast-IP routing table or MPLS forwarding table. + * XXX need to add rule for multicast routing. * - * @param gce the group chain element to be processed next + * @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 + */ - private void processGroupChain(GroupChainElem gce) { - GroupBucket bucket = DefaultGroupBucket - .createIndirectGroupBucket(gce.getBucketActions()); - GroupDescription groupDesc = new DefaultGroupDescription(deviceId, - GroupDescription.Type.INDIRECT, - new GroupBuckets(Collections.singletonList(bucket)), - gce.getGkey(), - gce.getGivenGroupId(), - gce.getAppId()); - groupService.addGroup(groupDesc); + 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) { @@ -493,7 +579,7 @@ public class OFDPA1Pipeline extends AbstractHandlerBehaviour implements Pipeline } /** - * In the OF-DPA 1.0 pipeline, versatile forwarding objectives go to the + * 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 @@ -508,37 +594,46 @@ public class OFDPA1Pipeline extends AbstractHandlerBehaviour implements Pipeline (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE); if (ethType == null) { log.error("Versatile forwarding objective must include ethType"); - fail(fwd, ObjectiveError.UNKNOWN); + fail(fwd, ObjectiveError.BADPARAMS); return Collections.emptySet(); } - if (ethType.ethType().toShort() == Ethernet.TYPE_ARP) { - log.warn("Installing ARP rule to table 60"); - - // currently need to punt from ACL table should use: - // OF apply-actions-instruction - // To use OF write-actions-instruction - /*TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder(); - fwd.treatment().allInstructions().stream() - .forEach(ti -> tb.deferred().add(ti));*/ - - 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()); + 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(); + } } - // XXX not handling other versatile flows yet + if (fwd.nextId() != null) { + // XXX overide case + log.warn("versatile objective --> next Id not yet implemeted"); + } return Collections.emptySet(); } /** - * In the OF-DPA 1.0 pipeline, specific forwarding refers to the IP table + * In the OF-DPA 2.0 pipeline, specific forwarding refers to the IP table * (unicast or multicast) or the L2 table (mac + vlan). * * @param fwd the forwarding objective of type 'specific' @@ -602,151 +697,126 @@ public class OFDPA1Pipeline extends AbstractHandlerBehaviour implements Pipeline } } - private void fail(Objective obj, ObjectiveError error) { if (obj.context().isPresent()) { obj.context().get().onError(obj, error); } } + ////////////////////////////////////// + // Group handling + ////////////////////////////////////// - protected void initializePipeline() { - processPortTable(); - processVlanTable(); - processTmacTable(); - processIpTable(); - //processMcastTable(); - //processBridgingTable(); - //processAclTable(); - //processGroupTable(); - //processMplsTable(); - } - - protected void processMplsTable() { - FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); - selector.matchEthType(Ethernet.MPLS_UNICAST); - selector.matchMplsLabel(MplsLabel.mplsLabel(0xff)); - selector.matchMplsBos(true); - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); - treatment.popMpls(Ethernet.TYPE_IPV4); - treatment.transition(ACL_TABLE); - FlowRule test = DefaultFlowRule.builder().forDevice(deviceId) - .withSelector(selector.build()).withTreatment(treatment.build()) - .withPriority(LOWEST_PRIORITY).fromApp(driverId).makePermanent() - .forTable(25).build(); - ops = ops.add(test); - - flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - log.info("Initialized mpls table"); - } - - @Override - public void onError(FlowRuleOperations ops) { - log.info("Failed to initialize mpls table"); + /** + * As per the OFDPA 2.0 TTP, packets are sent out of ports by using + * a chain of groups, namely an L3 Unicast Group that points to an L2 Interface + * Group which in turns points to an output port. The Next Objective passed + * in by the application has to be broken up into a group chain + * to satisfy this TTP. + * + * @param nextObj the nextObjective of type SIMPLE + */ + private void processSimpleNextObjective(NextObjective nextObj) { + // break up simple next objective to GroupChain objects + TrafficTreatment treatment = nextObj.next().iterator().next(); + // for the l2interface group, get vlan and port info + // for the l3unicast group, get the src/dst mac and vlan info + TrafficTreatment.Builder l3utt = DefaultTrafficTreatment.builder(); + TrafficTreatment.Builder l2itt = DefaultTrafficTreatment.builder(); + VlanId vlanid = null; + long portNum = 0; + for (Instruction ins : treatment.allInstructions()) { + if (ins.type() == Instruction.Type.L2MODIFICATION) { + L2ModificationInstruction l2ins = (L2ModificationInstruction) ins; + switch (l2ins.subtype()) { + case ETH_DST: + l3utt.setEthDst(((ModEtherInstruction) l2ins).mac()); + break; + case ETH_SRC: + l3utt.setEthSrc(((ModEtherInstruction) l2ins).mac()); + break; + case VLAN_ID: + vlanid = ((ModVlanIdInstruction) l2ins).vlanId(); + l3utt.setVlanId(vlanid); + break; + case DEC_MPLS_TTL: + case MPLS_LABEL: + case MPLS_POP: + case MPLS_PUSH: + case VLAN_PCP: + case VLAN_POP: + case VLAN_PUSH: + default: + break; + } + } else if (ins.type() == Instruction.Type.OUTPUT) { + portNum = ((OutputInstruction) ins).port().toLong(); + l2itt.add(ins); + } else { + log.warn("Driver does not handle this type of TrafficTreatment" + + " instruction in nextObjectives: {}", ins.type()); } - })); + } - } + // assemble information for ofdpa l2interface group + int l2gk = nextObj.id() | GROUP1MASK; + final GroupKey l2groupkey = new DefaultGroupKey(appKryo.serialize(l2gk)); + Integer l2groupId = L2INTERFACEMASK | (vlanid.toShort() << 16) | (int) portNum; - protected void processPortTable() { - //XXX is table miss entry enough or do we need to do the maskable in-port 0? - FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); - selector.matchInPort(PortNumber.portNumber(0)); // should be maskable? - 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); + // assemble information for ofdpa l3unicast group + int l3gk = nextObj.id() | GROUP0MASK; + final GroupKey l3groupkey = new DefaultGroupKey(appKryo.serialize(l3gk)); + Integer l3groupId = L3UNICASTMASK | (int) portNum; + l3utt.group(new DefaultGroupId(l2groupId)); + GroupChainElem gce = new GroupChainElem(l3groupkey, l3groupId, + l3utt.build(), nextObj.appId()); - flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { - @Override - public void onSuccess(FlowRuleOperations ops) { - log.info("Initialized port table"); - } + // create object for local and distributed storage + List<GroupKey> gkeys = new ArrayList<GroupKey>(); + gkeys.add(l3groupkey); // group0 in chain + gkeys.add(l2groupkey); // group1 in chain + OfdpaGroupChain ofdpaGrp = new OfdpaGroupChain(gkeys, nextObj); - @Override - public void onError(FlowRuleOperations ops) { - log.info("Failed to initialize port table"); - } - }));*/ + // store l2groupkey with the groupChainElem for the l3group that depends on it + pendingGroups.put(l2groupkey, gce); - } + // store l3groupkey with the ofdpaGroupChain for the nextObjective that depends on it + pendingNextObjectives.put(l3groupkey, ofdpaGrp); - private void processVlanTable() { - // Table miss entry is not required as ofdpa default is to drop - // In OF terms, the absence of a t.m.e. also implies drop + // create group description for the ofdpa l2interfacegroup and send to groupservice + GroupBucket bucket = + DefaultGroupBucket.createIndirectGroupBucket(l2itt.build()); + GroupDescription groupDescription = new DefaultGroupDescription(deviceId, + GroupDescription.Type.INDIRECT, + new GroupBuckets(Collections.singletonList(bucket)), + l2groupkey, + l2groupId, + nextObj.appId()); + groupService.addGroup(groupDescription); } - - 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); // XXX bug in ofdpa - 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"); - } - }));*/ + /** + * 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. + * + * @param gce the group chain element to be processed next + */ + private void processGroupChain(GroupChainElem gce) { + GroupBucket bucket = DefaultGroupBucket + .createIndirectGroupBucket(gce.getBucketActions()); + GroupDescription groupDesc = new DefaultGroupDescription(deviceId, + GroupDescription.Type.INDIRECT, + new GroupBuckets(Collections.singletonList(bucket)), + gce.getGkey(), + gce.getGivenGroupId(), + gce.getAppId()); + groupService.addGroup(groupDesc); } - 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.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"); - } - }));*/ - } private class GroupChecker implements Runnable { @Override @@ -884,4 +954,416 @@ public class OFDPA1Pipeline extends AbstractHandlerBehaviour implements Pipeline } } + + ////////////////////////////////////// + // Test code to be used for future + // static-flow-pusher app + ////////////////////////////////////// + + public void processStaticFlows() { + //processPortTable(); + processGroupTable(); + processVlanTable(); + processTmacTable(); + processIpTable(); + //processMcastTable(); + //processBridgingTable(); + processAclTable(); + sendPackets(); + processMplsTable(); + } + + protected void processGroupTable() { + TrafficTreatment.Builder act = DefaultTrafficTreatment.builder(); + + act.popVlan(); // to send out untagged packets + act.setOutput(PortNumber.portNumber(24)); + GroupBucket bucket = + DefaultGroupBucket.createIndirectGroupBucket(act.build()); + final GroupKey groupkey = new DefaultGroupKey(appKryo.serialize(500)); + Integer groupId = 0x00c80018; //l2 interface, vlan 200, port 24 + GroupDescription groupDescription = new DefaultGroupDescription(deviceId, + GroupDescription.Type.INDIRECT, + new GroupBuckets(Collections.singletonList(bucket)), + groupkey, + groupId, + driverId); + groupService.addGroup(groupDescription); + + TrafficTreatment.Builder act2 = DefaultTrafficTreatment.builder(); + act2.setOutput(PortNumber.portNumber(40)); + GroupBucket bucket2 = DefaultGroupBucket.createIndirectGroupBucket(act2.build()); + final GroupKey groupkey2 = new DefaultGroupKey(appKryo.serialize(502)); + Integer groupId2 = 0x00c50028; //l2 interface, vlan 197, port 40 + GroupDescription groupDescription2 = new DefaultGroupDescription(deviceId, + GroupDescription.Type.INDIRECT, + new GroupBuckets(Collections.singletonList(bucket2)), + groupkey2, + groupId2, + driverId); + groupService.addGroup(groupDescription2); + + while (groupService.getGroup(deviceId, groupkey2) == null) { + try { + Thread.sleep(500); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + //Now for L3 Unicast group + TrafficTreatment.Builder act3 = DefaultTrafficTreatment.builder(); + act3.setEthDst(MacAddress.valueOf(0x2020)); + act3.setEthSrc(MacAddress.valueOf(0x1010)); + act3.setVlanId(VlanId.vlanId((short) 200)); + act3.group(new DefaultGroupId(0x00c80018)); // point to L2 interface + // MPLS interface group - does not work for popping single label + //Integer secGroupId = MPLSINTERFACEMASK | 38; // 0x90000026 + Integer groupId3 = L3UNICASTMASK | 1; // 0x20000001 + GroupBucket bucket3 = + DefaultGroupBucket.createIndirectGroupBucket(act3.build()); + final GroupKey groupkey3 = new DefaultGroupKey(appKryo.serialize(503)); + GroupDescription groupDescription3 = new DefaultGroupDescription(deviceId, + GroupDescription.Type.INDIRECT, + new GroupBuckets(Collections.singletonList(bucket3)), + groupkey3, + groupId3, + driverId); + groupService.addGroup(groupDescription3); + + //Another L3 Unicast group + TrafficTreatment.Builder act4 = DefaultTrafficTreatment.builder(); + act4.setEthDst(MacAddress.valueOf(0x3030)); + act4.setEthSrc(MacAddress.valueOf(0x1010)); + act4.setVlanId(VlanId.vlanId((short) 197)); + act4.group(new DefaultGroupId(0x00c50028)); // point to L2 interface + Integer groupId4 = L3UNICASTMASK | 2; // 0x20000002 + GroupBucket bucket4 = + DefaultGroupBucket.createIndirectGroupBucket(act4.build()); + final GroupKey groupkey4 = new DefaultGroupKey(appKryo.serialize(504)); + GroupDescription groupDescription4 = new DefaultGroupDescription(deviceId, + GroupDescription.Type.INDIRECT, + new GroupBuckets(Collections.singletonList(bucket4)), + groupkey4, + groupId4, + driverId); + groupService.addGroup(groupDescription4); + + while (groupService.getGroup(deviceId, groupkey4) == null) { + try { + Thread.sleep(500); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + // L3 ecmp group + TrafficTreatment.Builder act5 = DefaultTrafficTreatment.builder(); + act5.group(new DefaultGroupId(0x20000001)); + TrafficTreatment.Builder act6 = DefaultTrafficTreatment.builder(); + act6.group(new DefaultGroupId(0x20000002)); + GroupBucket buckete1 = + DefaultGroupBucket.createSelectGroupBucket(act5.build()); + GroupBucket buckete2 = + DefaultGroupBucket.createSelectGroupBucket(act6.build()); + List<GroupBucket> bktlist = new ArrayList<GroupBucket>(); + bktlist.add(buckete1); + bktlist.add(buckete2); + final GroupKey groupkey5 = new DefaultGroupKey(appKryo.serialize(505)); + Integer groupId5 = L3ECMPMASK | 5; // 0x70000005 + GroupDescription groupDescription5 = new DefaultGroupDescription(deviceId, + GroupDescription.Type.SELECT, + new GroupBuckets(bktlist), + groupkey5, + groupId5, + driverId); + groupService.addGroup(groupDescription5); + + + } + + @SuppressWarnings("deprecation") + protected void processMplsTable() { + FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); + TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); + selector.matchEthType(Ethernet.MPLS_UNICAST); + selector.matchMplsLabel(MplsLabel.mplsLabel(0xff)); //255 + selector.matchMplsBos(true); + TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); + treatment.decMplsTtl(); // nw_ttl does not work + treatment.copyTtlIn(); + treatment.popMpls(Ethernet.TYPE_IPV4); + treatment.deferred().group(new DefaultGroupId(0x20000001)); // point to L3 Unicast + //treatment.deferred().group(new DefaultGroupId(0x70000005)); // point to L3 ECMP + treatment.transition(ACL_TABLE); + FlowRule test = DefaultFlowRule.builder().forDevice(deviceId) + .withSelector(selector.build()).withTreatment(treatment.build()) + .withPriority(DEFAULT_PRIORITY).fromApp(driverId).makePermanent() + .forTable(24).build(); + ops = ops.add(test); + + flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { + @Override + public void onSuccess(FlowRuleOperations ops) { + log.info("Initialized mpls table"); + } + + @Override + public void onError(FlowRuleOperations ops) { + log.info("Failed to initialize mpls table"); + } + })); + + } + + protected void processPortTable() { + FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); + TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); + selector.matchInPort(PortNumber.portNumber(0)); // should be maskable? + 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"); + } + })); + + } + + private void processVlanTable() { + // Table miss entry is not required as ofdpa default is to drop + // In OF terms, the absence of a t.m.e. also implies drop + FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); + TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); + TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); + selector.matchInPort(PortNumber.portNumber(12)); + selector.matchVlanId(VlanId.vlanId((short) 100)); + treatment.transition(TMAC_TABLE); + FlowRule rule = DefaultFlowRule.builder() + .forDevice(deviceId) + .withSelector(selector.build()) + .withTreatment(treatment.build()) + .withPriority(DEFAULT_PRIORITY) + .fromApp(driverId) + .makePermanent() + .forTable(VLAN_TABLE).build(); + ops = ops.add(rule); + flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { + @Override + public void onSuccess(FlowRuleOperations ops) { + log.info("Initialized vlan table"); + } + + @Override + public void onError(FlowRuleOperations ops) { + log.info("Failed to initialize vlan table"); + } + })); + } + + protected void processTmacTable() { + //table miss entry + FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); + TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); + TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); + selector.matchInPort(PortNumber.portNumber(12)); + selector.matchVlanId(VlanId.vlanId((short) 100)); + selector.matchEthType(Ethernet.TYPE_IPV4); + selector.matchEthDst(MacAddress.valueOf("00:00:00:00:00:02")); + treatment.transition(UNICAST_ROUTING_TABLE); + FlowRule rule = DefaultFlowRule.builder() + .forDevice(deviceId) + .withSelector(selector.build()) + .withTreatment(treatment.build()) + .withPriority(DEFAULT_PRIORITY) + .fromApp(driverId) + .makePermanent() + .forTable(TMAC_TABLE).build(); + ops = ops.add(rule); + + selector.matchEthType(Ethernet.MPLS_UNICAST); + treatment.transition(MPLS_TABLE_0); + FlowRule rulempls = DefaultFlowRule.builder() + .forDevice(deviceId) + .withSelector(selector.build()) + .withTreatment(treatment.build()) + .withPriority(DEFAULT_PRIORITY) + .fromApp(driverId) + .makePermanent() + .forTable(TMAC_TABLE).build(); + ops = ops.add(rulempls); + + 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.matchEthType(Ethernet.TYPE_IPV4); + selector.matchIPDst(IpPrefix.valueOf("2.0.0.0/16")); + treatment.deferred().group(new DefaultGroupId(0x20000001)); + treatment.transition(ACL_TABLE); + FlowRule rule = DefaultFlowRule.builder() + .forDevice(deviceId) + .withSelector(selector.build()) + .withTreatment(treatment.build()) + .withPriority(30000) + .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 processAclTable() { + //table miss entry + FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); + TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); + TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); + selector.matchEthDst(MacAddress.valueOf("00:00:00:00:00:02")); + treatment.deferred().group(new DefaultGroupId(0x20000001)); + FlowRule rule = DefaultFlowRule.builder() + .forDevice(deviceId) + .withSelector(selector.build()) + .withTreatment(treatment.build()) + .withPriority(60000) + .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"); + } + })); + } + + private void sendPackets() { + Ethernet eth = new Ethernet(); + eth.setDestinationMACAddress("00:00:00:00:00:02"); + eth.setSourceMACAddress("00:00:00:11:22:33"); + eth.setVlanID((short) 100); + eth.setEtherType(Ethernet.MPLS_UNICAST); + MPLS mplsPkt = new MPLS(); + mplsPkt.setLabel(255); + mplsPkt.setTtl((byte) 5); + + IPv4 ipv4 = new IPv4(); + + ipv4.setDestinationAddress("4.0.5.6"); + ipv4.setSourceAddress("1.0.2.3"); + ipv4.setTtl((byte) 64); + ipv4.setChecksum((short) 0); + + UDP udp = new UDP(); + udp.setDestinationPort(666); + udp.setSourcePort(333); + udp.setPayload(new Data(new byte[]{(byte) 1, (byte) 2})); + udp.setChecksum((short) 0); + + ipv4.setPayload(udp); + mplsPkt.setPayload(ipv4); + eth.setPayload(mplsPkt); + + TrafficTreatment treatment = DefaultTrafficTreatment.builder() + .setOutput(PortNumber.portNumber(24)) + .build(); + OutboundPacket packet = new DefaultOutboundPacket(deviceId, + treatment, + ByteBuffer.wrap(eth.serialize())); + + + Ethernet eth2 = new Ethernet(); + eth2.setDestinationMACAddress("00:00:00:00:00:02"); + eth2.setSourceMACAddress("00:00:00:11:22:33"); + eth2.setVlanID((short) 100); + eth2.setEtherType(Ethernet.TYPE_IPV4); + + IPv4 ipv42 = new IPv4(); + ipv42.setDestinationAddress("2.0.0.2"); + ipv42.setSourceAddress("1.0.9.9"); + ipv42.setTtl((byte) 64); + ipv42.setChecksum((short) 0); + + UDP udp2 = new UDP(); + udp2.setDestinationPort(999); + udp2.setSourcePort(333); + udp2.setPayload(new Data(new byte[]{(byte) 1, (byte) 2})); + udp2.setChecksum((short) 0); + + ipv42.setPayload(udp2); + eth2.setPayload(ipv42); + + TrafficTreatment treatment2 = DefaultTrafficTreatment.builder() + .setOutput(PortNumber.portNumber(26)) + .build(); + OutboundPacket packet2 = new DefaultOutboundPacket(deviceId, + treatment2, + ByteBuffer.wrap(eth2.serialize())); + + + log.info("Emitting packets now"); + packetService.emit(packet); + packetService.emit(packet); + packetService.emit(packet2); + packetService.emit(packet); + packetService.emit(packet); + log.info("Done emitting packets"); + } + + private class InternalPacketProcessor implements PacketProcessor { + + @Override + public void process(PacketContext context) { + + + } + } + } 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 index c02ba3ca..31297ff4 100644 --- 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 @@ -53,6 +53,7 @@ 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.flowobjective.FilteringObjective; import org.onosproject.net.flowobjective.FlowObjectiveStore; import org.onosproject.net.flowobjective.ForwardingObjective; @@ -246,6 +247,7 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour 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: log.debug("processing SIMPLE next objective"); @@ -273,7 +275,7 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour break; case HASHED: log.debug("processing HASHED next objective"); - List<GroupBucket> buckets = nextObjective + buckets = nextObjective .next() .stream() .map((treatment) -> DefaultGroupBucket @@ -297,8 +299,32 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour } break; case BROADCAST: + log.debug("processing BROADCAST next objective"); + 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 {}", + nextObjective.id()); + groupService.addGroup(groupDescription); + pendingGroups.put(key, nextObjective); + } + break; case FAILOVER: - log.debug("BROADCAST and FAILOVER next objectives not supported"); + log.debug("FAILOVER next objectives not supported"); fail(nextObjective, ObjectiveError.UNSUPPORTED); log.warn("Unsupported next objective type {}", nextObjective.type()); break; @@ -326,6 +352,8 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour 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; @@ -356,6 +384,8 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour 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; @@ -383,7 +413,7 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour private Collection<FlowRule> processVersatile(ForwardingObjective fwd) { log.debug("Processing versatile forwarding objective"); TrafficSelector selector = fwd.selector(); - + TrafficTreatment treatment = null; EthTypeCriterion ethType = (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE); if (ethType == null) { @@ -410,15 +440,26 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour return Collections.emptySet(); } treatmentBuilder.deferred().group(group.id()); + treatment = treatmentBuilder.build(); log.debug("Adding OUTGROUP action"); } + } else 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) { + log.warn("Punts to the controller are handled by misses in" + + " the TMAC, IP and MPLS tables."); + return Collections.emptySet(); + } + } + treatment = fwd.treatment(); } else { - log.warn("VERSATILE forwarding objective need next objective ID."); + log.warn("VERSATILE forwarding objective needs next objective ID " + + "or treatment."); return Collections.emptySet(); } - TrafficTreatment treatment = treatmentBuilder.build(); - FlowRule.Builder ruleBuilder = DefaultFlowRule.builder() .fromApp(fwd.appId()).withPriority(fwd.priority()) .forDevice(deviceId).withSelector(fwd.selector()) @@ -527,7 +568,7 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour protected List<FlowRule> processEthDstFilter(Criterion c, FilteringObjective filt, ApplicationId applicationId) { - List<FlowRule> rules = new ArrayList<FlowRule>(); + List<FlowRule> rules = new ArrayList<>(); EthCriterion e = (EthCriterion) c; TrafficSelector.Builder selectorIp = DefaultTrafficSelector .builder(); @@ -565,7 +606,7 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour protected List<FlowRule> processVlanIdFilter(Criterion c, FilteringObjective filt, ApplicationId applicationId) { - List<FlowRule> rules = new ArrayList<FlowRule>(); + List<FlowRule> rules = new ArrayList<>(); VlanIdCriterion v = (VlanIdCriterion) c; log.debug("adding rule for VLAN: {}", v.vlanId()); TrafficSelector.Builder selector = DefaultTrafficSelector @@ -616,21 +657,8 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour 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(aclTableId); - FlowRule rule = DefaultFlowRule.builder().forDevice(deviceId) - .withSelector(selector.build()) - .withTreatment(treatment.build()) - .withPriority(filt.priority()).fromApp(applicationId) - .makePermanent().forTable(ipv4UnicastTableId).build(); - ops = install ? ops.add(rule) : ops.remove(rule); + 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: {}", c.type()); @@ -762,6 +790,7 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour this.key = key; } + @SuppressWarnings("unused") public GroupKey key() { return key; } diff --git a/framework/src/onos/drivers/src/main/resources/onos-drivers.xml b/framework/src/onos/drivers/src/main/resources/onos-drivers.xml index 5059d4bf..af498832 100644 --- a/framework/src/onos/drivers/src/main/resources/onos-drivers.xml +++ b/framework/src/onos/drivers/src/main/resources/onos-drivers.xml @@ -32,12 +32,19 @@ impl="org.onosproject.driver.handshaker.NiciraSwitchHandshaker"/> <behaviour api="org.onosproject.net.behaviour.ControllerConfig" impl="org.onosproject.driver.ovsdb.OvsdbControllerConfig"/> + <behaviour api="org.onosproject.openflow.controller.ExtensionInterpreter" + impl="org.onosproject.driver.extensions.NiciraExtensionInterpreter" /> + <behaviour api="org.onosproject.net.behaviour.ExtensionResolver" + impl="org.onosproject.driver.extensions.NiciraExtensionInterpreter" /> </driver> <driver name="ovs-corsa" extends="ovs" manufacturer="Corsa" hwVersion="emulation" swVersion="0.0.0"> <behaviour api="org.onosproject.net.behaviour.Pipeliner" impl="org.onosproject.driver.pipeline.OVSCorsaPipeline"/> </driver> + <!-- Emulation of the spring-open pipeline using a CPqD OF 1.3 software switch. + ~ This driver is the default driver assigned to the CPqD switch. + --> <driver name="spring-open-cpqd" extends="default" manufacturer="Stanford University, Ericsson Research and CPqD Research" hwVersion="OpenFlow 1.3 Reference Userspace Switch" swVersion=".*"> @@ -66,7 +73,7 @@ <driver name="ofdpa" extends="default" manufacturer="Broadcom Corp." hwVersion="OF-DPA.*" swVersion="OF-DPA.*"> <behaviour api="org.onosproject.net.behaviour.Pipeliner" - impl="org.onosproject.driver.pipeline.OFDPA1Pipeline"/> + impl="org.onosproject.driver.pipeline.OFDPA2Pipeline"/> </driver> <driver name="pmc-olt" extends="default" manufacturer="Big Switch Networks" hwVersion="ivs 0.5" swVersion="ivs 0.5"> @@ -109,7 +116,7 @@ manufacturer="ONF" hwVersion="OF1.3 Software Switch from CPqD" swVersion="for Group Chaining"> <behaviour api="org.onosproject.net.behaviour.Pipeliner" - impl="org.onosproject.driver.pipeline.CpqdOFDPA1Pipeline"/> + impl="org.onosproject.driver.pipeline.CpqdOFDPA2Pipeline"/> </driver> <driver name="calient" extends="default" manufacturer="calient inc" hwVersion="calient hardware" |