From 3acd3a1906d2d6b09555ee88fedfe2a6c75008af Mon Sep 17 00:00:00 2001 From: Neil McKee Date: Mon, 15 Jul 2024 14:09:19 -0700 Subject: [PATCH] mod_sonic: accept max_header_size setting in Redis sFlow Global table, and disseminate to existing samplers --- src/Linux/hsflowd.c | 44 +++++++++++++++++++++++++++++++++++++++++ src/Linux/hsflowd.h | 1 + src/Linux/mod_pcap.c | 5 ++++- src/Linux/mod_sonic.c | 12 +++++++++++ src/Linux/readPackets.c | 2 +- 5 files changed, 62 insertions(+), 2 deletions(-) diff --git a/src/Linux/hsflowd.c b/src/Linux/hsflowd.c index 92dde73..20d4a42 100644 --- a/src/Linux/hsflowd.c +++ b/src/Linux/hsflowd.c @@ -1776,6 +1776,45 @@ extern "C" { return NO; } + /*_________________---------------------------__________________ + _________________ evt_all_header_bytes __________________ + -----------------___________________________------------------ + */ + + static void evt_all_header_bytes(EVMod *mod, EVEvent *evt, void *data, size_t dataLen) { + HSP *sp = (HSP *)EVROOTDATA(mod); + if(dataLen == sizeof(uint32_t)) { + uint32_t headerBytes = *(uint32_t *)data; + SFLSampler *samplers=NULL; + if(EVCurrentBus() == sp->packetBus) + samplers = sp->agent->samplers; + if(EVCurrentBus() == sp->pollBus) + samplers = sp->poll_agent->samplers; + for(SFLSampler *sm = samplers; sm; sm = sm->nxt) { + sfl_sampler_set_sFlowFsMaximumHeaderSize(sm, headerBytes); + } + } + } + + /*_________________---------------------------__________________ + _________________ updateHeaderBytes __________________ + -----------------___________________________------------------ + */ + + static void updateHeaderBytes(HSP *sp) { + if(sp->sFlowSettings) { + // pick up the configured headerBytes + uint32_t headerBytes = sp->sFlowSettings->headerBytes; + // apply constraints + if(headerBytes > HSP_MAX_HEADER_BYTES) { + headerBytes = HSP_MAX_HEADER_BYTES; + myDebug(1, "limiting headerBytes to max: %u", headerBytes); + } + // make sure any existing samplers get the memo, in any thread + EVEventTxAll(sp->rootModule, HSPEVENT_HEADER_BYTES, &headerBytes, sizeof(headerBytes)); + } + } + /*_________________---------------------------__________________ _________________ evt_config_first __________________ -----------------___________________________------------------ @@ -2016,6 +2055,9 @@ extern "C" { // adjust the polling schedule to respect constraints. (This is also called // if the interfaces change) configSwitchPorts(sp); // in readPackets.c + + // did the headerBytes setting change? + updateHeaderBytes(sp); } /*_________________---------------------------__________________ @@ -2571,6 +2613,8 @@ extern "C" { } // make sure every thread is notified on a change to the actual polling interval EVEventRxAll(sp->rootModule, HSPEVENT_POLL_INTERVAL, evt_all_poll_interval); + // make sure every thread is notified on a change to the header bytes setting + EVEventRxAll(sp->rootModule, HSPEVENT_HEADER_BYTES, evt_all_header_bytes); if(sp->DNSSD.DNSSD) { EVLoadModule(sp->rootModule, "mod_dnssd", sp->modulesPath); diff --git a/src/Linux/hsflowd.h b/src/Linux/hsflowd.h index c61e3b9..670a17f 100644 --- a/src/Linux/hsflowd.h +++ b/src/Linux/hsflowd.h @@ -436,6 +436,7 @@ extern "C" { #define HSPEVENT_REQUEST_POLLER "request_poller" // get counter samples for a switch port #define HSPEVENT_FLUSH_DATAGRAM "flush_datagram" // flush datagram (e.g. on counters batch) #define HSPEVENT_POLL_INTERVAL "poll_interval" // sent when actualPollingInterval changed +#define HSPEVENT_HEADER_BYTES "header_bytes" // (headerBytes) sent on config change typedef struct _HSPPendingSample { SFL_FLOW_SAMPLE_TYPE *fs; diff --git a/src/Linux/mod_pcap.c b/src/Linux/mod_pcap.c index 3c3a420..a4b2a0d 100644 --- a/src/Linux/mod_pcap.c +++ b/src/Linux/mod_pcap.c @@ -320,7 +320,10 @@ extern "C" { } // snaplen - if(pcap_set_snaplen(bpfs->pcap, sp->sFlowSettings_file->headerBytes) != 0) + // note that doing this here means we will not pick up any dynamic-config increase + // in the configured headerBytes (e.g. via DNS-SD). But it's not a problem for agents + // that require a restart on any change to the hsflowd.conf config file. + if(pcap_set_snaplen(bpfs->pcap, sp->sFlowSettings->headerBytes) != 0) myLog(LOG_ERR, "pcap: pcap_set_snaplen(%s) failed", bpfs->deviceName); // promiscuous mode diff --git a/src/Linux/mod_sonic.c b/src/Linux/mod_sonic.c index 2cb4613..fd56e01 100644 --- a/src/Linux/mod_sonic.c +++ b/src/Linux/mod_sonic.c @@ -50,6 +50,7 @@ extern "C" { #define HSP_SONIC_FIELD_SFLOW_AGENT "agent_id" #define HSP_SONIC_FIELD_SFLOW_DROP_MONITOR_LIMIT "drop_monitor_limit" // *proposed* #define HSP_SONIC_FIELD_SFLOW_SAMPLE_DIRECTION "sample_direction" // *proposed* +#define HSP_SONIC_FIELD_SFLOW_HEADER_BYTES "max_header_size" // *proposed* #define HSP_SONIC_FIELD_COLLECTOR_IP "collector_ip" #define HSP_SONIC_FIELD_COLLECTOR_PORT "collector_port" @@ -207,6 +208,7 @@ extern "C" { // sFlow config bool sflow_enable; uint32_t sflow_polling; + uint32_t sflow_headerBytes; char *sflow_agent; uint32_t sflow_dropLimit; bool sflow_dropLimit_set; @@ -1773,6 +1775,7 @@ extern "C" { bool sflow_enable = NO; char *sflow_agent = NULL; uint32_t sflow_polling = HSP_SONIC_DEFAULT_POLLING_INTERVAL; + uint32_t sflow_headerBytes = SFL_DEFAULT_HEADER_SIZE; uint32_t sflow_dropLimit = 0; char *sflow_direction = NULL; if(reply->type == REDIS_REPLY_ARRAY @@ -1793,6 +1796,9 @@ extern "C" { if(my_strequal(f_name->str, HSP_SONIC_FIELD_SFLOW_POLLING)) sflow_polling = db_getU32(f_val); + if(my_strequal(f_name->str, HSP_SONIC_FIELD_SFLOW_HEADER_BYTES)) + sflow_headerBytes = db_getU32(f_val); + if(my_strequal(f_name->str, HSP_SONIC_FIELD_SFLOW_DROP_MONITOR_LIMIT)) { sflow_dropLimit = db_getU32(f_val); mdata->sflow_dropLimit_set = YES; @@ -1820,6 +1826,10 @@ extern "C" { EVDebug(mod, 1, "sflow_polling %u -> %u", mdata->sflow_polling, sflow_polling); mdata->sflow_polling = sflow_polling; } + if(sflow_headerBytes != mdata->sflow_headerBytes) { + EVDebug(mod, 1, "sflow_headerBytes %u -> %u", mdata->sflow_headerBytes, sflow_headerBytes); + mdata->sflow_headerBytes = sflow_headerBytes; + } if(sflow_dropLimit != mdata->sflow_dropLimit) { EVDebug(mod, 1, "sflow_dropLimit %u -> %u", mdata->sflow_dropLimit, sflow_dropLimit); mdata->sflow_dropLimit = sflow_dropLimit; @@ -2177,6 +2187,8 @@ extern "C" { } snprintf(cfgLine, EV_MAX_EVT_DATALEN, "polling=%u", mdata->sflow_polling); EVEventTx(mod, mdata->configEvent, cfgLine, my_strlen(cfgLine)); + snprintf(cfgLine, EV_MAX_EVT_DATALEN, "headerBytes=%u", mdata->sflow_headerBytes); + EVEventTx(mod, mdata->configEvent, cfgLine, my_strlen(cfgLine)); if(mdata->sflow_dropLimit_set) { snprintf(cfgLine, EV_MAX_EVT_DATALEN, "dropLimit=%u", mdata->sflow_dropLimit); EVEventTx(mod, mdata->configEvent, cfgLine, my_strlen(cfgLine)); diff --git a/src/Linux/readPackets.c b/src/Linux/readPackets.c index 47f3eb5..3493242 100644 --- a/src/Linux/readPackets.c +++ b/src/Linux/readPackets.c @@ -58,7 +58,7 @@ extern "C" { sfl_sampler_set_sFlowFsReceiver(adaptorNIO->sampler, HSP_SFLOW_RECEIVER_INDEX); // TODO: adapt if headerBytes changes dynamically in config settings - broadcast event? // same as for changes in polling interval or datagram size? - sfl_sampler_set_sFlowFsMaximumHeaderSize(adaptorNIO->sampler, sp->sFlowSettings_file->headerBytes); + sfl_sampler_set_sFlowFsMaximumHeaderSize(adaptorNIO->sampler, sp->sFlowSettings->headerBytes); } return adaptorNIO->sampler; }