Add InMon's sFlow Agent library to the build system.
[cascardo/ovs.git] / lib / sflow_poller.c
diff --git a/lib/sflow_poller.c b/lib/sflow_poller.c
new file mode 100644 (file)
index 0000000..ffd09d3
--- /dev/null
@@ -0,0 +1,142 @@
+/* Copyright (c) 2002-2009 InMon Corp. Licensed under the terms of the InMon sFlow licence: */
+/* http://www.inmon.com/technology/sflowlicense.txt */
+
+#include "sflow_api.h"
+
+/*_________________--------------------------__________________
+  _________________    sfl_poller_init       __________________
+  -----------------__________________________------------------
+*/
+
+void sfl_poller_init(SFLPoller *poller,
+                    SFLAgent *agent,
+                    SFLDataSource_instance *pdsi,
+                    void *magic,         /* ptr to pass back in getCountersFn() */
+                    getCountersFn_t getCountersFn)
+{
+    /* copy the dsi in case it points to poller->dsi, which we are about to clear */
+    SFLDataSource_instance dsi = *pdsi;
+
+    /* preserve the *nxt pointer too, in case we are resetting this poller and it is
+       already part of the agent's linked list (thanks to Matt Woodly for pointing this out) */
+    SFLPoller *nxtPtr = poller->nxt;
+
+    /* clear everything */
+    memset(poller, 0, sizeof(*poller));
+  
+    /* restore the linked list ptr */
+    poller->nxt = nxtPtr;
+  
+    /* now copy in the parameters */
+    poller->agent = agent;
+    poller->dsi = dsi; /* structure copy */
+    poller->magic = magic;
+    poller->getCountersFn = getCountersFn;
+}
+
+/*_________________--------------------------__________________
+  _________________       reset              __________________
+  -----------------__________________________------------------
+*/
+
+static void reset(SFLPoller *poller)
+{
+    SFLDataSource_instance dsi = poller->dsi;
+    sfl_poller_init(poller, poller->agent, &dsi, poller->magic, poller->getCountersFn);
+}
+
+/*_________________---------------------------__________________
+  _________________      MIB access           __________________
+  -----------------___________________________------------------
+*/
+u_int32_t sfl_poller_get_sFlowCpReceiver(SFLPoller *poller) {
+    return poller->sFlowCpReceiver;
+}
+
+void sfl_poller_set_sFlowCpReceiver(SFLPoller *poller, u_int32_t sFlowCpReceiver) {
+    poller->sFlowCpReceiver = sFlowCpReceiver;
+    if(sFlowCpReceiver == 0) reset(poller);
+    else {
+       /* retrieve and cache a direct pointer to my receiver */
+       poller->myReceiver = sfl_agent_getReceiver(poller->agent, poller->sFlowCpReceiver);
+    }
+}
+
+u_int32_t sfl_poller_get_sFlowCpInterval(SFLPoller *poller) {
+    return poller->sFlowCpInterval;
+}
+
+void sfl_poller_set_sFlowCpInterval(SFLPoller *poller, u_int32_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 = 1 + (random() % sFlowCpInterval);
+}
+
+/*_________________---------------------------------__________________
+  _________________          bridge port            __________________
+  -----------------_________________________________------------------
+  May need a separate number to reference the local bridge port
+  to get counters if it is not the same as the global ifIndex.
+*/
+
+void sfl_poller_set_bridgePort(SFLPoller *poller, u_int32_t port_no) {
+    poller->bridgePort = port_no;
+}
+
+u_int32_t sfl_poller_get_bridgePort(SFLPoller *poller) {
+    return poller->bridgePort;
+}
+
+/*_________________---------------------------------__________________
+  _________________   sequence number reset         __________________
+  -----------------_________________________________------------------
+  Used to indicate a counter discontinuity
+  so that the sflow collector will know to ignore the next delta.
+*/
+void sfl_poller_resetCountersSeqNo(SFLPoller *poller) {  poller->countersSampleSeqNo = 0; }
+
+/*_________________---------------------------__________________
+  _________________    sfl_poller_tick        __________________
+  -----------------___________________________------------------
+*/
+
+void sfl_poller_tick(SFLPoller *poller, time_t now)
+{
+    if(poller->countersCountdown == 0) return; /* counters retrieval was not enabled */
+    if(poller->sFlowCpReceiver == 0) return;
+
+    if(--poller->countersCountdown == 0) {
+       if(poller->getCountersFn != NULL) {
+           /* call out for counters */
+           SFL_COUNTERS_SAMPLE_TYPE cs;
+           memset(&cs, 0, sizeof(cs));
+           poller->getCountersFn(poller->magic, poller, &cs);
+           /* this countersFn is expected to fill in some counter block elements
+              and then call sfl_poller_writeCountersSample(poller, &cs); */
+       }
+       /* reset the countdown */
+       poller->countersCountdown = poller->sFlowCpInterval;
+    }
+}
+
+/*_________________---------------------------------__________________
+  _________________ sfl_poller_writeCountersSample  __________________
+  -----------------_________________________________------------------
+*/
+
+void sfl_poller_writeCountersSample(SFLPoller *poller, SFL_COUNTERS_SAMPLE_TYPE *cs)
+{
+    /* fill in the rest of the header fields, and send to the receiver */
+    cs->sequence_number = ++poller->countersSampleSeqNo;
+#ifdef SFL_USE_32BIT_INDEX
+    cs->ds_class = SFL_DS_CLASS(poller->dsi);
+    cs->ds_index = SFL_DS_INDEX(poller->dsi);
+#else
+    cs->source_id = SFL_DS_DATASOURCE(poller->dsi);
+#endif
+    /* sent to my receiver */
+    if(poller->myReceiver) sfl_receiver_writeCountersSample(poller->myReceiver, cs);
+}
+