void sfl_poller_set_sFlowCpInterval(SFLPoller *poller, uint32_t sFlowCpInterval) { poller->sFlowCpInterval = sFlowCpInterval; /* Set the countersCountdown to be a randomly selected value between 1 and sFlowCpInterval. That way the counter polling would be desynchronised (on a 200-port switch, polling all the counters in one second could be harmful). */ poller->countersCountdown = sfl_random(sFlowCpInterval); }
int sfl_sampler_takeSample(SFLSampler *sampler) { // increment the samplePool sampler->samplePool++; if(--sampler->skip == 0) { /* reached zero. Set the next skip and return true. */ sampler->skip = sfl_random((2 * sampler->sFlowFsPacketSamplingRate) - 1); return 1; } return 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); } } } } } } }
void sfl_sampler_set_sFlowFsPacketSamplingRate(SFLSampler *sampler, uint32_t sFlowFsPacketSamplingRate) { sampler->sFlowFsPacketSamplingRate = sFlowFsPacketSamplingRate; // initialize the skip count too sampler->skip = sfl_random(sFlowFsPacketSamplingRate); }
int readPackets_ulog(EVMod *mod, EVBus *bus, int fd, void *data) { HSP_mod_ULOG *mdata = (HSP_mod_ULOG *)mod->data; HSP *sp = (HSP *)EVROOTDATA(mod); int batch = 0; static uint32_t MySkipCount=1; if(sp->sFlowSettings == NULL) { // config was turned off return 0; } if(mdata->subSamplingRate == 0) { // packet sampling was disabled by setting desired rate to 0 return 0; } for( ; batch < HSP_READPACKET_BATCH_ULOG; batch++) { char buf[HSP_MAX_ULOG_MSG_BYTES]; int len = recvfrom(mdata->ulog_soc, buf, HSP_MAX_ULOG_MSG_BYTES, 0, NULL, NULL); if(len <= 0) break; myDebug(1, "got ULOG msg: %u bytes", len); for(struct nlmsghdr *msg = (struct nlmsghdr *)buf; NLMSG_OK(msg, len); msg=NLMSG_NEXT(msg, len)) { myDebug(1, "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(mdata->ulog_seqno) { droppedSamples = msg->nlmsg_seq - mdata->ulog_seqno - 1; if(droppedSamples) { mdata->ulog_drops += droppedSamples; } } mdata->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 */ uint32_t sr = mdata->subSamplingRate; MySkipCount = sr == 1 ? 1 : sfl_random((2 * sr) - 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); myDebug(LOG_INFO, "ULOG mark=%u ts=%s prefix=%s", pkt->mark, ctime(&pkt->timestamp_sec), pkt->prefix); SFLAdaptor *dev_in = NULL; SFLAdaptor *dev_out = NULL; if(pkt->indev_name[0]) { dev_in = adaptorByName(sp, pkt->indev_name); } if(pkt->outdev_name[0]) { dev_out = adaptorByName(sp, pkt->outdev_name); } takeSample(sp, dev_in, dev_out, NULL, NO, pkt->hook, pkt->mac, pkt->mac_len, pkt->payload, pkt->data_len, /* length of captured payload */ pkt->data_len, /* length of packet (pdu) */ droppedSamples, mdata->actualSamplingRate); } } } } } return batch; }
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); } } } } } } }