@Override
    public OFPortDesc readFrom(ByteBuf bb) throws OFParseError {
      OFPort portNo = OFPort.read4Bytes(bb);
      // pad: 4 bytes
      bb.skipBytes(4);
      MacAddress hwAddr = MacAddress.read6Bytes(bb);
      // pad: 2 bytes
      bb.skipBytes(2);
      String name = ChannelUtils.readFixedLengthString(bb, 16);
      Set<OFPortConfig> config = OFPortConfigSerializerVer12.readFrom(bb);
      Set<OFPortState> state = OFPortStateSerializerVer12.readFrom(bb);
      Set<OFPortFeatures> curr = OFPortFeaturesSerializerVer12.readFrom(bb);
      Set<OFPortFeatures> advertised = OFPortFeaturesSerializerVer12.readFrom(bb);
      Set<OFPortFeatures> supported = OFPortFeaturesSerializerVer12.readFrom(bb);
      Set<OFPortFeatures> peer = OFPortFeaturesSerializerVer12.readFrom(bb);
      long currSpeed = U32.f(bb.readInt());
      long maxSpeed = U32.f(bb.readInt());

      OFPortDescVer12 portDescVer12 =
          new OFPortDescVer12(
              portNo,
              hwAddr,
              name,
              config,
              state,
              curr,
              advertised,
              supported,
              peer,
              currSpeed,
              maxSpeed);
      if (logger.isTraceEnabled()) logger.trace("readFrom - read={}", portDescVer12);
      return portDescVer12;
    }
  @Override
  public int hashCode() {
    final int prime = 31;
    int result = 1;

    result = prime * result + ((value == null) ? 0 : value.hashCode());
    return result;
  }
  @Override
  public int hashCode() {
    final int prime = 31;
    int result = 1;

    result = prime * result + ((dlAddr == null) ? 0 : dlAddr.hashCode());
    return result;
  }
  @Override
  public boolean equals(Object obj) {
    if (this == obj) return true;
    if (obj == null) return false;
    if (getClass() != obj.getClass()) return false;
    OFBsnTlvActorSystemMacVer14 other = (OFBsnTlvActorSystemMacVer14) obj;

    if (value == null) {
      if (other.value != null) return false;
    } else if (!value.equals(other.value)) return false;
    return true;
  }
  @Override
  public boolean equals(Object obj) {
    if (this == obj) return true;
    if (obj == null) return false;
    if (getClass() != obj.getClass()) return false;
    OFOxmBsnInnerEthDstVer14 other = (OFOxmBsnInnerEthDstVer14) obj;

    if (value == null) {
      if (other.value != null) return false;
    } else if (!value.equals(other.value)) return false;
    return true;
  }
    @Override
    public OFOxmBsnInnerEthDst readFrom(ByteBuf bb) throws OFParseError {
      // fixed value property typeLen == 0x32c06L
      int typeLen = bb.readInt();
      if (typeLen != 0x32c06)
        throw new OFParseError("Wrong typeLen: Expected=0x32c06L(0x32c06L), got=" + typeLen);
      MacAddress value = MacAddress.read6Bytes(bb);

      OFOxmBsnInnerEthDstVer14 oxmBsnInnerEthDstVer14 = new OFOxmBsnInnerEthDstVer14(value);
      if (logger.isTraceEnabled()) logger.trace("readFrom - read={}", oxmBsnInnerEthDstVer14);
      return oxmBsnInnerEthDstVer14;
    }
    @Override
    public OFOxmArpTha readFrom(ChannelBuffer bb) throws OFParseError {
      // fixed value property typeLen == 0x80003206L
      int typeLen = bb.readInt();
      if (typeLen != (int) 0x80003206)
        throw new OFParseError("Wrong typeLen: Expected=0x80003206L(0x80003206L), got=" + typeLen);
      MacAddress value = MacAddress.read6Bytes(bb);

      OFOxmArpThaVer13 oxmArpThaVer13 = new OFOxmArpThaVer13(value);
      if (logger.isTraceEnabled()) logger.trace("readFrom - read={}", oxmArpThaVer13);
      return oxmArpThaVer13;
    }
  @Override
  public boolean equals(Object obj) {
    if (this == obj) return true;
    if (obj == null) return false;
    if (getClass() != obj.getClass()) return false;
    OFActionSetDlSrcVer10 other = (OFActionSetDlSrcVer10) obj;

    if (dlAddr == null) {
      if (other.dlAddr != null) return false;
    } else if (!dlAddr.equals(other.dlAddr)) return false;
    return true;
  }
    @Override
    public OFOxmEthSrc readFrom(ByteBuf bb) throws OFParseError {
      // fixed value property typeLen == 0x80000806L
      int typeLen = bb.readInt();
      if (typeLen != (int) 0x80000806)
        throw new OFParseError("Wrong typeLen: Expected=0x80000806L(0x80000806L), got=" + typeLen);
      MacAddress value = MacAddress.read6Bytes(bb);

      OFOxmEthSrcVer12 oxmEthSrcVer12 = new OFOxmEthSrcVer12(value);
      if (logger.isTraceEnabled()) logger.trace("readFrom - read={}", oxmEthSrcVer12);
      return oxmEthSrcVer12;
    }
  @Test
  public void testWrite() {
    OFBsnGentableEntryDelete.Builder builder = factory.buildBsnGentableEntryDelete();
    builder
        .setXid(0x12345678)
        .setTableId(GenTableId.of(20))
        .setKey(
            ImmutableList.<OFBsnTlv>of(
                factory.bsnTlvs().port(OFPort.of(5)),
                factory.bsnTlvs().mac(MacAddress.of("01:23:45:67:89:ab"))));
    OFBsnGentableEntryDelete bsnGentableEntryDelete = builder.build();
    ByteBuf bb = Unpooled.buffer();
    bsnGentableEntryDelete.writeTo(bb);
    byte[] written = new byte[bb.readableBytes()];
    bb.readBytes(written);

    assertThat(written, CoreMatchers.equalTo(BSN_GENTABLE_ENTRY_DELETE_SERIALIZED));
  }
  @Override
  public int hashCode() {
    final int prime = 31;
    int result = 1;

    result = prime * result + ((portNo == null) ? 0 : portNo.hashCode());
    result = prime * result + ((hwAddr == null) ? 0 : hwAddr.hashCode());
    result = prime * result + ((name == null) ? 0 : name.hashCode());
    result = prime * result + ((config == null) ? 0 : config.hashCode());
    result = prime * result + ((state == null) ? 0 : state.hashCode());
    result = prime * result + ((curr == null) ? 0 : curr.hashCode());
    result = prime * result + ((advertised == null) ? 0 : advertised.hashCode());
    result = prime * result + ((supported == null) ? 0 : supported.hashCode());
    result = prime * result + ((peer == null) ? 0 : peer.hashCode());
    result = prime * (int) (currSpeed ^ (currSpeed >>> 32));
    result = prime * (int) (maxSpeed ^ (maxSpeed >>> 32));
    return result;
  }
  @Test
  public void testRead() throws Exception {
    OFBsnGentableEntryDelete.Builder builder = factory.buildBsnGentableEntryDelete();
    builder
        .setXid(0x12345678)
        .setTableId(GenTableId.of(20))
        .setKey(
            ImmutableList.<OFBsnTlv>of(
                factory.bsnTlvs().port(OFPort.of(5)),
                factory.bsnTlvs().mac(MacAddress.of("01:23:45:67:89:ab"))));
    OFBsnGentableEntryDelete bsnGentableEntryDeleteBuilt = builder.build();

    ByteBuf input = Unpooled.copiedBuffer(BSN_GENTABLE_ENTRY_DELETE_SERIALIZED);

    // FIXME should invoke the overall reader once implemented
    OFBsnGentableEntryDelete bsnGentableEntryDeleteRead =
        OFBsnGentableEntryDeleteVer13.READER.readFrom(input);
    assertEquals(BSN_GENTABLE_ENTRY_DELETE_SERIALIZED.length, input.readerIndex());

    assertEquals(bsnGentableEntryDeleteBuilt, bsnGentableEntryDeleteRead);
  }
    @Override
    public OFBsnTlvActorSystemMac readFrom(ChannelBuffer bb) throws OFParseError {
      int start = bb.readerIndex();
      // fixed value property type == 0x29
      short type = bb.readShort();
      if (type != (short) 0x29)
        throw new OFParseError("Wrong type: Expected=0x29(0x29), got=" + type);
      int length = U16.f(bb.readShort());
      if (length != 10) throw new OFParseError("Wrong length: Expected=10(10), got=" + length);
      if (bb.readableBytes() + (bb.readerIndex() - start) < length) {
        // Buffer does not have all data yet
        bb.readerIndex(start);
        return null;
      }
      if (logger.isTraceEnabled()) logger.trace("readFrom - length={}", length);
      MacAddress value = MacAddress.read6Bytes(bb);

      OFBsnTlvActorSystemMacVer14 bsnTlvActorSystemMacVer14 =
          new OFBsnTlvActorSystemMacVer14(value);
      if (logger.isTraceEnabled()) logger.trace("readFrom - read={}", bsnTlvActorSystemMacVer14);
      return bsnTlvActorSystemMacVer14;
    }
  @Override
  public boolean equals(Object obj) {
    if (this == obj) return true;
    if (obj == null) return false;
    if (getClass() != obj.getClass()) return false;
    OFPortDescVer12 other = (OFPortDescVer12) obj;

    if (portNo == null) {
      if (other.portNo != null) return false;
    } else if (!portNo.equals(other.portNo)) return false;
    if (hwAddr == null) {
      if (other.hwAddr != null) return false;
    } else if (!hwAddr.equals(other.hwAddr)) return false;
    if (name == null) {
      if (other.name != null) return false;
    } else if (!name.equals(other.name)) return false;
    if (config == null) {
      if (other.config != null) return false;
    } else if (!config.equals(other.config)) return false;
    if (state == null) {
      if (other.state != null) return false;
    } else if (!state.equals(other.state)) return false;
    if (curr == null) {
      if (other.curr != null) return false;
    } else if (!curr.equals(other.curr)) return false;
    if (advertised == null) {
      if (other.advertised != null) return false;
    } else if (!advertised.equals(other.advertised)) return false;
    if (supported == null) {
      if (other.supported != null) return false;
    } else if (!supported.equals(other.supported)) return false;
    if (peer == null) {
      if (other.peer != null) return false;
    } else if (!peer.equals(other.peer)) return false;
    if (currSpeed != other.currSpeed) return false;
    if (maxSpeed != other.maxSpeed) return false;
    return true;
  }
    @Override
    public OFActionSetDlSrc readFrom(ByteBuf bb) throws OFParseError {
      int start = bb.readerIndex();
      // fixed value property type == 4
      short type = bb.readShort();
      if (type != (short) 0x4)
        throw new OFParseError("Wrong type: Expected=OFActionType.SET_DL_SRC(4), got=" + type);
      int length = U16.f(bb.readShort());
      if (length != 16) throw new OFParseError("Wrong length: Expected=16(16), got=" + length);
      if (bb.readableBytes() + (bb.readerIndex() - start) < length) {
        // Buffer does not have all data yet
        bb.readerIndex(start);
        return null;
      }
      if (logger.isTraceEnabled()) logger.trace("readFrom - length={}", length);
      MacAddress dlAddr = MacAddress.read6Bytes(bb);
      // pad: 6 bytes
      bb.skipBytes(6);

      OFActionSetDlSrcVer10 actionSetDlSrcVer10 = new OFActionSetDlSrcVer10(dlAddr);
      if (logger.isTraceEnabled()) logger.trace("readFrom - read={}", actionSetDlSrcVer10);
      return actionSetDlSrcVer10;
    }