for (i = 0; i < chain->n_tables; i++) {
struct sw_table *t = chain->tables[i];
struct sw_flow *flow = t->lookup(t, key);
- if (flow)
+ if (flow) {
+ t->n_matched++;
return flow;
+ }
}
return NULL;
}
kfree(chain);
}
-/* Prints statistics for each of the tables in 'chain'. */
-void chain_print_stats(struct sw_chain *chain)
-{
- int i;
-
- printk("\n");
- for (i = 0; i < chain->n_tables; i++) {
- struct sw_table *t = chain->tables[i];
- struct sw_table_stats stats;
- t->stats(t, &stats);
- printk("%s: %lu/%lu flows\n",
- stats.name, stats.n_flows, stats.max_flows);
- }
-}
-
-
int chain_set_hw_hook(struct sw_table *(*create_hw_table)(void),
struct module *owner)
{
int chain_delete(struct sw_chain *, const struct sw_flow_key *, uint16_t, int);
int chain_timeout(struct sw_chain *);
void chain_destroy(struct sw_chain *);
-void chain_print_stats(struct sw_chain *);
int chain_set_hw_hook(struct sw_table *(*create_hw_table)(void),
struct module *owner);
memset(ots->pad, 0, sizeof ots->pad);
ots->max_entries = htonl(stats.max_flows);
ots->active_count = htonl(stats.n_flows);
- ots->matched_count = cpu_to_be64(0); /* FIXME */
+ ots->matched_count = cpu_to_be64(stats.n_matched);
}
return 0;
}
stats->name = "hash";
stats->n_flows = th->n_flows;
stats->max_flows = th->bucket_mask + 1;
+ stats->n_matched = swt->n_matched;
}
struct sw_table *table_hash_create(unsigned int polynomial,
struct sw_table_hash *th;
struct sw_table *swt;
- th = kmalloc(sizeof *th, GFP_KERNEL);
+ th = kzalloc(sizeof *th, GFP_KERNEL);
if (th == NULL)
return NULL;
stats->name = "hash2";
stats->n_flows = substats[0].n_flows + substats[1].n_flows;
stats->max_flows = substats[0].max_flows + substats[1].max_flows;
+ stats->n_matched = swt->n_matched;
}
struct sw_table *table_hash2_create(unsigned int poly0, unsigned int buckets0,
struct sw_table_hash2 *t2;
struct sw_table *swt;
- t2 = kmalloc(sizeof *t2, GFP_KERNEL);
+ t2 = kzalloc(sizeof *t2, GFP_KERNEL);
if (t2 == NULL)
return NULL;
stats->name = "linear";
stats->n_flows = tl->n_flows;
stats->max_flows = tl->max_flows;
+ stats->n_matched = swt->n_matched;
}
/* Table statistics. */
struct sw_table_stats {
- const char *name; /* Human-readable name. */
- unsigned long int n_flows; /* Number of active flows. */
- unsigned long int max_flows; /* Flow capacity. */
+ const char *name; /* Human-readable name. */
+ unsigned int n_flows; /* Number of active flows. */
+ unsigned int max_flows; /* Flow capacity. */
+ unsigned long int n_matched; /* Number of packets that have hit. */
};
/* Position within an iteration of a sw_table.
* rcu_read_lock. destroy must be fully serialized.
*/
struct sw_table {
+ /* Keep track of the number of packets that matched this table. To
+ * make this 100% accurate, it should be atomic. However, we're
+ * primarily concerned about speed. */
+ unsigned long int n_matched;
+
/* Searches 'table' for a flow matching 'key', which must not have any
* wildcard fields. Returns the flow if successful, a null pointer
* otherwise. */
for (i = 0; i < chain->n_tables; i++) {
struct sw_table *t = chain->tables[i];
struct sw_flow *flow = t->lookup(t, key);
- if (flow)
+ if (flow) {
+ t->n_matched++;
return flow;
+ }
}
return NULL;
}
}
free(chain);
}
-
-/* Prints statistics for each of the tables in 'chain'. */
-void
-chain_print_stats(struct sw_chain *chain)
-{
- int i;
-
- printf("\n");
- for (i = 0; i < chain->n_tables; i++) {
- struct sw_table *t = chain->tables[i];
- struct sw_table_stats stats;
- t->stats(t, &stats);
- printf("%s: %lu/%lu flows\n",
- stats.name, stats.n_flows, stats.max_flows);
- }
-}
int chain_delete(struct sw_chain *, const struct sw_flow_key *, uint16_t, int);
void chain_timeout(struct sw_chain *, struct list *deleted);
void chain_destroy(struct sw_chain *);
-void chain_print_stats(struct sw_chain *);
#endif /* chain.h */
memset(ots->pad, 0, sizeof ots->pad);
ots->max_entries = htonl(stats.max_flows);
ots->active_count = htonl(stats.n_flows);
- ots->matched_count = htonll(0); /* FIXME */
+ ots->matched_count = htonll(stats.n_matched);
}
return 0;
}
stats->name = "hash";
stats->n_flows = th->n_flows;
stats->max_flows = th->bucket_mask + 1;
+ stats->n_matched = swt->n_matched;
}
struct sw_table *table_hash_create(unsigned int polynomial,
stats->name = "hash2";
stats->n_flows = substats[0].n_flows + substats[1].n_flows;
stats->max_flows = substats[0].max_flows + substats[1].max_flows;
+ stats->n_matched = swt->n_matched;
}
struct sw_table *table_hash2_create(unsigned int poly0, unsigned int buckets0,
stats->name = "linear";
stats->n_flows = tl->n_flows;
stats->max_flows = tl->max_flows;
+ stats->n_matched = swt->n_matched;
}
/* Table statistics. */
struct sw_table_stats {
- const char *name; /* Human-readable name. */
- unsigned long int n_flows; /* Number of active flows. */
- unsigned long int max_flows; /* Flow capacity. */
+ const char *name; /* Human-readable name. */
+ unsigned int n_flows; /* Number of active flows. */
+ unsigned int max_flows; /* Flow capacity. */
+ unsigned long int n_matched; /* Number of packets that have hit. */
};
/* Position within an iteration of a sw_table.
/* A single table of flows. */
struct sw_table {
+ /* Keep track of the number of packets that matched this table. To
+ * make this 100% accurate, it should be atomic. However, we're
+ * primarily concerned about speed. */
+ unsigned long int n_matched;
+
/* Searches 'table' for a flow matching 'key', which must not have any
* wildcard fields. Returns the flow if successful, a null pointer
* otherwise. */