Implement packet seriailizer and deserializer for LACP
Change-Id: Idbbd87a3ddeb477cac49a65e6a5c768761019e11
diff --git a/utils/misc/src/main/java/org/onlab/packet/EthType.java b/utils/misc/src/main/java/org/onlab/packet/EthType.java
index 6976a15..c69ed145e 100644
--- a/utils/misc/src/main/java/org/onlab/packet/EthType.java
+++ b/utils/misc/src/main/java/org/onlab/packet/EthType.java
@@ -38,6 +38,7 @@
MPLS_UNICAST(0x8847, "mpls_unicast", org.onlab.packet.MPLS.deserializer()),
MPLS_MULTICAST(0x8848, "mpls_multicast", org.onlab.packet.MPLS.deserializer()),
EAPOL(0x888e, "eapol", org.onlab.packet.EAPOL.deserializer()),
+ SLOW(0x8809, "slow", org.onlab.packet.Slow.deserializer()),
UNKNOWN(0, "unknown", null);
diff --git a/utils/misc/src/main/java/org/onlab/packet/MacAddress.java b/utils/misc/src/main/java/org/onlab/packet/MacAddress.java
index 7abf12a..24b2616 100644
--- a/utils/misc/src/main/java/org/onlab/packet/MacAddress.java
+++ b/utils/misc/src/main/java/org/onlab/packet/MacAddress.java
@@ -74,6 +74,10 @@
MacAddress.valueOf("01:80:c2:00:00:00"),
MacAddress.valueOf("01:80:c2:00:00:03"),
MacAddress.valueOf("01:80:c2:00:00:0e"));
+ /**
+ * LACP MAC address.
+ */
+ public static final MacAddress LACP = valueOf("01:80:C2:00:00:02");
public static final int MAC_ADDRESS_LENGTH = 6;
private byte[] address = new byte[MacAddress.MAC_ADDRESS_LENGTH];
diff --git a/utils/misc/src/main/java/org/onlab/packet/Slow.java b/utils/misc/src/main/java/org/onlab/packet/Slow.java
new file mode 100644
index 0000000..ded5185
--- /dev/null
+++ b/utils/misc/src/main/java/org/onlab/packet/Slow.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.onlab.packet;
+
+import com.google.common.collect.ImmutableMap;
+import org.onlab.packet.lacp.Lacp;
+
+import java.nio.ByteBuffer;
+import java.util.Map;
+import java.util.Objects;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static org.onlab.packet.PacketUtils.checkInput;
+
+/**
+ * Implements ethernet slow protocols.
+ */
+public class Slow extends BasePacket {
+ public static final int HEADER_LENGTH = 1;
+
+ public static final byte SUBTYPE_LACP = 0x1;
+ // Subtypes below has not been implemented yet
+ // public static final byte SUBTYPE_LAMP = 0x2;
+ // public static final byte SUBTYPE_OAM = 0x3;
+ // public static final byte SUBTYPE_OSSP = 0xa;
+
+ public static final Map<Byte, Deserializer<? extends IPacket>> PROTOCOL_DESERIALIZER_MAP =
+ ImmutableMap.<Byte, Deserializer<? extends IPacket>>builder()
+ .put(Slow.SUBTYPE_LACP, Lacp.deserializer())
+ .build();
+
+ private byte subtype;
+
+ /**
+ * Gets subtype.
+ *
+ * @return subtype
+ */
+ public byte getSubtype() {
+ return subtype;
+ }
+
+ /**
+ * Sets subtype.
+ *
+ * @param subtype the subtype to set
+ * @return this
+ */
+ public Slow setSubtype(byte subtype) {
+ this.subtype = subtype;
+ return this;
+ }
+
+ /**
+ * Deserializer function for Slow packets.
+ *
+ * @return deserializer function
+ */
+ public static Deserializer<Slow> deserializer() {
+ return (data, offset, length) -> {
+ checkInput(data, offset, length, HEADER_LENGTH);
+
+ Slow slow = new Slow();
+ ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
+ slow.setSubtype(bb.get());
+
+ Deserializer<? extends IPacket> deserializer;
+ if (Slow.PROTOCOL_DESERIALIZER_MAP.containsKey(slow.subtype)) {
+ deserializer = Slow.PROTOCOL_DESERIALIZER_MAP.get(slow.subtype);
+ } else {
+ throw new DeserializationException("Unsupported slow protocol subtype " + Byte.toString(slow.subtype));
+ }
+
+ int remainingLength = bb.limit() - bb.position();
+ slow.payload = deserializer.deserialize(data, bb.position(), remainingLength);
+ slow.payload.setParent(slow);
+
+ return slow;
+ };
+ }
+
+ @Override
+ public byte[] serialize() {
+ int length = HEADER_LENGTH;
+ byte[] payloadData = null;
+ if (this.payload != null) {
+ this.payload.setParent(this);
+ payloadData = this.payload.serialize();
+ length += payloadData.length;
+ }
+
+ final byte[] data = new byte[length];
+
+ final ByteBuffer bb = ByteBuffer.wrap(data);
+ bb.put(this.subtype);
+ if (payloadData != null) {
+ bb.put(payloadData);
+ }
+
+ return data;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(super.hashCode(), subtype);
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!super.equals(obj)) {
+ return false;
+ }
+ if (!(obj instanceof Slow)) {
+ return false;
+ }
+ final Slow other = (Slow) obj;
+
+ return this.subtype == other.subtype;
+ }
+
+ @Override
+ public String toString() {
+ return toStringHelper(getClass())
+ .add("subtype", Byte.toString(subtype))
+ .toString();
+ }
+}
diff --git a/utils/misc/src/main/java/org/onlab/packet/lacp/Lacp.java b/utils/misc/src/main/java/org/onlab/packet/lacp/Lacp.java
new file mode 100644
index 0000000..0124b7f
--- /dev/null
+++ b/utils/misc/src/main/java/org/onlab/packet/lacp/Lacp.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.onlab.packet.lacp;
+
+import com.google.common.collect.ImmutableMap;
+import org.onlab.packet.BasePacket;
+import org.onlab.packet.DeserializationException;
+import org.onlab.packet.Deserializer;
+
+import java.nio.ByteBuffer;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.concurrent.ConcurrentHashMap;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static org.onlab.packet.PacketUtils.checkInput;
+
+public class Lacp extends BasePacket {
+ public static final int HEADER_LENGTH = 1;
+ public static final byte TYPE_ACTOR = 1;
+ public static final byte TYPE_PARTNER = 2;
+ public static final byte TYPE_COLLECTOR = 3;
+ public static final byte TYPE_TERMINATOR = 0;
+
+ private static final Map<Byte, Deserializer<? extends LacpTlv>> PROTOCOL_DESERIALIZER_MAP =
+ ImmutableMap.<Byte, Deserializer<? extends LacpTlv>>builder()
+ .put(TYPE_ACTOR, LacpBaseTlv.deserializer())
+ .put(TYPE_PARTNER, LacpBaseTlv.deserializer())
+ .put(TYPE_COLLECTOR, LacpCollectorTlv.deserializer())
+ .put(TYPE_TERMINATOR, LacpTerminatorTlv.deserializer())
+ .build();
+
+ private byte lacpVersion;
+ private Map<Byte, LacpTlv> tlv = new ConcurrentHashMap<>();
+
+ /**
+ * Gets LACP version.
+ *
+ * @return LACP version
+ */
+ public byte getLacpVersion() {
+ return this.lacpVersion;
+ }
+
+ /**
+ * Sets LACP version.
+ *
+ * @param lacpVersion LACP version
+ * @return this
+ */
+ public Lacp setLacpVersion(byte lacpVersion) {
+ this.lacpVersion = lacpVersion;
+ return this;
+ }
+
+ /**
+ * Gets LACP TLV.
+ *
+ * @return LACP TLV
+ */
+ public Map<Byte, LacpTlv> getTlv() {
+ return this.tlv;
+ }
+
+ /**
+ * Sets LACP TLV.
+ *
+ * @param tlv LACP TLV
+ * @return this
+ */
+ public Lacp setTlv(Map<Byte, LacpTlv> tlv) {
+ this.tlv = tlv;
+ return this;
+ }
+
+ /**
+ * Deserializer function for LACP packets.
+ *
+ * @return deserializer function
+ */
+ public static Deserializer<Lacp> deserializer() {
+ return (data, offset, length) -> {
+ checkInput(data, offset, length, HEADER_LENGTH);
+
+ Lacp lacp = new Lacp();
+ ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
+ lacp.setLacpVersion(bb.get());
+
+ while (bb.limit() - bb.position() > 0) {
+ byte nextType = bb.get();
+ int nextLength = Byte.toUnsignedInt(bb.get());
+ int parseLength = nextLength == 0 ?
+ LacpTerminatorTlv.PADDING_LENGTH : // Special case for LacpTerminatorTlv
+ nextLength - 2;
+
+ Deserializer<? extends LacpTlv> deserializer;
+ if (Lacp.PROTOCOL_DESERIALIZER_MAP.containsKey(nextType)) {
+ deserializer = Lacp.PROTOCOL_DESERIALIZER_MAP.get(nextType);
+ } else {
+ throw new DeserializationException("Unsupported LACP subtype " + Byte.toString(nextType));
+ }
+
+ LacpTlv tlv = deserializer.deserialize(data, bb.position(), parseLength);
+ LacpTlv previousTlv = lacp.tlv.put(nextType, tlv);
+ if (previousTlv != null) {
+ throw new DeserializationException("Duplicated type " + Byte.toString(nextType)
+ + "in LACP TLV");
+ }
+
+ bb.position(bb.position() + parseLength);
+ }
+
+ return lacp;
+ };
+ }
+
+ @Override
+ public byte[] serialize() {
+ byte[] actorInfo = Optional.ofNullable(tlv.get(TYPE_ACTOR)).map(LacpTlv::serialize)
+ .orElse(new byte[0]);
+ byte[] partnerInfo = Optional.ofNullable(tlv.get(TYPE_PARTNER)).map(LacpTlv::serialize)
+ .orElse(new byte[0]);
+ byte[] collectorInfo = Optional.ofNullable(tlv.get(TYPE_COLLECTOR)).map(LacpTlv::serialize)
+ .orElse(new byte[0]);
+ byte[] terminatorInfo = Optional.ofNullable(tlv.get(TYPE_TERMINATOR)).map(LacpTlv::serialize)
+ .orElse(new byte[0]);
+
+ final byte[] data = new byte[HEADER_LENGTH
+ + LacpTlv.HEADER_LENGTH + actorInfo.length
+ + LacpTlv.HEADER_LENGTH + partnerInfo.length
+ + LacpTlv.HEADER_LENGTH + collectorInfo.length
+ + LacpTlv.HEADER_LENGTH + terminatorInfo.length];
+
+ final ByteBuffer bb = ByteBuffer.wrap(data);
+ bb.put(lacpVersion);
+ bb.put(TYPE_ACTOR);
+ bb.put(LacpBaseTlv.LENGTH);
+ bb.put(actorInfo);
+ bb.put(TYPE_PARTNER);
+ bb.put(LacpBaseTlv.LENGTH);
+ bb.put(partnerInfo);
+ bb.put(TYPE_COLLECTOR);
+ bb.put(LacpCollectorTlv.LENGTH);
+ bb.put(collectorInfo);
+ bb.put(TYPE_TERMINATOR);
+ bb.put(LacpTerminatorTlv.LENGTH);
+ bb.put(terminatorInfo);
+
+ return data;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(super.hashCode(), lacpVersion, tlv);
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!super.equals(obj)) {
+ return false;
+ }
+ if (!(obj instanceof Lacp)) {
+ return false;
+ }
+ final Lacp other = (Lacp) obj;
+
+ return this.lacpVersion == other.lacpVersion &&
+ Objects.equals(this.tlv, other.tlv);
+ }
+
+ @Override
+ public String toString() {
+ return toStringHelper(getClass())
+ .add("lacpVersion", Byte.toString(lacpVersion))
+ .add("tlv", tlv)
+ .toString();
+ }
+}
diff --git a/utils/misc/src/main/java/org/onlab/packet/lacp/LacpBaseTlv.java b/utils/misc/src/main/java/org/onlab/packet/lacp/LacpBaseTlv.java
new file mode 100644
index 0000000..5a4a0c9
--- /dev/null
+++ b/utils/misc/src/main/java/org/onlab/packet/lacp/LacpBaseTlv.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.onlab.packet.lacp;
+
+import org.onlab.packet.Deserializer;
+import org.onlab.packet.MacAddress;
+
+import java.nio.ByteBuffer;
+import java.util.Objects;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static org.onlab.packet.PacketUtils.checkInput;
+
+/**
+ * Represents LACP ActorInfo or PartnerInfo information.
+ */
+public class LacpBaseTlv extends LacpTlv {
+ public static final byte LENGTH = 20;
+ private static final byte[] RESERVED = new byte[3];
+
+ private short systemPriority;
+ private MacAddress systemMac;
+ private short key;
+ private short portPriority;
+ private short port;
+ private LacpState state;
+
+ /**
+ * Gets system priority.
+ *
+ * @return system priority
+ */
+ public short getSystemPriority() {
+ return systemPriority;
+ }
+
+ /**
+ * Sets system priority.
+ *
+ * @param systemPriority system priority
+ * @return this
+ */
+ public LacpBaseTlv setSystemPriority(short systemPriority) {
+ this.systemPriority = systemPriority;
+ return this;
+ }
+
+ /**
+ * Gets system MAC address.
+ *
+ * @return system MAC address
+ */
+ public MacAddress getSystemMac() {
+ return systemMac;
+ }
+
+ /**
+ * Sets system MAC address.
+ *
+ * @param systemMac system MAC
+ * @return this
+ */
+ public LacpBaseTlv setSystemMac(MacAddress systemMac) {
+ this.systemMac = systemMac;
+ return this;
+ }
+
+ /**
+ * Gets key.
+ *
+ * @return key
+ */
+ public short getKey() {
+ return key;
+ }
+
+ /**
+ * Sets key.
+ *
+ * @param key key
+ * @return this
+ */
+ public LacpBaseTlv setKey(short key) {
+ this.key = key;
+ return this;
+ }
+
+ /**
+ * Gets port priority.
+ *
+ * @return port priority
+ */
+ public short getPortPriority() {
+ return portPriority;
+ }
+
+ /**
+ * Sets port priority.
+ *
+ * @param portPriority port priority
+ * @return this
+ */
+ public LacpBaseTlv setPortPriority(short portPriority) {
+ this.portPriority = portPriority;
+ return this;
+ }
+
+ /**
+ * Gets port.
+ *
+ * @return port
+ */
+ public short getPort() {
+ return port;
+ }
+
+ /**
+ * Sets port.
+ *
+ * @param port port
+ * @return this
+ */
+ public LacpBaseTlv setPort(short port) {
+ this.port = port;
+ return this;
+ }
+
+ /**
+ * Gets state.
+ *
+ * @return state
+ */
+ public LacpState getState() {
+ return state;
+ }
+
+ /**
+ * Sets state.
+ *
+ * @param state state
+ * @return this
+ */
+ public LacpBaseTlv setState(byte state) {
+ this.state = new LacpState(state);
+ return this;
+ }
+
+ /**
+ * Deserializer function for LacpBaseTlv packets.
+ *
+ * @return deserializer function
+ */
+ public static Deserializer<LacpBaseTlv> deserializer() {
+ return (data, offset, length) -> {
+ checkInput(data, offset, length, LENGTH - HEADER_LENGTH);
+
+ LacpBaseTlv lacpBaseTlv = new LacpBaseTlv();
+ ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
+
+ lacpBaseTlv.setSystemPriority(bb.getShort());
+ byte[] mac = new byte[6];
+ bb.get(mac);
+ lacpBaseTlv.setSystemMac(MacAddress.valueOf(mac));
+ lacpBaseTlv.setKey(bb.getShort());
+ lacpBaseTlv.setPortPriority(bb.getShort());
+ lacpBaseTlv.setPort(bb.getShort());
+ lacpBaseTlv.setState(bb.get());
+
+ return lacpBaseTlv;
+ };
+ }
+
+ @Override
+ public byte[] serialize() {
+ final byte[] data = new byte[LENGTH - HEADER_LENGTH];
+
+ final ByteBuffer bb = ByteBuffer.wrap(data);
+ bb.putShort(this.systemPriority);
+ bb.put(this.systemMac.toBytes());
+ bb.putShort(this.key);
+ bb.putShort(this.portPriority);
+ bb.putShort(this.port);
+ bb.put(this.state.toByte());
+ bb.put(RESERVED);
+
+ return data;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!super.equals(obj)) {
+ return false;
+ }
+ if (!(obj instanceof LacpBaseTlv)) {
+ return false;
+ }
+ final LacpBaseTlv other = (LacpBaseTlv) obj;
+ return systemPriority == other.systemPriority &&
+ key == other.key &&
+ portPriority == other.portPriority &&
+ port == other.port &&
+ Objects.equals(state, other.state) &&
+ Objects.equals(systemMac, other.systemMac);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(super.hashCode(), systemPriority, systemMac, key,
+ portPriority, port, state);
+ }
+
+ @Override
+ public String toString() {
+ return toStringHelper(getClass())
+ .add("systemPriority", Short.toString(systemPriority))
+ .add("systemMac", systemMac.toString())
+ .add("key", Short.toString(key))
+ .add("portPriority", Short.toString(portPriority))
+ .add("port", Short.toString(port))
+ .add("state", state.toString())
+ .toString();
+ }
+}
diff --git a/utils/misc/src/main/java/org/onlab/packet/lacp/LacpCollectorTlv.java b/utils/misc/src/main/java/org/onlab/packet/lacp/LacpCollectorTlv.java
new file mode 100644
index 0000000..e2d7039
--- /dev/null
+++ b/utils/misc/src/main/java/org/onlab/packet/lacp/LacpCollectorTlv.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.onlab.packet.lacp;
+
+import com.google.common.base.Objects;
+import org.onlab.packet.Deserializer;
+
+import java.nio.ByteBuffer;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static org.onlab.packet.PacketUtils.checkInput;
+
+/**
+ * Represents LACP collector information.
+ */
+public class LacpCollectorTlv extends LacpTlv {
+ public static final byte LENGTH = 16;
+ private static final byte[] RESERVED = new byte[12];
+
+ private short collectorMaxDelay;
+
+ /**
+ * Gets collector max delay.
+ *
+ * @return collector max delay
+ */
+ public short getCollectorMaxDelay() {
+ return collectorMaxDelay;
+ }
+
+ /**
+ * Sets collector max delay.
+ *
+ * @param collectorMaxDelay collector max delay
+ * @return this
+ */
+ public LacpCollectorTlv setCollectorMaxDelay(short collectorMaxDelay) {
+ this.collectorMaxDelay = collectorMaxDelay;
+ return this;
+ }
+
+ /**
+ * Deserializer function for LacpCollectorTlv packets.
+ *
+ * @return deserializer function
+ */
+ public static Deserializer<LacpCollectorTlv> deserializer() {
+ return (data, offset, length) -> {
+ checkInput(data, offset, length, LENGTH - HEADER_LENGTH);
+
+ LacpCollectorTlv lacpCollectorTlv = new LacpCollectorTlv();
+ ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
+
+ lacpCollectorTlv.setCollectorMaxDelay(bb.getShort());
+
+ return lacpCollectorTlv;
+ };
+ }
+
+ @Override
+ public byte[] serialize() {
+ final byte[] data = new byte[LENGTH - HEADER_LENGTH];
+
+ final ByteBuffer bb = ByteBuffer.wrap(data);
+ bb.putShort(this.collectorMaxDelay);
+ bb.put(RESERVED);
+
+ return data;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!super.equals(obj)) {
+ return false;
+ }
+ if (!(obj instanceof LacpCollectorTlv)) {
+ return false;
+ }
+ final LacpCollectorTlv other = (LacpCollectorTlv) obj;
+ return this.collectorMaxDelay == other.collectorMaxDelay;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(super.hashCode(), collectorMaxDelay);
+ }
+
+ @Override
+ public String toString() {
+ return toStringHelper(getClass())
+ .add("collectorMaxDelay", Short.toString(collectorMaxDelay))
+ .toString();
+ }
+}
diff --git a/utils/misc/src/main/java/org/onlab/packet/lacp/LacpState.java b/utils/misc/src/main/java/org/onlab/packet/lacp/LacpState.java
new file mode 100644
index 0000000..bd3a5ae
--- /dev/null
+++ b/utils/misc/src/main/java/org/onlab/packet/lacp/LacpState.java
@@ -0,0 +1,280 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.onlab.packet.lacp;
+
+import java.util.Objects;
+
+/**
+ * LACP state.
+ */
+public class LacpState {
+ private static final byte MASK_ACTIVE = 0x1;
+ private static final byte MASK_TIMEOUT = 0x2;
+ private static final byte MASK_AGG = 0x4;
+ private static final byte MASK_SYNC = 0x8;
+ private static final byte MASK_COLLECTING = 0x10;
+ private static final byte MASK_DISTRIBUTING = 0x20;
+ private static final byte MASK_DEFAULT = 0x40;
+ private static final byte MASK_EXPIRED = (byte) 0x80;
+
+ private byte state;
+
+ /**
+ * Constructs LACP state with zero value.
+ */
+ public LacpState() {
+ this.state = 0;
+ }
+
+ /**
+ * Constructs LACP state with given value.
+ *
+ * @param state state in byte.
+ */
+ public LacpState(byte state) {
+ this.state = state;
+ }
+
+ /**
+ * Gets LACP state in byte.
+ *
+ * @return LACP state
+ */
+ public byte toByte() {
+ return state;
+ }
+
+ /**
+ * Checks if this state has the active flag set.
+ *
+ * @return true if this state has the active flag set.
+ */
+ public boolean isActive() {
+ return (state & MASK_ACTIVE) != 0;
+ }
+
+ /**
+ * Sets active bit.
+ *
+ * @param value desired value
+ * @return this
+ */
+ public LacpState setActive(boolean value) {
+ setBit(MASK_ACTIVE, value);
+ return this;
+ }
+
+ /**
+ * Checks if this state has the timeout flag set. Timeout flag indicates short timeout if set.
+ *
+ * @return true if this state has the timeout flag set.
+ */
+ public boolean isTimeout() {
+ return (state & MASK_TIMEOUT) != 0;
+ }
+
+ /**
+ * Sets timeout bit.
+ *
+ * @param value desired value
+ * @return this
+ */
+ public LacpState setTimeout(boolean value) {
+ setBit(MASK_TIMEOUT, value);
+ return this;
+ }
+
+ /**
+ * Checks if this state has the aggregatable flag set.
+ *
+ * @return true if this state has the aggregatable flag set.
+ */
+ public boolean isAggregatable() {
+ return (state & MASK_AGG) != 0;
+ }
+
+ /**
+ * Sets aggregatable bit.
+ *
+ * @param value desired value
+ * @return this
+ */
+ public LacpState setAggregatable(boolean value) {
+ setBit(MASK_AGG, value);
+ return this;
+ }
+
+ /**
+ * Checks if this state has the synchronization flag set.
+ *
+ * @return true if this state has the synchronization flag set.
+ */
+ public boolean isSync() {
+ return (state & MASK_SYNC) != 0;
+ }
+
+ /**
+ * Sets sync bit.
+ *
+ * @param value desired value
+ * @return this
+ */
+ public LacpState setSync(boolean value) {
+ setBit(MASK_SYNC, value);
+ return this;
+ }
+
+ /**
+ * Checks if this state has the collecting flag set.
+ *
+ * @return true if this state has the collecting flag set.
+ */
+ public boolean isCollecting() {
+ return (state & MASK_COLLECTING) != 0;
+ }
+
+ /**
+ * Sets collecting bit.
+ *
+ * @param value desired value
+ * @return this
+ */
+ public LacpState setCollecting(boolean value) {
+ setBit(MASK_COLLECTING, value);
+ return this;
+ }
+
+ /**
+ * Checks if this state has the distributing flag set.
+ *
+ * @return true if this state has the distributing flag set.
+ */
+ public boolean isDistributing() {
+ return (state & MASK_DISTRIBUTING) != 0;
+ }
+
+ /**
+ * Sets distributing bit.
+ *
+ * @param value desired value
+ * @return this
+ */
+ public LacpState setDistributing(boolean value) {
+ setBit(MASK_DISTRIBUTING, value);
+ return this;
+ }
+
+ /**
+ * Checks if this state has the default flag set.
+ *
+ * @return true if this state has the default flag set.
+ */
+ public boolean isDefault() {
+ return (state & MASK_DEFAULT) != 0;
+ }
+
+ /**
+ * Sets default bit.
+ *
+ * @param value desired value
+ * @return this
+ */
+ public LacpState setDefault(boolean value) {
+ setBit(MASK_DEFAULT, value);
+ return this;
+ }
+
+ /**
+ * Checks if this state has the expired flag set.
+ *
+ * @return true if this state has the expired flag set.
+ */
+ public boolean isExpired() {
+ return (state & MASK_EXPIRED) != 0;
+ }
+
+ /**
+ * Sets expired bit.
+ *
+ * @param value desired value
+ * @return this
+ */
+ public LacpState setExpired(boolean value) {
+ setBit(MASK_EXPIRED, value);
+ return this;
+ }
+
+ /**
+ * Sets the bit masked by given mask in the state to desired value.
+ *
+ * @param mask bit to mask
+ * @param value desire value
+ */
+ private void setBit(byte mask, boolean value) {
+ state = (byte) (value ? state | mask : state & ~mask);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof LacpState)) {
+ return false;
+ }
+ final LacpState other = (LacpState) obj;
+
+ return this.state == other.state;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(state);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("{ ");
+ if (isActive()) {
+ builder.append("ACT ");
+ }
+ if (isTimeout()) {
+ builder.append("STO ");
+ }
+ if (isAggregatable()) {
+ builder.append("AGG ");
+ }
+ if (isSync()) {
+ builder.append("SYN ");
+ }
+ if (isCollecting()) {
+ builder.append("COL ");
+ }
+ if (isDistributing()) {
+ builder.append("DIS ");
+ }
+ if (isDefault()) {
+ builder.append("DEF ");
+ }
+ if (isExpired()) {
+ builder.append("EXP ");
+ }
+ builder.append("}");
+ return builder.toString();
+ }
+}
diff --git a/utils/misc/src/main/java/org/onlab/packet/lacp/LacpTerminatorTlv.java b/utils/misc/src/main/java/org/onlab/packet/lacp/LacpTerminatorTlv.java
new file mode 100644
index 0000000..2afd50a
--- /dev/null
+++ b/utils/misc/src/main/java/org/onlab/packet/lacp/LacpTerminatorTlv.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.onlab.packet.lacp;
+
+import org.onlab.packet.Deserializer;
+
+import java.nio.ByteBuffer;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static org.onlab.packet.PacketUtils.checkInput;
+
+/**
+ * Represents LACP terminator information.
+ */
+public class LacpTerminatorTlv extends LacpTlv {
+ public static final byte LENGTH = 0;
+ static final byte PADDING_LENGTH = 50;
+ private static final byte[] PADDING = new byte[PADDING_LENGTH];
+
+ /**
+ * Deserializer function for LacpTerminatorTlv packets.
+ *
+ * @return deserializer function
+ */
+ public static Deserializer<LacpTerminatorTlv> deserializer() {
+ return (data, offset, length) -> {
+ checkInput(data, offset, length, LENGTH);
+
+ return new LacpTerminatorTlv();
+ };
+ }
+
+ @Override
+ public byte[] serialize() {
+ final byte[] data = new byte[LENGTH + PADDING_LENGTH];
+
+ final ByteBuffer bb = ByteBuffer.wrap(data);
+ bb.put(PADDING);
+
+ return data;
+ }
+
+ @Override
+ public String toString() {
+ return toStringHelper(getClass()).toString();
+ }
+}
\ No newline at end of file
diff --git a/utils/misc/src/main/java/org/onlab/packet/lacp/LacpTlv.java b/utils/misc/src/main/java/org/onlab/packet/lacp/LacpTlv.java
new file mode 100644
index 0000000..dedb095
--- /dev/null
+++ b/utils/misc/src/main/java/org/onlab/packet/lacp/LacpTlv.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.onlab.packet.lacp;
+
+import org.onlab.packet.BasePacket;
+
+public abstract class LacpTlv extends BasePacket {
+ public static final byte HEADER_LENGTH = 2;
+}
diff --git a/utils/misc/src/main/java/org/onlab/packet/lacp/package-info.java b/utils/misc/src/main/java/org/onlab/packet/lacp/package-info.java
new file mode 100644
index 0000000..f7f7bfe
--- /dev/null
+++ b/utils/misc/src/main/java/org/onlab/packet/lacp/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.
+ */
+
+/**
+ * Utilities for decoding and encoding LACP packets.
+ */
+package org.onlab.packet.lacp;
\ No newline at end of file
diff --git a/utils/misc/src/test/java/org/onlab/packet/lacp/LacpBaseTlvTest.java b/utils/misc/src/test/java/org/onlab/packet/lacp/LacpBaseTlvTest.java
new file mode 100644
index 0000000..874d5c1
--- /dev/null
+++ b/utils/misc/src/test/java/org/onlab/packet/lacp/LacpBaseTlvTest.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.onlab.packet.lacp;
+
+import com.google.common.io.Resources;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.MacAddress;
+
+import static org.junit.Assert.*;
+
+public class LacpBaseTlvTest {
+ private static final String PACKET_DUMP = "baseinfo.bin";
+
+ private byte[] data;
+
+ private static final short SYS_PRIORITY = (short) 32768;
+ private static final MacAddress SYS_MAC = MacAddress.valueOf("a4:23:05:00:11:22");
+ private static final short KEY = (short) 13;
+ private static final short PORT_PRIORITY = (short) 32768;
+ private static final short PORT = 22;
+ private static final byte STATE = (byte) 0x85;
+
+ static final LacpBaseTlv BASE_TLV = new LacpBaseTlv()
+ .setSystemPriority(SYS_PRIORITY)
+ .setSystemMac(SYS_MAC)
+ .setKey(KEY)
+ .setPortPriority(PORT_PRIORITY)
+ .setPort(PORT)
+ .setState(STATE);
+
+ @Before
+ public void setUp() throws Exception {
+ data = Resources.toByteArray(LacpBaseTlvTest.class.getResource(PACKET_DUMP));
+ }
+
+ @Test
+ public void deserializer() throws Exception {
+ LacpBaseTlv actorInfo = LacpBaseTlv.deserializer().deserialize(data, 0, data.length);
+ assertEquals(SYS_PRIORITY, actorInfo.getSystemPriority());
+ assertEquals(SYS_MAC, actorInfo.getSystemMac());
+ assertEquals(KEY, actorInfo.getKey());
+ assertEquals(PORT_PRIORITY, actorInfo.getPortPriority());
+ assertEquals(PORT, actorInfo.getPort());
+ assertEquals(STATE, actorInfo.getState().toByte());
+ }
+
+ @Test
+ public void serialize() {
+ assertArrayEquals(data, BASE_TLV.serialize());
+ }
+}
\ No newline at end of file
diff --git a/utils/misc/src/test/java/org/onlab/packet/lacp/LacpCollectorTlvTest.java b/utils/misc/src/test/java/org/onlab/packet/lacp/LacpCollectorTlvTest.java
new file mode 100644
index 0000000..1e098ee
--- /dev/null
+++ b/utils/misc/src/test/java/org/onlab/packet/lacp/LacpCollectorTlvTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.onlab.packet.lacp;
+
+import com.google.common.io.Resources;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+
+public class LacpCollectorTlvTest {
+ private static final String PACKET_DUMP = "collectorinfo.bin";
+
+ private byte[] data;
+
+ private static final short COLLECTOR_MAX_DELAY = (short) 32768;
+
+ static final LacpCollectorTlv COLLECTOR_TLV = new LacpCollectorTlv()
+ .setCollectorMaxDelay(COLLECTOR_MAX_DELAY);
+
+ @Before
+ public void setUp() throws Exception {
+ data = Resources.toByteArray(LacpCollectorTlvTest.class.getResource(PACKET_DUMP));
+ }
+
+ @Test
+ public void deserializer() throws Exception {
+ LacpCollectorTlv lacpCollectorTlv = LacpCollectorTlv.deserializer().deserialize(data, 0, data.length);
+ assertEquals(COLLECTOR_MAX_DELAY, lacpCollectorTlv.getCollectorMaxDelay());
+
+ }
+
+ @Test
+ public void serialize() {
+ assertArrayEquals(data, COLLECTOR_TLV.serialize());
+ }
+}
\ No newline at end of file
diff --git a/utils/misc/src/test/java/org/onlab/packet/lacp/LacpStateTest.java b/utils/misc/src/test/java/org/onlab/packet/lacp/LacpStateTest.java
new file mode 100644
index 0000000..4645664
--- /dev/null
+++ b/utils/misc/src/test/java/org/onlab/packet/lacp/LacpStateTest.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.onlab.packet.lacp;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class LacpStateTest {
+
+ @Test
+ public void toByte() {
+ LacpState state = new LacpState((byte) 0x15);
+ assertEquals((byte) 0x15, state.toByte());
+ }
+
+ @Test
+ public void isActive() {
+ LacpState state = new LacpState((byte) 0x1);
+ assertTrue(state.isActive());
+ }
+
+ @Test
+ public void isTimeout() {
+ LacpState state = new LacpState((byte) 0x2);
+ assertTrue(state.isTimeout());
+ }
+
+ @Test
+ public void isAggregatable() {
+ LacpState state = new LacpState((byte) 0x4);
+ assertTrue(state.isAggregatable());
+ }
+
+ @Test
+ public void isSync() {
+ LacpState state = new LacpState((byte) 0x8);
+ assertTrue(state.isSync());
+ }
+
+ @Test
+ public void isCollecting() {
+ LacpState state = new LacpState((byte) 0x10);
+ assertTrue(state.isCollecting());
+ }
+
+ @Test
+ public void isDistributing() {
+ LacpState state = new LacpState((byte) 0x20);
+ assertTrue(state.isDistributing());
+ }
+
+ @Test
+ public void isDefault() {
+ LacpState state = new LacpState((byte) 0x40);
+ assertTrue(state.isDefault());
+ }
+
+ @Test
+ public void isExpired() {
+ LacpState state = new LacpState((byte) 0x80);
+ assertTrue(state.isExpired());
+ }
+
+ @Test
+ public void equals() {
+ LacpState state1 = new LacpState((byte) 0x15);
+ LacpState state2 = new LacpState((byte) 0x15);
+ LacpState state3 = new LacpState((byte) 0x51);
+
+ assertEquals(state1, state2);
+ assertNotEquals(state1, state3);
+
+ }
+}
\ No newline at end of file
diff --git a/utils/misc/src/test/java/org/onlab/packet/lacp/LacpTerminatorTlvTest.java b/utils/misc/src/test/java/org/onlab/packet/lacp/LacpTerminatorTlvTest.java
new file mode 100644
index 0000000..6f84a5a
--- /dev/null
+++ b/utils/misc/src/test/java/org/onlab/packet/lacp/LacpTerminatorTlvTest.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.onlab.packet.lacp;
+
+import com.google.common.io.Resources;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertArrayEquals;
+
+public class LacpTerminatorTlvTest {
+ private static final String PACKET_DUMP = "terminatorinfo.bin";
+
+ private byte[] data;
+
+ static final LacpTerminatorTlv TERMINATOR_TLV = new LacpTerminatorTlv();
+
+ @Before
+ public void setUp() throws Exception {
+ data = Resources.toByteArray(LacpTerminatorTlvTest.class.getResource(PACKET_DUMP));
+ }
+
+ @Test
+ public void deserializer() throws Exception {
+ LacpTerminatorTlv lacpTerminatorTlv = LacpTerminatorTlv.deserializer().deserialize(data, 0, data.length);
+ }
+
+ @Test
+ public void serialize() {
+ assertArrayEquals(data, TERMINATOR_TLV.serialize());
+ }
+}
\ No newline at end of file
diff --git a/utils/misc/src/test/java/org/onlab/packet/lacp/LacpTest.java b/utils/misc/src/test/java/org/onlab/packet/lacp/LacpTest.java
new file mode 100644
index 0000000..810799c
--- /dev/null
+++ b/utils/misc/src/test/java/org/onlab/packet/lacp/LacpTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.onlab.packet.lacp;
+
+import com.google.common.collect.Maps;
+import com.google.common.io.Resources;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Map;
+
+import static org.junit.Assert.*;
+
+public class LacpTest {
+ private static final String PACKET_DUMP = "lacp.bin";
+
+ private static final byte LACP_VERSION = 1;
+ private static final Map<Byte, LacpTlv> LACP_TLV = Maps.newHashMap();
+ private static final Lacp LACP = new Lacp();
+
+ static {
+ LACP_TLV.put(Lacp.TYPE_ACTOR, LacpBaseTlvTest.BASE_TLV);
+ LACP_TLV.put(Lacp.TYPE_PARTNER, LacpBaseTlvTest.BASE_TLV);
+ LACP_TLV.put(Lacp.TYPE_COLLECTOR, LacpCollectorTlvTest.COLLECTOR_TLV);
+ LACP_TLV.put(Lacp.TYPE_TERMINATOR, LacpTerminatorTlvTest.TERMINATOR_TLV);
+
+ LACP.setLacpVersion(LACP_VERSION)
+ .setTlv(LACP_TLV);
+ }
+
+ private byte[] data;
+
+ @Before
+ public void setUp() throws Exception {
+ data = Resources.toByteArray(LacpBaseTlvTest.class.getResource(PACKET_DUMP));
+ }
+
+ @Test
+ public void deserializer() throws Exception {
+ Lacp lacp = Lacp.deserializer().deserialize(data, 0, data.length);
+ assertEquals(LACP_VERSION, lacp.getLacpVersion());
+ assertEquals(LACP_TLV, lacp.getTlv());
+ }
+
+ @Test
+ public void serialize() {
+ assertArrayEquals(data, LACP.serialize());
+ }
+}
\ No newline at end of file
diff --git a/utils/misc/src/test/resources/org/onlab/packet/lacp/baseinfo.bin b/utils/misc/src/test/resources/org/onlab/packet/lacp/baseinfo.bin
new file mode 100644
index 0000000..cf9e8cf
--- /dev/null
+++ b/utils/misc/src/test/resources/org/onlab/packet/lacp/baseinfo.bin
Binary files differ
diff --git a/utils/misc/src/test/resources/org/onlab/packet/lacp/collectorinfo.bin b/utils/misc/src/test/resources/org/onlab/packet/lacp/collectorinfo.bin
new file mode 100644
index 0000000..59f08bc
--- /dev/null
+++ b/utils/misc/src/test/resources/org/onlab/packet/lacp/collectorinfo.bin
Binary files differ
diff --git a/utils/misc/src/test/resources/org/onlab/packet/lacp/lacp.bin b/utils/misc/src/test/resources/org/onlab/packet/lacp/lacp.bin
new file mode 100644
index 0000000..d3e13b6
--- /dev/null
+++ b/utils/misc/src/test/resources/org/onlab/packet/lacp/lacp.bin
Binary files differ
diff --git a/utils/misc/src/test/resources/org/onlab/packet/lacp/terminatorinfo.bin b/utils/misc/src/test/resources/org/onlab/packet/lacp/terminatorinfo.bin
new file mode 100644
index 0000000..445c896
--- /dev/null
+++ b/utils/misc/src/test/resources/org/onlab/packet/lacp/terminatorinfo.bin
Binary files differ