@Override
    public OFFlowStatsEntry readFrom(ByteBuf bb) throws OFParseError {
      int start = bb.readerIndex();
      int length = U16.f(bb.readShort());
      if (length < MINIMUM_LENGTH)
        throw new OFParseError(
            "Wrong length: Expected to be >= " + MINIMUM_LENGTH + ", was: " + 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);
      TableId tableId = TableId.readByte(bb);
      // pad: 1 bytes
      bb.skipBytes(1);
      long durationSec = U32.f(bb.readInt());
      long durationNsec = U32.f(bb.readInt());
      int priority = U16.f(bb.readShort());
      int idleTimeout = U16.f(bb.readShort());
      int hardTimeout = U16.f(bb.readShort());
      Set<OFFlowModFlags> flags = OFFlowModFlagsSerializerVer14.readFrom(bb);
      int importance = U16.f(bb.readShort());
      // pad: 2 bytes
      bb.skipBytes(2);
      U64 cookie = U64.ofRaw(bb.readLong());
      U64 packetCount = U64.ofRaw(bb.readLong());
      U64 byteCount = U64.ofRaw(bb.readLong());
      Match match = ChannelUtilsVer14.readOFMatch(bb);
      List<OFInstruction> instructions =
          ChannelUtils.readList(bb, length - (bb.readerIndex() - start), OFInstructionVer14.READER);

      OFFlowStatsEntryVer14 flowStatsEntryVer14 =
          new OFFlowStatsEntryVer14(
              tableId,
              durationSec,
              durationNsec,
              priority,
              idleTimeout,
              hardTimeout,
              flags,
              importance,
              cookie,
              packetCount,
              byteCount,
              match,
              instructions);
      if (logger.isTraceEnabled()) logger.trace("readFrom - read={}", flowStatsEntryVer14);
      return flowStatsEntryVer14;
    }