--- collectd-5.5.1_orig/src/iptables.c
+++ collectd-5.5.1/src/iptables.c
@@ -236,10 +236,79 @@ static int iptables_config (const char *
        return (0);
 } /* int iptables_config */
 
+
+/* stack for storing value_list_t's that would otherwise be dispatched immediately */
+typedef struct value_list_list_s
+{
+    value_t value; // deep copy of vl.values
+    value_list_t vl;
+    struct value_list_list_s *next;
+} value_list_list_t;
+
+
+/* adds a value_list_t to an existing one that shares the same comment or push it as a new node */
+static void plugin_aggregate_values(value_list_list_t **vll, const value_list_t *vl)
+{
+    assert (vl->values_len == 1); // using only a single value
+    assert (vl->meta == NULL); // not used
+
+    // check whether there already is a node for this counter
+    value_list_list_t *it = *vll;
+    while (it)
+    {
+        if ((strcmp (it->vl.plugin_instance, vl->plugin_instance) == 0) &&
+            (strcmp (it->vl.type, vl->type) == 0) &&
+            (strcmp (it->vl.type_instance, vl->type_instance) == 0))
+        {
+            break; // found it
+        }
+        it = it->next;
+    }
+
+    if (it != NULL)
+    {
+        // found: sum up
+        it->value.derive += vl->values->derive; // we know it's a derive
+    }
+    else
+    {
+        // allocate new stack node
+        it = (value_list_list_t*) malloc (sizeof(value_list_list_t)); // XXX: could use plugin_value_list_clone() instead?
+        if (it == NULL)
+        {
+            return; // oom
+        }
+
+        // deep copy
+        it->vl = *vl;
+        it->value = *vl->values;
+        it->vl.values = &it->value;
+
+        // update stack
+        it->next = *vll;
+        *vll = it;
+    }
+}
+
+
+/* dispatch buffered value_list_t's and clear stack */
+static void plugin_dispatch_aggregate_values(value_list_list_t *vll)
+{
+    while (vll != NULL)
+    {
+        plugin_dispatch_values (&vll->vl);
+        value_list_list_t *tmp = vll;
+        vll = vll->next;
+        free (tmp);
+    }
+}
+
+
 static int submit6_match (const struct ip6t_entry_match *match,
                 const struct ip6t_entry *entry,
                 const ip_chain_t *chain,
-                int rule_num)
+                int rule_num,
+                value_list_list_t **vll)
 {
     int status;
     value_t values[1];
@@ -286,11 +355,11 @@ static int submit6_match (const struct i
 
     sstrncpy (vl.type, "ipt_bytes", sizeof (vl.type));
     values[0].derive = (derive_t) entry->counters.bcnt;
-    plugin_dispatch_values (&vl);
+    plugin_aggregate_values (vll, &vl);
 
     sstrncpy (vl.type, "ipt_packets", sizeof (vl.type));
     values[0].derive = (derive_t) entry->counters.pcnt;
-    plugin_dispatch_values (&vl);
+    plugin_aggregate_values (vll, &vl);
 
     return (0);
 } /* int submit_match */
@@ -300,7 +369,8 @@ static int submit6_match (const struct i
 static int submit_match (const struct ipt_entry_match *match,
                const struct ipt_entry *entry,
                const ip_chain_t *chain,
-		int rule_num) 
+		int rule_num,
+		value_list_list_t **vll)
 {
     int status;
     value_t values[1];
@@ -347,11 +417,11 @@ static int submit_match (const struct ip
 
     sstrncpy (vl.type, "ipt_bytes", sizeof (vl.type));
     values[0].derive = (derive_t) entry->counters.bcnt;
-    plugin_dispatch_values (&vl);
+    plugin_aggregate_values (vll, &vl);
 
     sstrncpy (vl.type, "ipt_packets", sizeof (vl.type));
     values[0].derive = (derive_t) entry->counters.pcnt;
-    plugin_dispatch_values (&vl);
+    plugin_aggregate_values (vll, &vl);
 
     return (0);
 } /* int submit_match */
@@ -362,6 +432,7 @@ static void submit6_chain( ip6tc_handle_
 {
     const struct ip6t_entry *entry;
     int rule_num;
+    value_list_list_t* vll = NULL;
 
     /* Find first rule for chain and use the iterate macro */
     entry = ip6tc_first_rule( chain->chain, handle );
@@ -376,16 +447,18 @@ static void submit6_chain( ip6tc_handle_
     {
         if (chain->rule_type == RTYPE_NUM)
         {
-            submit6_match (NULL, entry, chain, rule_num);
+            submit6_match (NULL, entry, chain, rule_num, &vll);
         }
         else
         {
-            IP6T_MATCH_ITERATE( entry, submit6_match, entry, chain, rule_num );
+            IP6T_MATCH_ITERATE( entry, submit6_match, entry, chain, rule_num, &vll );
         }
 
         entry = ip6tc_next_rule( entry, handle );
         rule_num++;
     } /* while (entry) */
+
+    plugin_dispatch_aggregate_values( vll );
 }
 
 
@@ -394,6 +467,7 @@ static void submit_chain( iptc_handle_t
 {
     const struct ipt_entry *entry;
     int rule_num;
+    value_list_list_t* vll = NULL;
 
     /* Find first rule for chain and use the iterate macro */    
     entry = iptc_first_rule( chain->chain, handle );
@@ -408,16 +482,18 @@ static void submit_chain( iptc_handle_t
     {
        if (chain->rule_type == RTYPE_NUM)
        {
-	    submit_match (NULL, entry, chain, rule_num);
+	    submit_match (NULL, entry, chain, rule_num, &vll);
        }
        else
        {
-	    IPT_MATCH_ITERATE( entry, submit_match, entry, chain, rule_num );
+	    IPT_MATCH_ITERATE( entry, submit_match, entry, chain, rule_num, &vll );
        }
 
        entry = iptc_next_rule( entry, handle );
        rule_num++;
     } /* while (entry) */
+
+    plugin_dispatch_aggregate_values( vll );
 }