Пример #1
0
void Context::bindSampler(GLuint textureUnit, GLuint sampler)
{
    ASSERT(textureUnit < mCaps.maxCombinedTextureImageUnits);
    mResourceManager->checkSamplerAllocation(sampler);

    mState.setSamplerBinding(textureUnit, getSampler(sampler));
}
Пример #2
0
void ResourceManager::checkSamplerAllocation(GLuint sampler)
{
    if (sampler != 0 && !getSampler(sampler))
    {
        Sampler *samplerObject = new Sampler(sampler);
        mSamplerMap[sampler] = samplerObject;
        samplerObject->addRef();
    }
}
Пример #3
0
void ResourceManager::checkSamplerAllocation(GLuint sampler)
{
    if (sampler != 0 && !getSampler(sampler))
    {
        Sampler *samplerObject = new Sampler(sampler);
        mSamplerMap[sampler] = samplerObject;
        samplerObject->addRef();
        // Samplers cannot be created via Bind
    }
}
Пример #4
0
	inline void doUnbindPassOpacityMap( PassRenderNode & node
		, Pass & pass )
	{
		auto unit = pass.getTextureUnit( TextureChannel::eOpacity );

		if ( unit )
		{
			unit->getSampler()->unbind( 0u );
			unit->getTexture()->unbind( 0u );
		}
	}
Пример #5
0
	inline void doBindPassOpacityMap( PassRenderNode & node
		, Pass & pass )
	{
		auto unit = pass.getTextureUnit( TextureChannel::eOpacity );

		if ( unit )
		{
			node.m_textures.find( unit->getIndex() )->second.get().setValue( 0 );
			unit->getTexture()->bind( 0u );
			unit->getSampler()->bind( 0u );
		}
	}
