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 945254d..db74bf0 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