diff options
Diffstat (limited to 'framework/src/onos/drivers')
24 files changed, 2073 insertions, 539 deletions
diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/DefaultMoveExtensionTreatment.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/DefaultMoveExtensionTreatment.java new file mode 100644 index 00000000..140a8167 --- /dev/null +++ b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/DefaultMoveExtensionTreatment.java @@ -0,0 +1,146 @@ +/* + * 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 java.util.Map; +import java.util.Objects; + +import org.onlab.util.KryoNamespace; +import org.onosproject.net.flow.AbstractExtension; +import org.onosproject.net.flow.instructions.ExtensionTreatmentType; + +import com.google.common.base.MoreObjects; +import com.google.common.collect.Maps; + +/** + * Default implementation of Move treatment. + */ +public class DefaultMoveExtensionTreatment extends AbstractExtension + implements MoveExtensionTreatment { + + private int srcOfs; + private int dstOfs; + private int nBits; + private int src; + private int dst; + private ExtensionTreatmentType type; + + private final KryoNamespace appKryo = new KryoNamespace.Builder() + .register(byte[].class).register(Integer.class).register(Map.class) + .build(); + + /** + * Creates a new move Treatment. + * + * @param srcOfs source offset + * @param dstOfs destination offset + * @param nBits nbits + * @param src source + * @param dst destination + * @param type extension treatment type + */ + public DefaultMoveExtensionTreatment(int srcOfs, int dstOfs, int nBits, + int src, int dst, ExtensionTreatmentType type) { + this.srcOfs = srcOfs; + this.dstOfs = dstOfs; + this.nBits = nBits; + this.src = src; + this.dst = dst; + this.type = type; + } + + @Override + public ExtensionTreatmentType type() { + return type; + } + + @Override + public byte[] serialize() { + Map<String, Integer> values = Maps.newHashMap(); + values.put("srcOfs", srcOfs); + values.put("dstOfs", dstOfs); + values.put("nBits", nBits); + values.put("src", src); + values.put("dst", dst); + values.put("type", ExtensionTreatmentType.ExtensionTreatmentTypes.valueOf(type.toString()).ordinal()); + return appKryo.serialize(values); + } + + @Override + public void deserialize(byte[] data) { + Map<String, Integer> values = appKryo.deserialize(data); + srcOfs = values.get("srcOfs"); + dstOfs = values.get("dstOfs"); + nBits = values.get("nBits"); + src = values.get("src"); + dst = values.get("dst"); + type = new ExtensionTreatmentType(values.get("type").intValue()); + } + + @Override + public int srcOffset() { + return srcOfs; + } + + @Override + public int dstOffset() { + return dstOfs; + } + + @Override + public int src() { + return src; + } + + @Override + public int dst() { + return dst; + } + + @Override + public int nBits() { + return nBits; + } + + @Override + public int hashCode() { + return Objects.hash(srcOfs, dstOfs, src, dst, nBits); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof DefaultMoveExtensionTreatment) { + DefaultMoveExtensionTreatment that = (DefaultMoveExtensionTreatment) obj; + return Objects.equals(srcOfs, that.srcOfs) + && Objects.equals(dstOfs, that.dstOfs) + && Objects.equals(src, that.src) + && Objects.equals(dst, that.dst) + && Objects.equals(nBits, that.nBits); + + } + return false; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()).add("srcOfs", srcOfs) + .add("dstOfs", dstOfs).add("nBits", nBits).add("src", src) + .add("dst", dst).toString(); + } +} diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/MoveExtensionTreatment.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/MoveExtensionTreatment.java new file mode 100644 index 00000000..b67e1bed --- /dev/null +++ b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/MoveExtensionTreatment.java @@ -0,0 +1,59 @@ +/* + * 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.onosproject.net.flow.instructions.ExtensionTreatment; + +/** + * The abstraction of Move Treatment. + */ +public interface MoveExtensionTreatment extends ExtensionTreatment { + + /** + * Returns SRC_OFS field of move extension action. + * + * @return SRC_OFS + */ + int srcOffset(); + + /** + * Returns DST_OFS field of move extension action. + * + * @return DST_OFS + */ + int dstOffset(); + + /** + * Returns SRC field of move extension action. + * + * @return SRC + */ + int src(); + + /** + * Returns DST field of move extension action. + * + * @return DST + */ + int dst(); + + /** + * Returns N_BITS field of move extension action. + * + * @return N_BITS + */ + int nBits(); +} diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraExtensionSelectorInterpreter.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraExtensionSelectorInterpreter.java new file mode 100644 index 00000000..9f302991 --- /dev/null +++ b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraExtensionSelectorInterpreter.java @@ -0,0 +1,102 @@ +/* + * 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.onosproject.net.behaviour.ExtensionSelectorResolver; +import org.onosproject.net.driver.AbstractHandlerBehaviour; +import org.onosproject.net.flow.criteria.ExtensionSelector; +import org.onosproject.net.flow.criteria.ExtensionSelectorType; +import org.onosproject.openflow.controller.ExtensionSelectorInterpreter; +import org.projectfloodlight.openflow.protocol.OFFactory; +import org.projectfloodlight.openflow.protocol.oxm.OFOxm; + +/** + * Interpreter for Nicira OpenFlow selector extensions. + */ +public class NiciraExtensionSelectorInterpreter + extends AbstractHandlerBehaviour + implements ExtensionSelectorInterpreter, ExtensionSelectorResolver { + + @Override + public boolean supported(ExtensionSelectorType extensionSelectorType) { + if (extensionSelectorType.equals(ExtensionSelectorType.ExtensionSelectorTypes.NICIRA_MATCH_NSH_SPI.type())) { + return true; + } + if (extensionSelectorType.equals(ExtensionSelectorType.ExtensionSelectorTypes.NICIRA_MATCH_NSH_SI.type())) { + return true; + } + if (extensionSelectorType.equals(ExtensionSelectorType.ExtensionSelectorTypes.NICIRA_MATCH_NSH_CH1.type())) { + return true; + } + if (extensionSelectorType.equals(ExtensionSelectorType.ExtensionSelectorTypes.NICIRA_MATCH_NSH_CH2.type())) { + return true; + } + if (extensionSelectorType.equals(ExtensionSelectorType.ExtensionSelectorTypes.NICIRA_MATCH_NSH_CH3.type())) { + return true; + } + if (extensionSelectorType.equals(ExtensionSelectorType.ExtensionSelectorTypes.NICIRA_MATCH_NSH_CH4.type())) { + return true; + } + return false; + } + + @Override + public OFOxm<?> mapSelector(OFFactory factory, ExtensionSelector extensionSelector) { + ExtensionSelectorType type = extensionSelector.type(); + if (type.equals(ExtensionSelectorType.ExtensionSelectorTypes.NICIRA_MATCH_NSH_SPI.type())) { + // TODO + } + if (type.equals(ExtensionSelectorType.ExtensionSelectorTypes.NICIRA_MATCH_NSH_SI.type())) { + // TODO + } + if (type.equals(ExtensionSelectorType.ExtensionSelectorTypes.NICIRA_MATCH_NSH_CH1.type())) { + // TODO + } + if (type.equals(ExtensionSelectorType.ExtensionSelectorTypes.NICIRA_MATCH_NSH_CH2.type())) { + // TODO + } + if (type.equals(ExtensionSelectorType.ExtensionSelectorTypes.NICIRA_MATCH_NSH_CH3.type())) { + // TODO + } + if (type.equals(ExtensionSelectorType.ExtensionSelectorTypes.NICIRA_MATCH_NSH_CH4.type())) { + // TODO + } + return null; + } + + @Override + public ExtensionSelector mapOxm(OFOxm<?> oxm) { + return null; + } + + @Override + public ExtensionSelector getExtensionSelector(ExtensionSelectorType type) { + if (type.equals(ExtensionSelectorType.ExtensionSelectorTypes.NICIRA_MATCH_NSH_SPI.type())) { + return new NiciraMatchNshSpi(); + } + if (type.equals(ExtensionSelectorType.ExtensionSelectorTypes.NICIRA_MATCH_NSH_SI.type())) { + return new NiciraMatchNshSi(); + } + if (type.equals(ExtensionSelectorType.ExtensionSelectorTypes.NICIRA_MATCH_NSH_CH1.type()) + || type.equals(ExtensionSelectorType.ExtensionSelectorTypes.NICIRA_MATCH_NSH_CH2.type()) + || type.equals(ExtensionSelectorType.ExtensionSelectorTypes.NICIRA_MATCH_NSH_CH3.type()) + || type.equals(ExtensionSelectorType.ExtensionSelectorTypes.NICIRA_MATCH_NSH_CH4.type())) { + return new NiciraMatchNshContextHeader(type); + } + return null; + } +} diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraExtensionTreatmentInterpreter.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraExtensionTreatmentInterpreter.java index a7f70f98..5e374d9b 100644 --- a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraExtensionTreatmentInterpreter.java +++ b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraExtensionTreatmentInterpreter.java @@ -31,7 +31,7 @@ import org.projectfloodlight.openflow.protocol.oxm.OFOxmTunnelIpv4Dst; import org.projectfloodlight.openflow.types.IPv4Address; /** - * Interpreter for Nicira OpenFlow extensions. + * Interpreter for Nicira OpenFlow treatment extensions. */ public class NiciraExtensionTreatmentInterpreter extends AbstractHandlerBehaviour implements ExtensionTreatmentInterpreter, ExtensionTreatmentResolver { @@ -46,8 +46,42 @@ public class NiciraExtensionTreatmentInterpreter extends AbstractHandlerBehaviou ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_RESUBMIT.type())) { return true; } + if (extensionTreatmentType.equals(ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_NSH_SPI.type())) { + return true; + } + if (extensionTreatmentType.equals(ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_NSH_SI.type())) { + return true; + } + if (extensionTreatmentType.equals(ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_NSH_CH1.type())) { + return true; + } + if (extensionTreatmentType.equals(ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_NSH_CH2.type())) { + return true; + } + if (extensionTreatmentType.equals(ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_NSH_CH3.type())) { + return true; + } + if (extensionTreatmentType.equals(ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_NSH_CH4.type())) { + return true; + } if (extensionTreatmentType.equals( - ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_NSH_SPI.type())) { + ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_RESUBMIT_TABLE.type())) { + return true; + } + if (extensionTreatmentType.equals( + ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_MOV_ARP_SHA_TO_THA.type())) { + return true; + } + if (extensionTreatmentType.equals( + ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_MOV_ARP_SPA_TO_TPA.type())) { + return true; + } + if (extensionTreatmentType.equals( + ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_MOV_ETH_SRC_TO_DST.type())) { + return true; + } + if (extensionTreatmentType.equals( + ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_MOV_IP_SRC_TO_DST.type())) { return true; } return false; @@ -62,11 +96,35 @@ public class NiciraExtensionTreatmentInterpreter extends AbstractHandlerBehaviou IPv4Address.of(tunnelDst.tunnelDst().toInt()))); } if (type.equals(ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_RESUBMIT.type())) { - // TODO this will be implemented later + // TODO this will be implemented later } if (type.equals(ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_NSH_SPI.type())) { // TODO this will be implemented later } + if (type.equals(ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_RESUBMIT_TABLE.type())) { + // TODO this will be implemented later + } + if (type.equals(ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_NSH_SI.type())) { + // TODO this will be implemented later + } + if (type.equals(ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_NSH_CH1.type())) { + // TODO this will be implemented later + } + if (type.equals(ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_NSH_CH2.type())) { + // TODO this will be implemented later + } + if (type.equals(ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_NSH_CH3.type())) { + // TODO this will be implemented later + } + if (type.equals(ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_NSH_CH4.type())) { + // TODO this will be implemented later + } + if (type.equals(ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_MOV_ETH_SRC_TO_DST.type()) + || type.equals(ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_MOV_ARP_SPA_TO_TPA.type()) + || type.equals(ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_MOV_ETH_SRC_TO_DST.type()) + || type.equals(ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_MOV_IP_SRC_TO_DST.type())) { + // TODO this will be implemented later + } return null; } @@ -95,9 +153,33 @@ public class NiciraExtensionTreatmentInterpreter extends AbstractHandlerBehaviou if (type.equals(ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_RESUBMIT.type())) { return new NiciraResubmit(); } + if (type.equals(ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_RESUBMIT_TABLE.type())) { + return new NiciraResubmitTable(); + } if (type.equals(ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_NSH_SPI.type())) { return new NiciraSetNshSpi(); } + if (type.equals(ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_NSH_SI.type())) { + return new NiciraSetNshSi(); + } + if (type.equals(ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_NSH_CH1.type()) + || type.equals(ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_NSH_CH2.type()) + || type.equals(ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_NSH_CH3.type()) + || type.equals(ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_NSH_CH4.type())) { + return new NiciraSetNshContextHeader(type); + } + if (type.equals(ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_MOV_ARP_SHA_TO_THA.type())) { + return NiciraMoveTreatmentFactory.createNiciraMovArpShaToTha(); + } + if (type.equals(ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_MOV_ARP_SPA_TO_TPA.type())) { + return NiciraMoveTreatmentFactory.createNiciraMovArpSpaToTpa(); + } + if (type.equals(ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_MOV_ETH_SRC_TO_DST.type())) { + return NiciraMoveTreatmentFactory.createNiciraMovEthSrcToDst(); + } + if (type.equals(ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_MOV_IP_SRC_TO_DST.type())) { + return NiciraMoveTreatmentFactory.createNiciraMovIpSrcToDst(); + } 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/NiciraMatchNshContextHeader.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraMatchNshContextHeader.java new file mode 100644 index 00000000..5f37247f --- /dev/null +++ b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraMatchNshContextHeader.java @@ -0,0 +1,95 @@ +/* + * 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 static com.google.common.base.MoreObjects.toStringHelper; + +import java.util.Objects; + +import org.onlab.util.KryoNamespace; +import org.onosproject.net.NshContextHeader; +import org.onosproject.net.flow.AbstractExtension; +import org.onosproject.net.flow.criteria.ExtensionSelector; +import org.onosproject.net.flow.criteria.ExtensionSelectorType; +/** + * Implementation of Nsh context header criterion. + */ +public final class NiciraMatchNshContextHeader extends AbstractExtension implements ExtensionSelector { + private NshContextHeader nshContextHeader; + private ExtensionSelectorType type; + + private final KryoNamespace appKryo = new KryoNamespace.Builder().build(); + + /** + * Constructor to create Nsh context header. + * + * @param type extension selector type + */ + public NiciraMatchNshContextHeader(ExtensionSelectorType type) { + this.nshContextHeader = null; + this.type = type; + } + + /** + * Gets the nsh context header to match. + * + * @return the nsh context header to match + */ + public NshContextHeader nshContextHeader() { + return nshContextHeader; + } + + @Override + public byte[] serialize() { + return appKryo.serialize(nshContextHeader.nshContextHeader()); + } + + @Override + public void deserialize(byte[] data) { + nshContextHeader = nshContextHeader.of(appKryo.deserialize(data)); + + } + + @Override + public ExtensionSelectorType type() { + return type; + } + + @Override + public String toString() { + return toStringHelper(type().toString()) + .add("nshContextHeader", nshContextHeader.toString()) + .toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type(), nshContextHeader); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof NiciraMatchNshContextHeader) { + NiciraMatchNshContextHeader that = (NiciraMatchNshContextHeader) obj; + return Objects.equals(nshContextHeader, that.nshContextHeader) && + Objects.equals(this.type(), that.type()); + } + return false; + } +} diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraMatchNshSi.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraMatchNshSi.java new file mode 100644 index 00000000..c98a584a --- /dev/null +++ b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraMatchNshSi.java @@ -0,0 +1,91 @@ +/* + * 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 static com.google.common.base.MoreObjects.toStringHelper; + +import java.util.Objects; + +import org.onlab.util.KryoNamespace; +import org.onosproject.net.NshServiceIndex; +import org.onosproject.net.flow.AbstractExtension; +import org.onosproject.net.flow.criteria.ExtensionSelector; +import org.onosproject.net.flow.criteria.ExtensionSelectorType; +/** + * Implementation of NSH Service Index(SI). + */ +public final class NiciraMatchNshSi extends AbstractExtension implements ExtensionSelector { + + private NshServiceIndex nshSi; + + private final KryoNamespace appKryo = new KryoNamespace.Builder().build(); + + /** + * Default constructor. + * + */ + public NiciraMatchNshSi() { + this.nshSi = null; + } + + /** + * Gets the nsh service index to match. + * + * @return the si to match + */ + public NshServiceIndex nshSi() { + return nshSi; + } + + @Override + public byte[] serialize() { + return appKryo.serialize(nshSi.serviceIndex()); + } + + @Override + public void deserialize(byte[] data) { + nshSi = NshServiceIndex.of(appKryo.deserialize(data)); + } + + @Override + public ExtensionSelectorType type() { + return ExtensionSelectorType.ExtensionSelectorTypes.NICIRA_MATCH_NSH_SI.type(); + } + + @Override + public String toString() { + return toStringHelper(type().toString()) + .add("nshSi", nshSi.toString()) + .toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type(), nshSi); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof NiciraMatchNshSi) { + NiciraMatchNshSi that = (NiciraMatchNshSi) obj; + return Objects.equals(nshSi, that.nshSi); + } + return false; + } +} diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraMatchNshSpi.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraMatchNshSpi.java new file mode 100644 index 00000000..42bb78d4 --- /dev/null +++ b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraMatchNshSpi.java @@ -0,0 +1,91 @@ +/* + * 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 static com.google.common.base.MoreObjects.toStringHelper; + +import java.util.Objects; + +import org.onlab.util.KryoNamespace; +import org.onosproject.net.NshServicePathId; +import org.onosproject.net.flow.AbstractExtension; +import org.onosproject.net.flow.criteria.ExtensionSelector; +import org.onosproject.net.flow.criteria.ExtensionSelectorType; + +/** + * Implementation of NSH Service Path Id selector. + */ +public final class NiciraMatchNshSpi extends AbstractExtension implements ExtensionSelector { + private NshServicePathId nshSpi; + + private final KryoNamespace appKryo = new KryoNamespace.Builder().build(); + + /** + * Default constructor. + */ + public NiciraMatchNshSpi() { + this.nshSpi = null; + } + + /** + * Gets the network service path id to match. + * + * @return the nshSpi to match + */ + public NshServicePathId nshSpi() { + return nshSpi; + } + + @Override + public ExtensionSelectorType type() { + return ExtensionSelectorType.ExtensionSelectorTypes.NICIRA_MATCH_NSH_SPI.type(); + } + + @Override + public byte[] serialize() { + return appKryo.serialize(nshSpi); + } + + @Override + public void deserialize(byte[] data) { + nshSpi = NshServicePathId.of(appKryo.deserialize(data)); + } + + @Override + public String toString() { + return toStringHelper(type().toString()) + .add("nshSpi", nshSpi.toString()) + .toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type(), nshSpi); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof NiciraMatchNshSpi) { + NiciraMatchNshSpi that = (NiciraMatchNshSpi) obj; + return Objects.equals(nshSpi, that.nshSpi) && + Objects.equals(this.type(), that.type()); + } + return false; + } +} diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraMoveTreatmentFactory.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraMoveTreatmentFactory.java new file mode 100644 index 00000000..ac42a3b2 --- /dev/null +++ b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraMoveTreatmentFactory.java @@ -0,0 +1,100 @@ +/* + * 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.onosproject.net.flow.instructions.ExtensionTreatment; +import org.onosproject.net.flow.instructions.ExtensionTreatmentType; + +/** + * The factory of move treatment. + */ +public final class NiciraMoveTreatmentFactory { + + /** + * Public constructor is prohibited. + */ + private NiciraMoveTreatmentFactory() { + + } + + /** + * Creates a move treatment that move arp sha to tha. + * + * @return ExtensionTreatment + */ + public static ExtensionTreatment createNiciraMovArpShaToTha() { + int srcOfs = 0; + int dstOfs = 0; + int nBits = 48; + int srcSha = 0x00012206; + int dstTha = 0x00012406; + return new DefaultMoveExtensionTreatment(srcOfs, dstOfs, nBits, srcSha, + dstTha, + ExtensionTreatmentType.ExtensionTreatmentTypes + .NICIRA_MOV_ARP_SHA_TO_THA.type()); + } + + /** + * Creates a move treatment that move arp spa to tpa. + * + * @return ExtensionTreatment + */ + public static ExtensionTreatment createNiciraMovArpSpaToTpa() { + int srcOfs = 0; + int dstOfs = 0; + int nBits = 32; + int srcSpa = 0x00002004; + int dstTpa = 0x00002204; + return new DefaultMoveExtensionTreatment(srcOfs, dstOfs, nBits, srcSpa, + dstTpa, + ExtensionTreatmentType.ExtensionTreatmentTypes + .NICIRA_MOV_ARP_SPA_TO_TPA.type()); + } + + /** + * Creates a move treatment that move eth src to dst. + * + * @return ExtensionTreatment + */ + public static ExtensionTreatment createNiciraMovEthSrcToDst() { + int srcOfs = 0; + int dstOfs = 0; + int nBits = 48; + int srcEth = 0x00000406; + int dstEth = 0x00000206; + return new DefaultMoveExtensionTreatment(srcOfs, dstOfs, nBits, srcEth, + dstEth, + ExtensionTreatmentType.ExtensionTreatmentTypes + .NICIRA_MOV_ETH_SRC_TO_DST.type()); + } + + /** + * Creates a move treatment that move ip src to dst. + * + * @return ExtensionTreatment + */ + public static ExtensionTreatment createNiciraMovIpSrcToDst() { + int srcOfs = 0; + int dstOfs = 0; + int nBits = 32; + int srcIp = 0x00000e04; + int dstIp = 0x00001006; + return new DefaultMoveExtensionTreatment(srcOfs, dstOfs, nBits, srcIp, + dstIp, + ExtensionTreatmentType.ExtensionTreatmentTypes + .NICIRA_MOV_IP_SRC_TO_DST.type()); + } +} diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraResubmit.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraResubmit.java index 481b6f9c..b85af4f2 100644 --- a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraResubmit.java +++ b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraResubmit.java @@ -19,7 +19,8 @@ package org.onosproject.driver.extensions; import com.google.common.base.MoreObjects; import org.onlab.util.KryoNamespace; import org.onosproject.net.PortNumber; -import org.onosproject.net.flow.instructions.AbstractExtensionTreatment; +import org.onosproject.net.flow.AbstractExtension; +import org.onosproject.net.flow.instructions.ExtensionTreatment; import org.onosproject.net.flow.instructions.ExtensionTreatmentType; import org.onosproject.store.serializers.PortNumberSerializer; @@ -30,7 +31,7 @@ import static com.google.common.base.Preconditions.checkNotNull; /** * Nicira resubmit extension instruction. */ -public class NiciraResubmit extends AbstractExtensionTreatment { +public class NiciraResubmit extends AbstractExtension implements ExtensionTreatment { private PortNumber inPort; diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraResubmitTable.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraResubmitTable.java new file mode 100644 index 00000000..4743d217 --- /dev/null +++ b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraResubmitTable.java @@ -0,0 +1,114 @@ +/* + * 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.util.KryoNamespace; +import org.onosproject.net.PortNumber; +import org.onosproject.net.flow.AbstractExtension; +import org.onosproject.net.flow.instructions.ExtensionTreatment; +import org.onosproject.net.flow.instructions.ExtensionTreatmentType; +import org.onosproject.store.serializers.PortNumberSerializer; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Nicira resubmit-table extension instruction. + */ +public class NiciraResubmitTable extends AbstractExtension implements + ExtensionTreatment { + + //the list of the in port number(PortNumber) and the table(short) + private List<Object> inPortAndTable = new ArrayList<Object>(); + + private final KryoNamespace appKryo = new KryoNamespace.Builder() + .register(ArrayList.class) + .register(new PortNumberSerializer(), PortNumber.class) + .register(short.class) + .register(byte[].class) + .build(); + + /** + * Creates a new resubmit-table instruction. + */ + NiciraResubmitTable() { + inPortAndTable = null; + } + + /** + * Creates a new resubmit-table instruction with a particular inPort and table. + * + * @param inPortAndTable the list of in port number and table + */ + public NiciraResubmitTable(List<Object> inPortAndTable) { + checkNotNull(inPortAndTable); + this.inPortAndTable = inPortAndTable; + } + + /** + * Gets the inPortAndTable. + * + * @return inPortAndTable + */ + public List<Object> inPortAndTable() { + return inPortAndTable; + } + + @Override + public ExtensionTreatmentType type() { + return ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_RESUBMIT_TABLE.type(); + } + + @Override + public void deserialize(byte[] data) { + inPortAndTable = appKryo.deserialize(data); + } + + @Override + public byte[] serialize() { + return appKryo.serialize(inPortAndTable); + } + + @Override + public int hashCode() { + return Objects.hash(inPortAndTable); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof NiciraResubmitTable) { + NiciraResubmitTable that = (NiciraResubmitTable) obj; + return Objects.equals(inPortAndTable, that.inPortAndTable); + + } + return false; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("inPortAndTable", inPortAndTable).toString(); + } +} diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraSetNshContextHeader.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraSetNshContextHeader.java new file mode 100644 index 00000000..c8267984 --- /dev/null +++ b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraSetNshContextHeader.java @@ -0,0 +1,108 @@ +/* + * 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.util.KryoNamespace; +import org.onosproject.net.flow.AbstractExtension; +import org.onosproject.net.flow.instructions.ExtensionTreatment; +import org.onosproject.net.flow.instructions.ExtensionTreatmentType; + +import java.util.Objects; + +/** + * Nicira set NSH Context header extension instruction. + */ +public class NiciraSetNshContextHeader extends AbstractExtension implements + ExtensionTreatment { + + private int nshCh; + private ExtensionTreatmentType type; + + private final KryoNamespace appKryo = new KryoNamespace.Builder().build(); + + /** + * Creates a new set nsh context header instruction. + * + * @param type extension treatment type + */ + NiciraSetNshContextHeader(ExtensionTreatmentType type) { + this.nshCh = 0; + this.type = type; + } + + /** + * Creates a new set nsh context header instruction. + * + * @param nshCh nsh context header + * @param type extension treatment type + */ + NiciraSetNshContextHeader(int nshCh, ExtensionTreatmentType type) { + this.nshCh = nshCh; + this.type = type; + } + + /** + * Gets the nsh context header. + * + * @return nsh context header + */ + public int nshCh() { + return nshCh; + } + + @Override + public ExtensionTreatmentType type() { + return type; + } + + @Override + public void deserialize(byte[] data) { + nshCh = appKryo.deserialize(data); + } + + @Override + public byte[] serialize() { + return appKryo.serialize(nshCh); + } + + @Override + public int hashCode() { + return Objects.hash(nshCh, type); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof NiciraSetNshContextHeader) { + NiciraSetNshContextHeader that = (NiciraSetNshContextHeader) obj; + return Objects.equals(nshCh, that.nshCh) && Objects.equals(type, that.type); + + } + return false; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("nshCh", nshCh) + .add("type", type) + .toString(); + } +} diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraSetNshSi.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraSetNshSi.java new file mode 100644 index 00000000..1480508e --- /dev/null +++ b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraSetNshSi.java @@ -0,0 +1,101 @@ +/* + * 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.util.KryoNamespace; +import org.onosproject.net.flow.AbstractExtension; +import org.onosproject.net.flow.instructions.ExtensionTreatment; +import org.onosproject.net.flow.instructions.ExtensionTreatmentType; + +import java.util.Objects; + +/** + * Nicira set NSH SI extension instruction. + */ +public class NiciraSetNshSi extends AbstractExtension implements + ExtensionTreatment { + + private byte nshSi; + + private final KryoNamespace appKryo = new KryoNamespace.Builder().build(); + + /** + * Creates a new set nsh si instruction. + */ + NiciraSetNshSi() { + nshSi = 0; + } + + /** + * Creates a new set nsh si instruction with given si. + * + * @param nshSi nsh service index + */ + NiciraSetNshSi(byte nshSi) { + this.nshSi = nshSi; + } + + /** + * Gets the nsh service index. + * + * @return nsh service index + */ + public byte nshSi() { + return nshSi; + } + + @Override + public ExtensionTreatmentType type() { + return ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_NSH_SI.type(); + } + + @Override + public void deserialize(byte[] data) { + nshSi = appKryo.deserialize(data); + } + + @Override + public byte[] serialize() { + return appKryo.serialize(nshSi); + } + + @Override + public int hashCode() { + return Objects.hash(nshSi); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof NiciraSetNshSi) { + NiciraSetNshSi that = (NiciraSetNshSi) obj; + return Objects.equals(nshSi, that.nshSi); + + } + return false; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("nshSi", nshSi) + .toString(); + } +} diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraSetNshSpi.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraSetNshSpi.java index 25358702..1a47173e 100644 --- a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraSetNshSpi.java +++ b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/extensions/NiciraSetNshSpi.java @@ -16,26 +16,23 @@ package org.onosproject.driver.extensions; -import java.util.Objects; - +import com.google.common.base.MoreObjects; import org.onlab.util.KryoNamespace; -import org.onosproject.net.flow.instructions.AbstractExtensionTreatment; +import org.onosproject.net.flow.AbstractExtension; +import org.onosproject.net.flow.instructions.ExtensionTreatment; import org.onosproject.net.flow.instructions.ExtensionTreatmentType; -import org.onosproject.store.serializers.Ip4AddressSerializer; -import com.google.common.base.MoreObjects; +import java.util.Objects; /** * Nicira set NSH SPI extension instruction. */ -public class NiciraSetNshSpi extends AbstractExtensionTreatment { +public class NiciraSetNshSpi extends AbstractExtension implements + ExtensionTreatment { private int nshSpi; - private final KryoNamespace appKryo = new KryoNamespace.Builder() - .register(new Ip4AddressSerializer(), Integer.class) - .register(byte[].class) - .build(); + private final KryoNamespace appKryo = new KryoNamespace.Builder().build(); /** * Creates a new set nsh spi instruction. 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 index ec23a9e0..e28a1e24 100644 --- 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 @@ -19,7 +19,8 @@ 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.AbstractExtensionTreatment; +import org.onosproject.net.flow.AbstractExtension; +import org.onosproject.net.flow.instructions.ExtensionTreatment; import org.onosproject.net.flow.instructions.ExtensionTreatmentType; import org.onosproject.store.serializers.Ip4AddressSerializer; @@ -30,7 +31,8 @@ import static com.google.common.base.Preconditions.checkNotNull; /** * Nicira set tunnel destination extension instruction. */ -public class NiciraSetTunnelDst extends AbstractExtensionTreatment { +public class NiciraSetTunnelDst extends AbstractExtension implements + ExtensionTreatment { private Ip4Address tunnelDst; diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/handshaker/CalientFiberSwitchHandshaker.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/handshaker/CalientFiberSwitchHandshaker.java index df4dfa53..270008f3 100644 --- a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/handshaker/CalientFiberSwitchHandshaker.java +++ b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/handshaker/CalientFiberSwitchHandshaker.java @@ -17,7 +17,14 @@ package org.onosproject.driver.handshaker; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; +import org.onlab.util.Spectrum; +import org.onosproject.net.ChannelSpacing; +import org.onosproject.net.DefaultOchSignalComparator; import org.onosproject.net.Device; +import org.onosproject.net.GridType; +import org.onosproject.net.OchSignal; +import org.onosproject.net.PortNumber; +import org.onosproject.net.behaviour.LambdaQuery; import org.onosproject.openflow.controller.OpenFlowOpticalSwitch; import org.onosproject.openflow.controller.PortDescPropertyType; import org.onosproject.openflow.controller.driver.AbstractOpenFlowSwitch; @@ -41,9 +48,24 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.Collectors; +import java.util.stream.IntStream; -public class CalientFiberSwitchHandshaker extends AbstractOpenFlowSwitch implements OpenFlowOpticalSwitch { +/** + * Driver for Calient S160 Optical Circuit Switch. Untested on Calient S320 but probably works ok. + * + * Driver implements custom handshaker, and rewrites flow stats as expected by the device. Port stats are currently + * not supported. + * + * The device consists of OMS ports only, and each port exposes lambda resources covering the whole + * usable optical spectrum (U to O band, see {@link Spectrum} for spectrum definitions). + */ +public class CalientFiberSwitchHandshaker + extends AbstractOpenFlowSwitch + implements OpenFlowOpticalSwitch, LambdaQuery { private final AtomicBoolean driverHandshakeComplete = new AtomicBoolean(false); private List<OFCalientPortDescStatsEntry> fiberPorts = new ArrayList<>(); @@ -178,4 +200,22 @@ public class CalientFiberSwitchHandshaker extends AbstractOpenFlowSwitch impleme super.sendMsg(newMsg); } + + @Override + public SortedSet<OchSignal> queryLambdas(PortNumber port) { + // S160 data sheet + // Wavelength range: 1260 - 1630 nm + long startSpacingMultiplier = Spectrum.U_BAND_MIN.subtract(Spectrum.CENTER_FREQUENCY).asHz() / + ChannelSpacing.CHL_12P5GHZ.frequency().asHz(); + long stopSpacingMultiplier = Spectrum.O_BAND_MAX.subtract(Spectrum.CENTER_FREQUENCY).asHz() / + ChannelSpacing.CHL_12P5GHZ.frequency().asHz(); + List<OchSignal> lambdas = IntStream.rangeClosed((int) startSpacingMultiplier, (int) stopSpacingMultiplier) + .mapToObj(x -> new OchSignal(GridType.FLEX, ChannelSpacing.CHL_12P5GHZ, x, 1)) + .collect(Collectors.toList()); + + SortedSet<OchSignal> result = new TreeSet<>(new DefaultOchSignalComparator()); + result.addAll(lambdas); + + return result; + } } diff --git a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/handshaker/OfOpticalSwitchImplLinc13.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/handshaker/OfOpticalSwitchImplLinc13.java index f91e2a7e..23378e95 100644 --- a/framework/src/onos/drivers/src/main/java/org/onosproject/driver/handshaker/OfOpticalSwitchImplLinc13.java +++ b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/handshaker/OfOpticalSwitchImplLinc13.java @@ -16,7 +16,13 @@ package org.onosproject.driver.handshaker; import com.google.common.collect.ImmutableSet; +import org.onosproject.net.ChannelSpacing; +import org.onosproject.net.DefaultOchSignalComparator; import org.onosproject.net.Device; +import org.onosproject.net.GridType; +import org.onosproject.net.OchSignal; +import org.onosproject.net.PortNumber; +import org.onosproject.net.behaviour.LambdaQuery; import org.onosproject.openflow.controller.OpenFlowOpticalSwitch; import org.onosproject.openflow.controller.PortDescPropertyType; import org.onosproject.openflow.controller.driver.AbstractOpenFlowSwitch; @@ -42,7 +48,6 @@ import org.projectfloodlight.openflow.protocol.match.Match; import org.projectfloodlight.openflow.protocol.match.MatchField; import org.projectfloodlight.openflow.protocol.oxm.OFOxmExpOchSigId; import org.projectfloodlight.openflow.types.CircuitSignalID; -import org.projectfloodlight.openflow.types.OFPort; import org.projectfloodlight.openflow.types.U8; import java.io.IOException; @@ -51,7 +56,11 @@ import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.Collectors; +import java.util.stream.IntStream; /** * LINC-OE Optical Emulator switch class. @@ -65,10 +74,13 @@ import java.util.concurrent.atomic.AtomicBoolean; * As LINC implements custom OF optical extensions (in contrast to the final standard as specified in * ONF TS-022 (March 15, 2015), we need to rewrite flow stat requests and flow mods in {@link #sendMsg(OFMessage)}. * + * LINC exposes OchSignal resources: 80 lambdas of 50 GHz around ITU-T G.694.1 center frequency 193.1 GHz. + * */ public class OfOpticalSwitchImplLinc13 - extends AbstractOpenFlowSwitch implements OpenFlowOpticalSwitch { + extends AbstractOpenFlowSwitch implements OpenFlowOpticalSwitch, LambdaQuery { + private static final int LAMBDA_COUNT = 80; private final AtomicBoolean driverHandshakeComplete = new AtomicBoolean(false); private long barrierXidToWaitFor = -1; @@ -267,13 +279,13 @@ public class OfOpticalSwitchImplLinc13 /** * Checks if given port is also part of the regular port desc stats, i.e., is the port a tap port. * - * @param port given OF port + * @param port given port number * @return true if the port is a tap (OCh), false otherwise (OMS port) */ - private boolean hasPort(OFPort port) { + private boolean isOChPort(long port) { for (OFPortDescStatsReply reply : this.ports) { for (OFPortDesc p : reply.getEntries()) { - if (p.getPortNo().equals(port)) { + if (p.getPortNo().getPortNumber() == port) { return true; } } @@ -328,7 +340,7 @@ public class OfOpticalSwitchImplLinc13 short signalType; // FIXME: use constants once loxi has full optical extensions - if (hasPort(p.getPortNo())) { + if (isOChPort(p.getPortNo().getPortNumber())) { signalType = 5; // OCH port } else { signalType = 2; // OMS port @@ -351,4 +363,23 @@ public class OfOpticalSwitchImplLinc13 public Set<PortDescPropertyType> getPortTypes() { return ImmutableSet.of(PortDescPropertyType.OPTICAL_TRANSPORT); } + + @Override + public SortedSet<OchSignal> queryLambdas(PortNumber port) { + // OCh ports don't have lambdas + if (isOChPort(port.toLong())) { + return Collections.emptySortedSet(); + } + + // OMS ports expose 80 lambdas of 50GHz width, centered around the ITU-T center frequency. + // We report these with a spacing of 12.5 GHz. + List<OchSignal> lambdas = IntStream.range(0, LAMBDA_COUNT) + .mapToObj(x -> new OchSignal(GridType.FLEX, ChannelSpacing.CHL_12P5GHZ, x - (LAMBDA_COUNT / 2), 1)) + .collect(Collectors.toList()); + + SortedSet<OchSignal> result = new TreeSet<>(new DefaultOchSignalComparator()); + result.addAll(lambdas); + + return result; + } } 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 index 937c9ac8..02522cf1 100644 --- 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 @@ -39,7 +39,9 @@ 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; @@ -62,6 +64,14 @@ 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, @@ -122,16 +132,101 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline { 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 Collection<FlowRule> processSpecific(ForwardingObjective fwd) { + 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 criteraia"); + log.warn("processSpecific: Unsupported forwarding objective criteria" + + "ethType:{} in dev:{}", ethType, deviceId); fail(fwd, ObjectiveError.UNSUPPORTED); return Collections.emptySet(); } @@ -143,8 +238,8 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline { .matchIPDst(((IPCriterion) selector.getCriterion(Criterion.Type.IPV4_DST)).ip()); forTableId = UNICAST_ROUTING_TABLE; - log.debug("processing IPv4 specific forwarding objective {} hash{} in dev:{}", - fwd.id(), fwd.hashCode(), deviceId); + log.debug("processing IPv4 specific forwarding objective {} -> next:{}" + + " in dev:{}", fwd.id(), fwd.nextId(), deviceId); } else { filteredSelector .matchEthType(Ethernet.MPLS_UNICAST) @@ -156,8 +251,8 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline { filteredSelector.matchMplsBos(bos.mplsBos()); } forTableId = MPLS_TABLE_1; - log.debug("processing MPLS specific forwarding objective {} hash:{} in dev {}", - fwd.id(), fwd.hashCode(), deviceId); + log.debug("processing MPLS specific forwarding objective {} -> next:{}" + + " in dev {}", fwd.id(), fwd.nextId(), deviceId); } TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder(); @@ -197,7 +292,6 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline { return Collections.singletonList(ruleBuilder.build()); } - @Override protected void initializePipeline() { processPortTable(); @@ -210,7 +304,6 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline { processAclTable(); } - @Override protected void processPortTable() { FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); @@ -239,7 +332,6 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline { })); } - @Override protected void processTmacTable() { //table miss entry FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); @@ -270,7 +362,6 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline { })); } - @Override protected void processIpTable() { //table miss entry FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); @@ -278,6 +369,7 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline { 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) @@ -301,7 +393,6 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline { })); } - @Override protected void processMplsTable() { //table miss entry FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); @@ -374,7 +465,6 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline { })); } - @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/OFDPA2Pipeline.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/OFDPA2Pipeline.java index 863caebb..5f84b43a 100644 --- 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 @@ -18,7 +18,6 @@ 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.ArrayDeque; import java.util.ArrayList; import java.util.Collection; @@ -28,6 +27,7 @@ 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; @@ -35,14 +35,9 @@ import java.util.concurrent.atomic.AtomicInteger; 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; @@ -99,10 +94,6 @@ 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; @@ -160,7 +151,6 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline protected ApplicationId driverId; protected PacketService packetService; protected DeviceService deviceService; - private InternalPacketProcessor processor = new InternalPacketProcessor(); protected KryoNamespace appKryo = new KryoNamespace.Builder() .register(KryoNamespaces.API) .register(GroupKey.class) @@ -170,7 +160,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline .register(ArrayDeque.class) .build(); - private Cache<GroupKey, OfdpaNextGroup> pendingNextObjectives; + private Cache<GroupKey, List<OfdpaNextGroup>> pendingNextObjectives; private ConcurrentHashMap<GroupKey, Set<GroupChainElem>> pendingGroups; private ScheduledExecutorService groupChecker = @@ -196,10 +186,12 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline pendingNextObjectives = CacheBuilder.newBuilder() .expireAfterWrite(20, TimeUnit.SECONDS) .removalListener(( - RemovalNotification<GroupKey, OfdpaNextGroup> notification) -> { + RemovalNotification<GroupKey, List<OfdpaNextGroup>> notification) -> { if (notification.getCause() == RemovalCause.EXPIRED) { - fail(notification.getValue().nextObjective(), - ObjectiveError.GROUPINSTALLATIONFAILED); + notification.getValue().forEach(ofdpaNextGrp -> + fail(ofdpaNextGrp.nextObj, + ObjectiveError.GROUPINSTALLATIONFAILED)); + } }).build(); @@ -212,7 +204,6 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline 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( @@ -271,7 +262,6 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline log.warn("Unknown forwarding type {}", fwd.op()); } - flowRuleService.apply(flowOpsBuilder.build(new FlowRuleOperationsContext() { @Override public void onSuccess(FlowRuleOperations ops) { @@ -283,7 +273,6 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED); } })); - } @Override @@ -697,17 +686,57 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline * returned if there is an issue in processing the objective. */ protected Collection<FlowRule> processSpecific(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 criteraia"); + 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(); @@ -716,8 +745,8 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline .matchIPDst(((IPCriterion) selector.getCriterion(Criterion.Type.IPV4_DST)).ip()); forTableId = UNICAST_ROUTING_TABLE; - log.debug("processing IPv4 specific forwarding objective {} in dev:{}", - fwd.id(), deviceId); + log.debug("processing IPv4 specific forwarding objective {} -> next:{}" + + " in dev:{}", fwd.id(), fwd.nextId(), deviceId); } else { filteredSelector .matchEthType(Ethernet.MPLS_UNICAST) @@ -729,8 +758,8 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline filteredSelector.matchMplsBos(bos.mplsBos()); } forTableId = MPLS_TABLE_1; - log.debug("processing MPLS specific forwarding objective {} in dev {}", - fwd.id(), deviceId); + log.debug("processing MPLS specific forwarding objective {} -> next:{}" + + " in dev {}", fwd.id(), fwd.nextId(), deviceId); } TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder(); @@ -754,6 +783,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline // 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(); } @@ -762,7 +792,8 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline // 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!"); + 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(); } @@ -786,6 +817,88 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline 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); @@ -842,9 +955,26 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline * @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(); + // 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()); @@ -860,8 +990,8 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline Collections.singletonList(gkeyChain), nextObj); - // store l3groupkey with the ofdpaGroupChain for the nextObjective that depends on it - pendingNextObjectives.put(groupInfo.outerGrpDesc.appCookie(), ofdpaGrp); + // 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 @@ -869,6 +999,98 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline 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 @@ -895,6 +1117,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline 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; @@ -908,9 +1131,11 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline 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: @@ -935,12 +1160,11 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline vlanid = port2Vlan.get(PortNumber.portNumber(portNum)); } - if (vlanid == null) { - // use metadata - for (Criterion metaCriterion : meta.criteria()) { - if (metaCriterion.type() == Type.VLAN_VID) { - vlanid = ((VlanIdCriterion) metaCriterion).vlanId(); - } + if (vlanid == null && meta != null) { + // use metadata if available + Criterion vidCriterion = meta.getCriterion(Type.VLAN_VID); + if (vidCriterion != null) { + vlanid = ((VlanIdCriterion) vidCriterion).vlanId(); } } @@ -951,6 +1175,14 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline 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 @@ -1077,6 +1309,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline } // 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; @@ -1151,7 +1384,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline // store l2floodgroupkey with the ofdpaGroupChain for the nextObjective // that depends on it - pendingNextObjectives.put(l2floodgroupkey, ofdpaGrp); + updatePendingNextObjective(l2floodgroupkey, ofdpaGrp); for (GroupDescription l2intGrpDesc : l2interfaceGroupDescs) { // store all l2groupkeys with the groupChainElem for the l2floodgroup @@ -1336,7 +1569,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline // store l3ecmpGroupKey with the ofdpaGroupChain for the nextObjective // that depends on it - pendingNextObjectives.put(l3ecmpGroupKey, ofdpaGrp); + updatePendingNextObjective(l3ecmpGroupKey, ofdpaGrp); log.debug("Trying L3ECMP: device:{} gid:{} gkey:{} nextId:{}", deviceId, Integer.toHexString(l3ecmpGroupId), @@ -1422,16 +1655,18 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline processGroupChain(gce); } } else { - OfdpaNextGroup obj = pendingNextObjectives.getIfPresent(key); - if (obj != null) { - 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()); + List<OfdpaNextGroup> objList = pendingNextObjectives.getIfPresent(key); + if (objList != null) { pendingNextObjectives.invalidate(key); - flowObjectiveStore.putNextGroup(obj.nextObjective().id(), obj); + 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); + }); } } }); @@ -1455,16 +1690,18 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline processGroupChain(gce); } } else { - OfdpaNextGroup obj = pendingNextObjectives.getIfPresent(key); - if (obj != null) { - 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()); + List<OfdpaNextGroup> objList = pendingNextObjectives.getIfPresent(key); + if (objList != null) { pendingNextObjectives.invalidate(key); - flowObjectiveStore.putNextGroup(obj.nextObjective().id(), obj); + 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); + }); } } } @@ -1550,418 +1787,6 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline " waiting-on-groups: " + waitOnGroups.get() + " device: " + deviceId); } - - } - - ////////////////////////////////////// - // 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/OpenstackPipeline.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/OpenstackPipeline.java new file mode 100644 index 00000000..7a92b4fa --- /dev/null +++ b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/OpenstackPipeline.java @@ -0,0 +1,286 @@ +/* + * 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/SpringOpenTTP.java b/framework/src/onos/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java index 8ac5eec8..dba4557a 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 @@ -287,24 +287,14 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour 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, - nextObjective.appId()); - log.debug("Creating SIMPLE group for next objective id {} " - + "in dev:{}", nextObjective.id(), deviceId); - pendingGroups.put(key, nextObjective); - groupService.addGroup(groupDescription); + // 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: @@ -624,8 +614,9 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour if (next != null) { SpringOpenGroup soGroup = appKryo.deserialize(next.data()); if (soGroup.dummy) { - log.debug("Adding flow-actions for fwd. obj. {} " - + "in dev: {}", fwd.id(), deviceId); + 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); } @@ -639,7 +630,8 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour } treatmentBuilder.deferred().group(group.id()); log.debug("Adding OUTGROUP action to group:{} for fwd. obj. {} " - + "in dev: {}", group.id(), fwd.id(), deviceId); + + "for next:{} in dev: {}", group.id(), fwd.id(), + fwd.nextId(), deviceId); } } else { log.warn("processSpecific: No associated next objective object"); @@ -705,10 +697,11 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour if (next != null) { SpringOpenGroup soGrp = appKryo.deserialize(next.data()); if (soGrp.dummy) { - log.debug("Adding flow-actions for fwd. obj. {} " - + "in dev: {}", fwd.id(), deviceId); + log.debug("Adding {} flow-actions for fwd. obj. {} " + + "in dev: {}", soGrp.treatment.allInstructions().size(), + fwd.id(), deviceId); for (Instruction ins : soGrp.treatment.allInstructions()) { - treatmentBuilder.add(ins); + treatmentBuilder.deferred().add(ins); } } else { GroupKey key = soGrp.key; @@ -773,6 +766,12 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour 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, @@ -783,12 +782,6 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour vlanIdCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan); } - /* - * 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. - */ List<FlowRule> rules = new ArrayList<>(); TrafficSelector.Builder selectorIp = DefaultTrafficSelector .builder(); 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 a172c18b..2494e123 100644 --- a/framework/src/onos/drivers/src/main/resources/onos-drivers.xml +++ b/framework/src/onos/drivers/src/main/resources/onos-drivers.xml @@ -36,6 +36,10 @@ impl="org.onosproject.driver.extensions.NiciraExtensionTreatmentInterpreter" /> <behaviour api="org.onosproject.net.behaviour.ExtensionTreatmentResolver" impl="org.onosproject.driver.extensions.NiciraExtensionTreatmentInterpreter" /> + <behaviour api="org.onosproject.openflow.controller.ExtensionSelectorInterpreter" + impl="org.onosproject.driver.extensions.NiciraExtensionSelectorInterpreter" /> + <behaviour api="org.onosproject.net.behaviour.ExtensionSelectorResolver" + impl="org.onosproject.driver.extensions.NiciraExtensionSelectorInterpreter" /> </driver> <!--This driver is for simulated NETCONF devices through of-config tool on top og OVSDB--> <driver name="ovs-netconf" extends="default" @@ -70,6 +74,8 @@ swVersion="LINC-OE OpenFlow Software Switch 1.1"> <behaviour api="org.onosproject.openflow.controller.driver.OpenFlowSwitchDriver" impl="org.onosproject.driver.handshaker.OfOpticalSwitchImplLinc13"/> + <behaviour api="org.onosproject.net.behaviour.LambdaQuery" + impl="org.onosproject.driver.handshaker.OfOpticalSwitchImplLinc13"/> </driver> <driver name="corsa" manufacturer="Corsa" hwVersion="Corsa Element" swVersion="2.3.1"> @@ -131,6 +137,8 @@ swVersion="ocs switch"> <behaviour api="org.onosproject.openflow.controller.driver.OpenFlowSwitchDriver" impl="org.onosproject.driver.handshaker.CalientFiberSwitchHandshaker"/> + <behaviour api="org.onosproject.net.behaviour.LambdaQuery" + impl="org.onosproject.driver.handshaker.CalientFiberSwitchHandshaker"/> </driver> <driver name="onosfw" extends="ovs" manufacturer="" hwVersion="" swVersion=""> diff --git a/framework/src/onos/drivers/src/test/java/org/onosproject/driver/extensions/NiciraSetNshContextHeaderTest.java b/framework/src/onos/drivers/src/test/java/org/onosproject/driver/extensions/NiciraSetNshContextHeaderTest.java new file mode 100644 index 00000000..45d6d941 --- /dev/null +++ b/framework/src/onos/drivers/src/test/java/org/onosproject/driver/extensions/NiciraSetNshContextHeaderTest.java @@ -0,0 +1,68 @@ +/* + * 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 static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; + +import org.junit.Test; +import org.onosproject.net.flow.instructions.ExtensionTreatmentType; + +import com.google.common.testing.EqualsTester; + +/** + * Unit tests for NiciraSetNshContextHeader class. + */ +public class NiciraSetNshContextHeaderTest { + + final NiciraSetNshContextHeader nshCh1 = new NiciraSetNshContextHeader(10, + ExtensionTreatmentType. + ExtensionTreatmentTypes. + NICIRA_SET_NSH_CH1.type()); + final NiciraSetNshContextHeader sameAsNshCh1 = new NiciraSetNshContextHeader(10, + ExtensionTreatmentType. + ExtensionTreatmentTypes. + NICIRA_SET_NSH_CH1.type()); + final NiciraSetNshContextHeader nshCh2 = new NiciraSetNshContextHeader(20, + ExtensionTreatmentType. + ExtensionTreatmentTypes. + NICIRA_SET_NSH_CH1.type()); + + /** + * Checks the operation of equals() methods. + */ + @Test + public void testEquals() { + new EqualsTester().addEqualityGroup(nshCh1, sameAsNshCh1).addEqualityGroup(nshCh2).testEquals(); + } + + /** + * Checks the construction of a NiciraSetNshSi object. + */ + @Test + public void testConstruction() { + final NiciraSetNshContextHeader niciraSetNshCh = new NiciraSetNshContextHeader(10, + ExtensionTreatmentType. + ExtensionTreatmentTypes. + NICIRA_SET_NSH_CH1.type()); + assertThat(niciraSetNshCh, is(notNullValue())); + assertThat(niciraSetNshCh.nshCh(), is(10)); + assertThat(niciraSetNshCh.type(), is(ExtensionTreatmentType. + ExtensionTreatmentTypes. + NICIRA_SET_NSH_CH1.type())); + } +} diff --git a/framework/src/onos/drivers/src/test/java/org/onosproject/driver/extensions/NiciraSetNshSiTest.java b/framework/src/onos/drivers/src/test/java/org/onosproject/driver/extensions/NiciraSetNshSiTest.java new file mode 100644 index 00000000..8541e9f0 --- /dev/null +++ b/framework/src/onos/drivers/src/test/java/org/onosproject/driver/extensions/NiciraSetNshSiTest.java @@ -0,0 +1,52 @@ +/* + * 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 static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; + +import org.junit.Test; + +import com.google.common.testing.EqualsTester; + +/** + * Unit tests for NiciraSetNshSi class. + */ +public class NiciraSetNshSiTest { + + final NiciraSetNshSi nshSi1 = new NiciraSetNshSi((byte) 10); + final NiciraSetNshSi sameAsNshSi1 = new NiciraSetNshSi((byte) 10); + final NiciraSetNshSi nshSi2 = new NiciraSetNshSi((byte) 20); + + /** + * Checks the operation of equals() methods. + */ + @Test + public void testEquals() { + new EqualsTester().addEqualityGroup(nshSi1, sameAsNshSi1).addEqualityGroup(nshSi2).testEquals(); + } + + /** + * Checks the construction of a NiciraSetNshSi object. + */ + @Test + public void testConstruction() { + final NiciraSetNshSi niciraSetNshSi = new NiciraSetNshSi((byte) 15); + assertThat(niciraSetNshSi, is(notNullValue())); + assertThat(niciraSetNshSi.nshSi(), is((byte) 15)); + } +} diff --git a/framework/src/onos/drivers/src/test/java/org/onosproject/driver/extensions/NiciraSetNshSpiTest.java b/framework/src/onos/drivers/src/test/java/org/onosproject/driver/extensions/NiciraSetNshSpiTest.java new file mode 100644 index 00000000..197e3bf9 --- /dev/null +++ b/framework/src/onos/drivers/src/test/java/org/onosproject/driver/extensions/NiciraSetNshSpiTest.java @@ -0,0 +1,52 @@ +/* + * 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 static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; + +import org.junit.Test; + +import com.google.common.testing.EqualsTester; + +/** + * Unit tests for NiciraSetNshSpi class. + */ +public class NiciraSetNshSpiTest { + + final NiciraSetNshSpi nshSpi1 = new NiciraSetNshSpi(10); + final NiciraSetNshSpi sameAsNshSpi1 = new NiciraSetNshSpi(10); + final NiciraSetNshSpi nshSpi2 = new NiciraSetNshSpi(20); + + /** + * Checks the operation of equals() methods. + */ + @Test + public void testEquals() { + new EqualsTester().addEqualityGroup(nshSpi1, sameAsNshSpi1).addEqualityGroup(nshSpi2).testEquals(); + } + + /** + * Checks the construction of a NiciraSetNshSpi object. + */ + @Test + public void testConstruction() { + final NiciraSetNshSpi niciraSetNshSpi = new NiciraSetNshSpi(10); + assertThat(niciraSetNshSpi, is(notNullValue())); + assertThat(niciraSetNshSpi.nshSpi(), is(10)); + } +} |