Пример #6
0
void wxraytracerFrame::OnRenderStart( wxCommandEvent& event ) {
    switch(canvas->getState()){
        case RenderCanvas::RENDERING:
            canvas->renderPause();
            return;
        case RenderCanvas::PAUSED:
            canvas->renderResume();
            return;
        case RenderCanvas::STOPPED:
        case RenderCanvas::WAITING:
        default:
            break;
    }

    wxMenu* menuFile = GetMenuBar()->GetMenu(0);
    menuFile->Enable(menuFile->FindItem(wxT( "&Open..."   )), FALSE);
    menuFile->Enable(menuFile->FindItem(wxT( "&Save As...")), TRUE );

    RenderParams rp;
    int selection = samplerCombo_->GetSelection();
    if (selection >= 0 ) {
        void* data = samplerCombo_->GetClientData(selection);
        assert(data);
        SamplerType sampleType = *reinterpret_cast<SamplerType*>(data);
        rp.sampler_ = getSampler(sampleType);
    }

    selection = builderCombo_->GetSelection();
    if (selection >= 0 ) {
        void* data = builderCombo_->GetClientData(selection);
        assert(data);
        rp.builder_ = reinterpret_cast<builderFunc>(data);
    }

    wxString numSamples = sampleNumCombo_->GetValue();
    long val = 1;
    numSamples.ToLong(&val, 10);
    rp.numSamples_  = val;
    rp.pixelSize_   = pixSizeSpin_->GetValue() / 100.0f;
    rp.transform_   = transformCheck_->IsChecked();
    rp.debugFlags_  |= menuDebug_->IsChecked(Menu_Debug_Sampler) ? DEBUG_FLAG_SAMPLER : 0x0000;

    canvas->renderStart(rp);
}
Пример #7
0
Sampler *ResourceManager::checkSamplerAllocation(rx::GLImplFactory *factory, GLuint samplerHandle)
{
    // Samplers cannot be created via Bind
    if (samplerHandle == 0)
    {
        return nullptr;
    }

    Sampler *sampler = getSampler(samplerHandle);

    if (!sampler)
    {
        sampler                    = new Sampler(factory, samplerHandle);
        mSamplerMap[samplerHandle] = sampler;
        sampler->addRef();
    }

    return sampler;
}
Пример #8
0
GLfloat Context::getSamplerParameterf(GLuint sampler, GLenum pname)
{
    mResourceManager->checkSamplerAllocation(sampler);

    Sampler *samplerObject = getSampler(sampler);
    ASSERT(samplerObject);

    switch (pname)
    {
      case GL_TEXTURE_MIN_FILTER:    return static_cast<GLfloat>(samplerObject->getMinFilter());
      case GL_TEXTURE_MAG_FILTER:    return static_cast<GLfloat>(samplerObject->getMagFilter());
      case GL_TEXTURE_WRAP_S:        return static_cast<GLfloat>(samplerObject->getWrapS());
      case GL_TEXTURE_WRAP_T:        return static_cast<GLfloat>(samplerObject->getWrapT());
      case GL_TEXTURE_WRAP_R:        return static_cast<GLfloat>(samplerObject->getWrapR());
      case GL_TEXTURE_MIN_LOD:       return samplerObject->getMinLod();
      case GL_TEXTURE_MAX_LOD:       return samplerObject->getMaxLod();
      case GL_TEXTURE_COMPARE_MODE:  return static_cast<GLfloat>(samplerObject->getComparisonMode());
      case GL_TEXTURE_COMPARE_FUNC:  return static_cast<GLfloat>(samplerObject->getComparisonFunc());
      default:                       UNREACHABLE(); return 0;
    }
}
Пример #9
0
void Context::samplerParameterf(GLuint sampler, GLenum pname, GLfloat param)
{
    mResourceManager->checkSamplerAllocation(sampler);

    Sampler *samplerObject = getSampler(sampler);
    ASSERT(samplerObject);

    switch (pname)
    {
      case GL_TEXTURE_MIN_FILTER:    samplerObject->setMinFilter(uiround<GLenum>(param));       break;
      case GL_TEXTURE_MAG_FILTER:    samplerObject->setMagFilter(uiround<GLenum>(param));       break;
      case GL_TEXTURE_WRAP_S:        samplerObject->setWrapS(uiround<GLenum>(param));           break;
      case GL_TEXTURE_WRAP_T:        samplerObject->setWrapT(uiround<GLenum>(param));           break;
      case GL_TEXTURE_WRAP_R:        samplerObject->setWrapR(uiround<GLenum>(param));           break;
      case GL_TEXTURE_MIN_LOD:       samplerObject->setMinLod(param);                           break;
      case GL_TEXTURE_MAX_LOD:       samplerObject->setMaxLod(param);                           break;
      case GL_TEXTURE_COMPARE_MODE:  samplerObject->setComparisonMode(uiround<GLenum>(param));  break;
      case GL_TEXTURE_COMPARE_FUNC:  samplerObject->setComparisonFunc(uiround<GLenum>(param));  break;
      default:                       UNREACHABLE(); break;
    }
}
Пример #10
0
  int readPackets(HSP *sp)
  {
    int batch = 0;
    static uint32_t MySkipCount=1;
    if(sp->sFlow->sFlowSettings->ulogSubSamplingRate == 0) {
      // packet sampling was disabled by setting desired rate to 0
      return 0;
    }
    if(sp->ulog_soc) {
      for( ; batch < HSP_READPACKET_BATCH; batch++) {
	char buf[HSP_MAX_MSG_BYTES];
	socklen_t peerlen = sizeof(sp->ulog_peer);
	int len = recvfrom(sp->ulog_soc,
			   buf,
			   HSP_MAX_MSG_BYTES,
			   0,
			   (struct sockaddr *)&sp->ulog_peer,
			   &peerlen);
	if(len <= 0) break;
	if(debug > 1) myLog(LOG_INFO, "got ULOG msg: %u bytes", len);
	for(struct nlmsghdr *msg = (struct nlmsghdr *)buf; NLMSG_OK(msg, len); msg=NLMSG_NEXT(msg, len)) {

	  if(debug > 1) {
	    myLog(LOG_INFO, "netlink (%u bytes left) msg [len=%u type=%u flags=0x%x seq=%u pid=%u]",
		  len,
		  msg->nlmsg_len,
		  msg->nlmsg_type,
		  msg->nlmsg_flags,
		  msg->nlmsg_seq,
		  msg->nlmsg_pid);
	  }

	  switch(msg->nlmsg_type) {
	  case NLMSG_NOOP:
	  case NLMSG_ERROR:
	  case NLMSG_OVERRUN:
	    // ignore these
	    break;
	  case NLMSG_DONE: // last in multi-part
	  default:
	    {

	      if(--MySkipCount == 0) {
		/* reached zero. Set the next skip */
		MySkipCount = sfl_random((2 * sp->sFlow->sFlowSettings->ulogSubSamplingRate) - 1);

		/* and take a sample */

		// we're seeing type==111 on Fedora14
		//if(msg->nlmsg_flags & NLM_F_REQUEST) { }
		//if(msg->nlmsg_flags & NLM_F_MULTI) { }
		//if(msg->nlmsg_flags & NLM_F_ACK) { }
		//if(msg->nlmsg_flags & NLM_F_ECHO) { }
		ulog_packet_msg_t *pkt = NLMSG_DATA(msg);
		
		if(debug > 1) {
		  myLog(LOG_INFO, "mark=%u ts=%s hook=%u in=%s out=%s len=%u prefix=%s maclen=%u\n",
			pkt->mark,
			ctime(&pkt->timestamp_sec),
			pkt->hook,
			pkt->indev_name,
			pkt->outdev_name,
			pkt->data_len,
			pkt->prefix,
			pkt->mac_len);
		  if(pkt->mac_len == 14) {
		    u_char macdst[12], macsrc[12];
		    printHex(pkt->mac+6,6,macsrc,12,NO);
		    printHex(pkt->mac+0,6,macdst,12,NO);
		    uint16_t ethtype = (pkt->mac[12] << 8) + pkt->mac[13];
		    myLog(LOG_INFO, "%s -> %s (ethertype=0x%04X)", macsrc, macdst, ethtype);
		  }
		}

		
		SFL_FLOW_SAMPLE_TYPE fs = { 0 };
	
		SFLSampler *sampler = NULL;

		// set the ingress and egress ifIndex numbers.
		// Can be "INTERNAL" (0x3FFFFFFF) or "UNKNOWN" (0).
		if(pkt->indev_name[0]) {
		  SFLAdaptor *in = adaptorListGet(sp->adaptorList, pkt->indev_name);
		  if(in && in->ifIndex) {
		    fs.input = in->ifIndex;
		    sampler = getSampler(sp, pkt->indev_name, in->ifIndex);
		  }
		}
		else {
		  fs.input = SFL_INTERNAL_INTERFACE;
		}
		if(pkt->outdev_name[0]) {
		  SFLAdaptor *out = adaptorListGet(sp->adaptorList, pkt->outdev_name);
		  if(out && out->ifIndex) {
		    fs.output = out->ifIndex;
		    sampler = getSampler(sp, pkt->outdev_name, out->ifIndex);
		  }
		}
		else {
		  fs.output = SFL_INTERNAL_INTERFACE;
		}

		if(sampler == NULL) {
		  // maybe ULOG sent us a packet on device lo(?)
		  if(debug > 1) myLog(LOG_INFO, "dropped sample with no ifIndex\n");
		}
		else {
		  SFLFlow_sample_element hdrElem = { 0 };
		  hdrElem.tag = SFLFLOW_HEADER;
		  uint32_t FCS_bytes = 4;
		  uint32_t maxHdrLen = sampler->sFlowFsMaximumHeaderSize;
		  hdrElem.flowType.header.frame_length = pkt->data_len + FCS_bytes;
		  hdrElem.flowType.header.stripped = FCS_bytes;
		
		  u_char hdr[HSP_MAX_HEADER_BYTES];
		
		  if(pkt->mac_len == 14) {
		    // set the header_protocol to ethernet and
		    // reunite the mac header and payload in one buffer
		    hdrElem.flowType.header.header_protocol = SFLHEADER_ETHERNET_ISO8023;
		    memcpy(hdr, pkt->mac, 14);
		    maxHdrLen -= 14;
		    uint32_t payloadBytes = (pkt->data_len < maxHdrLen) ? pkt->data_len : maxHdrLen;
		    memcpy(hdr+14, pkt->payload, payloadBytes);
		    hdrElem.flowType.header.header_length = payloadBytes + 14;
		    hdrElem.flowType.header.header_bytes = hdr;
		    hdrElem.flowType.header.frame_length += 14;
		  }
		  else {
		    // no need to copy - just point at the payload
		    u_char ipversion = pkt->payload[0] >> 4;
		    if(ipversion != 4 && ipversion != 6) {
		      if(debug) myLog(LOG_ERR, "received non-IP packet. Encapsulation is unknown");
		    }
		    else {
		      hdrElem.flowType.header.header_protocol = (ipversion == 4) ? SFLHEADER_IPv4 : SFLHEADER_IPv6;
		      hdrElem.flowType.header.stripped += 14; // assume ethernet was (or will be) the framing
		      hdrElem.flowType.header.header_length = (pkt->data_len < maxHdrLen) ? pkt->data_len : maxHdrLen;
		      hdrElem.flowType.header.header_bytes = pkt->payload;
		    }
		  }
		
		  SFLADD_ELEMENT(&fs, &hdrElem);
		  // submit the actual sampling rate so it goes out with the sFlow feed
		  // otherwise the sampler object would fill in his own (sub-sampling) rate.
		  uint32_t actualSamplingRate = sp->sFlow->sFlowSettings->ulogActualSamplingRate;
		  fs.sampling_rate = actualSamplingRate;

		  // estimate the sample pool from the samples.  Could maybe do this
		  // above with the (possibly more granular) ulogSamplingRate, but then
		  // we would have to look up the sampler object every time, which
		  // might be too expensive in the case where ulogSamplingRate==1.
		  sampler->samplePool += actualSamplingRate;

		  sfl_sampler_writeFlowSample(sampler, &fs);
		}
	      }
	    }
	  } 
	}
      }
    }
Пример #11
0
  int readPackets(HSP *sp)
  {
    int batch = 0;
    static uint32_t MySkipCount=1;

    if(sp->sFlow->sFlowSettings == NULL) {
      // config was turned off
      return 0;
    }

    if(sp->sFlow->sFlowSettings->ulogSubSamplingRate == 0) {
      // packet sampling was disabled by setting desired rate to 0
      return 0;
    }

    if(sp->ulog_soc) {
      for( ; batch < HSP_READPACKET_BATCH; batch++) {
	char buf[HSP_MAX_ULOG_MSG_BYTES];
	socklen_t peerlen = sizeof(sp->ulog_peer);
	int len = recvfrom(sp->ulog_soc,
			   buf,
			   HSP_MAX_ULOG_MSG_BYTES,
			   0,
			   (struct sockaddr *)&sp->ulog_peer,
			   &peerlen);
	if(len <= 0) break;
	if(debug > 1) myLog(LOG_INFO, "got ULOG msg: %u bytes", len);
	for(struct nlmsghdr *msg = (struct nlmsghdr *)buf; NLMSG_OK(msg, len); msg=NLMSG_NEXT(msg, len)) {

	  if(debug > 1) {
	    myLog(LOG_INFO, "netlink (%u bytes left) msg [len=%u type=%u flags=0x%x seq=%u pid=%u]",
		  len,
		  msg->nlmsg_len,
		  msg->nlmsg_type,
		  msg->nlmsg_flags,
		  msg->nlmsg_seq,
		  msg->nlmsg_pid);
	  }

          // check for drops indicated by sequence no
          uint32_t droppedSamples = 0;
          if(sp->ulog_seqno) {
            droppedSamples = msg->nlmsg_seq - sp->ulog_seqno - 1;
            if(droppedSamples) {
              sp->ulog_drops += droppedSamples;
            }
          }
          sp->ulog_seqno = msg->nlmsg_seq;

	  switch(msg->nlmsg_type) {
	  case NLMSG_NOOP:
	  case NLMSG_ERROR:
	  case NLMSG_OVERRUN:
	    // ignore these
	    break;
	  case NLMSG_DONE: // last in multi-part
	  default:
	    {

	      if(--MySkipCount == 0) {
		/* reached zero. Set the next skip */
		MySkipCount = sfl_random((2 * sp->sFlow->sFlowSettings->ulogSubSamplingRate) - 1);

		/* and take a sample */

		// we're seeing type==111 on Fedora14
		//if(msg->nlmsg_flags & NLM_F_REQUEST) { }
		//if(msg->nlmsg_flags & NLM_F_MULTI) { }
		//if(msg->nlmsg_flags & NLM_F_ACK) { }
		//if(msg->nlmsg_flags & NLM_F_ECHO) { }
		ulog_packet_msg_t *pkt = NLMSG_DATA(msg);
		
		if(debug > 1) {
		  myLog(LOG_INFO, "mark=%u ts=%s hook=%u in=%s out=%s len=%u prefix=%s maclen=%u",
			pkt->mark,
			ctime(&pkt->timestamp_sec),
			pkt->hook,
			pkt->indev_name,
			pkt->outdev_name,
			pkt->data_len,
			pkt->prefix,
			pkt->mac_len);
		  if(pkt->mac_len == 14) {
		    u_char macdst[12], macsrc[12];
		    printHex(pkt->mac+6,6,macsrc,12,NO);
		    printHex(pkt->mac+0,6,macdst,12,NO);
		    uint16_t ethtype = (pkt->mac[12] << 8) + pkt->mac[13];
		    myLog(LOG_INFO, "%s -> %s (ethertype=0x%04X)", macsrc, macdst, ethtype);
		  }
		}

		
		SFL_FLOW_SAMPLE_TYPE fs = { 0 };
	
		SFLAdaptor *sampler_dev = NULL;
                int inIsLoopback=0, outIsLoopback=0;
 
		// set the ingress and egress ifIndex numbers.
		// Can be "INTERNAL" (0x3FFFFFFF) or "UNKNOWN" (0).
		if(pkt->indev_name[0]) {
		  SFLAdaptor *in = adaptorListGet(sp->adaptorList, pkt->indev_name);
		  if(in) {
		    fs.input = in->ifIndex;
                    // record whether this was a loopback or not - used below
                    HSPAdaptorNIO *inNIO = (HSPAdaptorNIO *)in->userData;
                    inIsLoopback = inNIO->loopback;
#ifdef HSF_CUMULUS
                    // On Cumulus Linux the sampling direction is indicated in the low
                    // bit of the pkt->hook field: 0==ingress,1==egress
                    if((pkt->hook & 1) == 0) {
                      sampler_dev = in;
                    }
#else
                    // set this provisionally - may be overidden below
	            sampler_dev = in;
#endif
		  }
		}
		else {
		  fs.input = SFL_INTERNAL_INTERFACE;
		}
		if(pkt->outdev_name[0]) {
		  SFLAdaptor *out = adaptorListGet(sp->adaptorList, pkt->outdev_name);
		  if(out && out->ifIndex) {
		    fs.output = out->ifIndex;
                    HSPAdaptorNIO *outNIO = (HSPAdaptorNIO *)out->userData;
                    outIsLoopback = outNIO->loopback;
#ifdef HSF_CUMULUS
                    // On Cumulus Linux the sampling direction is indicated in the low
                    // bit of the pkt->hook field: 0==ingress,1==egress
                    if((pkt->hook & 1) == 1) {
                      sampler_dev = out;
                    }
#else
                    // If one of them is not a loopback interface, then assume the
                    // sample was taken there.  In a typical scenario most samples
	            // will be "lo" -> "eth0" or "eth0" -> "lo", so this ensures that
                    // that we make that look like bidirectional sampling on eth0.
                    if(sampler_dev == NULL
                       || (inIsLoopback && !outIsLoopback)) {
		      sampler_dev = out;
                    }
#endif
		  }
		}
		else {
		  fs.output = SFL_INTERNAL_INTERFACE;
		}

		// must have a sampler_dev with an ifIndex
		if(sampler_dev && sampler_dev->ifIndex) {
                  HSPAdaptorNIO *samplerNIO = (HSPAdaptorNIO *)sampler_dev->userData;

                  if(debug > 2) {
                    myLog(LOG_INFO, "selected sampler %s (loopback in=%d out=%d)",
                          sampler_dev->deviceName, 
                          inIsLoopback,
                          outIsLoopback);
                  }

		  SFLSampler *sampler = getSampler(sp, sampler_dev);
		  
		  if(sampler) {
		    SFLFlow_sample_element hdrElem = { 0 };
		    hdrElem.tag = SFLFLOW_HEADER;
		    uint32_t FCS_bytes = 4;
		    uint32_t maxHdrLen = sampler->sFlowFsMaximumHeaderSize;
		    hdrElem.flowType.header.frame_length = pkt->data_len + FCS_bytes;
		    hdrElem.flowType.header.stripped = FCS_bytes;
		    
		    u_char hdr[HSP_MAX_HEADER_BYTES];
		    
		    if(pkt->mac_len == 14) {
		      // set the header_protocol to ethernet and
		      // reunite the mac header and payload in one buffer
		      hdrElem.flowType.header.header_protocol = SFLHEADER_ETHERNET_ISO8023;
		      memcpy(hdr, pkt->mac, 14);
		      maxHdrLen -= 14;
		      uint32_t payloadBytes = (pkt->data_len < maxHdrLen) ? pkt->data_len : maxHdrLen;
		      memcpy(hdr+14, pkt->payload, payloadBytes);
		      hdrElem.flowType.header.header_length = payloadBytes + 14;
		      hdrElem.flowType.header.header_bytes = hdr;
		      hdrElem.flowType.header.frame_length += 14;
		    }
		    else {
		      // no need to copy - just point at the payload
		      u_char ipversion = pkt->payload[0] >> 4;
		      if(ipversion != 4 && ipversion != 6) {
			if(debug) myLog(LOG_ERR, "received non-IP packet. Encapsulation is unknown");
		      }
		      else {
			hdrElem.flowType.header.header_protocol = (ipversion == 4) ? SFLHEADER_IPv4 : SFLHEADER_IPv6;
			hdrElem.flowType.header.stripped += 14; // assume ethernet was (or will be) the framing
			hdrElem.flowType.header.header_length = (pkt->data_len < maxHdrLen) ? pkt->data_len : maxHdrLen;
			hdrElem.flowType.header.header_bytes = pkt->payload;
		      }
		    }
		    
		    SFLADD_ELEMENT(&fs, &hdrElem);
		    // submit the actual sampling rate so it goes out with the sFlow feed
		    // otherwise the sampler object would fill in his own (sub-sampling) rate.
		    // If it's a switch port then samplerNIO->sampling_n will be set, so that
		    // takes precendence (allows different ports to have different sampling
		    // settings).
		    uint32_t actualSamplingRate = samplerNIO->sampling_n ?: sp->sFlow->sFlowSettings->ulogActualSamplingRate;
		    fs.sampling_rate = actualSamplingRate;
		    
		    // estimate the sample pool from the samples.  Could maybe do this
		    // above with the (possibly more granular) ulogSamplingRate, but then
		    // we would have to look up the sampler object every time, which
		    // might be too expensive in the case where ulogSamplingRate==1.
		    sampler->samplePool += actualSamplingRate;
		    
                    // accumulate any dropped-samples we detected against whichever sampler
                    // sends the next sample. This is not perfect,  but is likely to accrue
                    // drops against the point whose sampling-rate needs to be adjusted.
                    samplerNIO->ulog_drops += droppedSamples;
                    fs.drops = samplerNIO->ulog_drops;
		    sfl_sampler_writeFlowSample(sampler, &fs);
		  }
		}
	      }
	    }
	  } 
	}
      }
Пример #12
0
/**
 * Reads a sampled packet header and associated information from
 * the buffer creates a packet sample.
 * Includes looking up the sampler from the ingress and egress
 * port information, and creating a new sampler (and poller) if
 * one does not already exist.
 */
void readPackets(HSP *sp, PUCHAR buffer)
{
	PSFlowSample sample = (PSFlowSample)buffer;
	if (sample->version != 1) {
		myLog(LOG_INFO, "readPackets: unknown filter sample version: %u", 
			  sample->version);
		return;
	}

	SFL_FLOW_SAMPLE_TYPE fs = { 0 };
	char *sampler_dev = NULL;
	uint32_t sampler_ifIndex = 0;
	// set the ingress and egress ifIndex numbers.
	// Can be "INTERNAL" (0x3FFFFFFF) or "UNKNOWN" (0).
	// mimic ingress sampling by using the ingress interface as the data source
	SFLAdaptor *in = getVAdaptorByIds(sp->vAdaptorList, sample->switchID, sample->srcPort);
	if (in) {
		fs.input = in->ifIndex;
		sampler_dev = in->deviceName;
		sampler_ifIndex = in->ifIndex;
	} 
	SFLAdaptor *out = getVAdaptorByIds(sp->vAdaptorList, sample->switchID, sample->destPort);
	if (out) {
		fs.output = out->ifIndex;
	} else {
		fs.output = 0;
	}
	// must have an ifIndex to generate a sample
	if (sampler_ifIndex) {
		SFLSampler *sampler = getSampler(sp, sampler_dev, sampler_ifIndex);
		if (sampler) {
			// submit the actual sampling rate so it goes out with the sFlow feed
			// otherwise the sampler object would fill in his own (sub-sampling) rate.
			fs.sampling_rate = sample->sampleRate;
			// estimate the sample pool from the samples. Could maybe do this
			// above with the (possibly more granular) samplingRate, but then
			// we would have to look up the sampler object every time, which
			// might be too expensive in the case where samplingRate==1.
			sampler->samplePool += sample->sampleRate;

			fs.drops = sample->drops;

			PSFlowRecord currRecord = &sample->firstRecord;
			SFLFlow_sample_element hdrElem = { 0 };
			SFLFlow_sample_element extSwElem = { 0 };
			while (currRecord->recordType != NULL_RECORD_TYPE) {
				switch(currRecord->recordType) {
				case SAMPLED_HEADER_RECORD_TYPE: {
					PSFlowSampledHeader sampledHeader = 
						GET_OPAQUE_DATA_ADDR(currRecord, PSFlowSampledHeader);
					hdrElem.tag = SFLFLOW_HEADER;
					hdrElem.flowType.header.frame_length = 
						sampledHeader->frameLength;
                    hdrElem.flowType.header.stripped = sampledHeader->stripped;
					hdrElem.flowType.header.header_protocol = SFLOW_HEADER_PROTOCOL;
					hdrElem.flowType.header.header_length = 
						currRecord->dataLength - sizeof(SFlowSampledHeader);
					hdrElem.flowType.header.header_bytes = GET_OPAQUE_DATA_ADDR(sampledHeader, PUCHAR);
					SFLADD_ELEMENT(&fs, &hdrElem);
					if (LOG_INFO <= debug) {
						 /*u_char pkt[HSP_MAX_HEADER_BYTES*2 +1]; //2 chars/byte + null
						printHex(GET_OPAQUE_DATA_ADDR(sampledHeader, PUCHAR), 
								 hdrElem.flowType.header.header_length, pkt, 
								 HSP_MAX_HEADER_BYTES*2+1, NO);*/
						myLog(LOG_INFO, "readPackets: sampler: %s index: %u headerLength: %u, frameLength: %u dropped: %u", 
							  sampler->userData, SFL_DS_INDEX(sampler->dsi), 
							  hdrElem.flowType.header.header_length, 
							  hdrElem.flowType.header.frame_length,
							  fs.drops);
					}
					break; }
				case EXTENDED_SWITCH_RECORD_TYPE: {
					PSFlowExtendedSwitch extendedSwitch =
						GET_OPAQUE_DATA_ADDR(currRecord, PSFlowExtendedSwitch);
					extSwElem.tag = SFLFLOW_EX_SWITCH;
					extSwElem.flowType.sw.src_vlan = extendedSwitch->sourceVLAN;
					extSwElem.flowType.sw.src_priority = extendedSwitch->sourcePriority;
					extSwElem.flowType.sw.dst_vlan = extendedSwitch->destVLAN;
					extSwElem.flowType.sw.dst_priority = extendedSwitch->destPriority;
					SFLADD_ELEMENT(&fs, &extSwElem);
					if (LOG_INFO <= debug) {
						myLog(LOG_INFO, "readPackets: sampler %s index %u srcVlan: %u srcPriority: %u dstVlan: %u dstPriority: %u",
							sampler->userData, SFL_DS_INDEX(sampler->dsi), 
							extSwElem.flowType.sw.src_vlan, extSwElem.flowType.sw.src_priority,
							extSwElem.flowType.sw.dst_vlan, extSwElem.flowType.sw.dst_priority);
					}
					break; }
                case EXTENDED_TUNNEL_RECORD_TYPE: {
                    PSFlowExtendedTunnel extendedTunnel =
                        GET_OPAQUE_DATA_ADDR(currRecord, PSFlowExtendedTunnel);
					if (LOG_INFO <= debug) {
						myLog(LOG_INFO, "readPackets: sampler %s index %u VSID: %u",
							sampler->userData, SFL_DS_INDEX(sampler->dsi), 
							extendedTunnel->vsid);
					}
                    break; }
				default: {
					myLog(LOG_INFO, "readPackets: unknown filter record type: %u", 
						currRecord->recordType); }
				}
				currRecord = GET_NEXT_SFLOW_RECORD(currRecord);
			}
			sfl_sampler_writeFlowSample(sampler, &fs);
		}
	}
}