summaryrefslogtreecommitdiffstats
path: root/sys/netgraph/netflow/netflow.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netgraph/netflow/netflow.c')
-rw-r--r--sys/netgraph/netflow/netflow.c207
1 files changed, 125 insertions, 82 deletions
diff --git a/sys/netgraph/netflow/netflow.c b/sys/netgraph/netflow/netflow.c
index dfbb507..8ec5629 100644
--- a/sys/netgraph/netflow/netflow.c
+++ b/sys/netgraph/netflow/netflow.c
@@ -100,7 +100,7 @@ static int export_send(priv_p, fib_export_p, item_p, int);
static int hash_insert(priv_p, struct flow_hash_entry *, struct flow_rec *, int, uint8_t);
#ifdef INET6
-static int hash6_insert(priv_p, struct flow6_hash_entry *, struct flow6_rec *, int, uint8_t);
+static int hash6_insert(priv_p, struct flow_hash_entry *, struct flow6_rec *, int, uint8_t);
#endif
static __inline void expire_flow(priv_p, fib_export_p, struct flow_entry *, int);
@@ -412,7 +412,7 @@ hash_insert(priv_p priv, struct flow_hash_entry *hsh, struct flow_rec *r,
bitcount32((x).__u6_addr.__u6_addr32[3])
/* XXX: Do we need inline here ? */
static __inline int
-hash6_insert(priv_p priv, struct flow6_hash_entry *hsh6, struct flow6_rec *r,
+hash6_insert(priv_p priv, struct flow_hash_entry *hsh6, struct flow6_rec *r,
int plen, uint8_t tcp_flags)
{
struct flow6_entry *fle6;
@@ -491,7 +491,7 @@ hash6_insert(priv_p priv, struct flow6_hash_entry *hsh6, struct flow6_rec *r,
}
/* Push new flow at the and of hash. */
- TAILQ_INSERT_TAIL(&hsh6->head, fle6, fle6_hash);
+ TAILQ_INSERT_TAIL(&hsh6->head, (struct flow_entry *)fle6, fle_hash);
return (0);
}
@@ -507,9 +507,6 @@ void
ng_netflow_cache_init(priv_p priv)
{
struct flow_hash_entry *hsh;
-#ifdef INET6
- struct flow6_hash_entry *hsh6;
-#endif
int i;
/* Initialize cache UMA zone. */
@@ -534,13 +531,13 @@ ng_netflow_cache_init(priv_p priv)
#ifdef INET6
/* Allocate hash. */
- priv->hash6 = malloc(NBUCKETS * sizeof(struct flow6_hash_entry),
+ priv->hash6 = malloc(NBUCKETS * sizeof(struct flow_hash_entry),
M_NETFLOW_HASH, M_WAITOK | M_ZERO);
/* Initialize hash. */
- for (i = 0, hsh6 = priv->hash6; i < NBUCKETS; i++, hsh6++) {
- mtx_init(&hsh6->mtx, "hash mutex", NULL, MTX_DEF);
- TAILQ_INIT(&hsh6->head);
+ for (i = 0, hsh = priv->hash6; i < NBUCKETS; i++, hsh++) {
+ mtx_init(&hsh->mtx, "hash mutex", NULL, MTX_DEF);
+ TAILQ_INIT(&hsh->head);
}
#endif
@@ -588,10 +585,6 @@ ng_netflow_cache_flush(priv_p priv)
{
struct flow_entry *fle, *fle1;
struct flow_hash_entry *hsh;
-#ifdef INET6
- struct flow6_entry *fle6, *fle61;
- struct flow6_hash_entry *hsh6;
-#endif
struct netflow_export_item exp;
fib_export_p fe;
int i;
@@ -610,11 +603,11 @@ ng_netflow_cache_flush(priv_p priv)
expire_flow(priv, fe, fle, NG_QUEUE);
}
#ifdef INET6
- for (hsh6 = priv->hash6, i = 0; i < NBUCKETS; hsh6++, i++)
- TAILQ_FOREACH_SAFE(fle6, &hsh6->head, fle6_hash, fle61) {
- TAILQ_REMOVE(&hsh6->head, fle6, fle6_hash);
- fe = priv_to_fib(priv, fle6->f.r.fib);
- expire_flow(priv, fe, (struct flow_entry *)fle6, NG_QUEUE);
+ for (hsh = priv->hash6, i = 0; i < NBUCKETS; hsh++, i++)
+ TAILQ_FOREACH_SAFE(fle, &hsh->head, fle_hash, fle1) {
+ TAILQ_REMOVE(&hsh->head, fle, fle_hash);
+ fe = priv_to_fib(priv, fle->f.r.fib);
+ expire_flow(priv, fe, fle, NG_QUEUE);
}
#endif
@@ -629,8 +622,8 @@ ng_netflow_cache_flush(priv_p priv)
#ifdef INET6
uma_zdestroy(priv->zone6);
/* Destroy hash mutexes. */
- for (i = 0, hsh6 = priv->hash6; i < NBUCKETS; i++, hsh6++)
- mtx_destroy(&hsh6->mtx);
+ for (i = 0, hsh = priv->hash6; i < NBUCKETS; i++, hsh++)
+ mtx_destroy(&hsh->mtx);
/* Free hash memory. */
if (priv->hash6 != NULL)
@@ -790,8 +783,9 @@ int
ng_netflow_flow6_add(priv_p priv, fib_export_p fe, struct ip6_hdr *ip6, caddr_t upper_ptr, uint8_t upper_proto,
uint8_t is_frag, unsigned int src_if_index)
{
- register struct flow6_entry *fle6 = NULL, *fle61;
- struct flow6_hash_entry *hsh6;
+ register struct flow_entry *fle = NULL, *fle1;
+ register struct flow6_entry *fle6;
+ struct flow_hash_entry *hsh;
struct flow6_rec r;
int plen;
int error = 0;
@@ -846,9 +840,9 @@ ng_netflow_flow6_add(priv_p priv, fib_export_p fe, struct ip6_hdr *ip6, caddr_t
priv->info.nfinfo_bytes6 += plen;
/* Find hash slot. */
- hsh6 = &priv->hash6[ip6_hash(&r)];
+ hsh = &priv->hash6[ip6_hash(&r)];
- mtx_lock(&hsh6->mtx);
+ mtx_lock(&hsh->mtx);
/*
* Go through hash and find our entry. If we encounter an
@@ -856,19 +850,22 @@ ng_netflow_flow6_add(priv_p priv, fib_export_p fe, struct ip6_hdr *ip6, caddr_t
* search since most active entries are first, and most
* searches are done on most active entries.
*/
- TAILQ_FOREACH_REVERSE_SAFE(fle6, &hsh6->head, f6head, fle6_hash, fle61) {
- if (fle6->f.version != IP6VERSION)
+ TAILQ_FOREACH_REVERSE_SAFE(fle, &hsh->head, fhead, fle_hash, fle1) {
+ if (fle->f.version != IP6VERSION)
continue;
+ fle6 = (struct flow6_entry *)fle;
if (bcmp(&r, &fle6->f.r, sizeof(struct flow6_rec)) == 0)
break;
if ((INACTIVE(fle6) && SMALL(fle6)) || AGED(fle6)) {
- TAILQ_REMOVE(&hsh6->head, fle6, fle6_hash);
- expire_flow(priv, priv_to_fib(priv, fle6->f.r.fib), (struct flow_entry *)fle6, NG_QUEUE);
+ TAILQ_REMOVE(&hsh->head, fle, fle_hash);
+ expire_flow(priv, priv_to_fib(priv, fle->f.r.fib), fle,
+ NG_QUEUE);
atomic_add_32(&priv->info.nfinfo_act_exp, 1);
}
}
- if (fle6 != NULL) { /* An existent entry. */
+ if (fle != NULL) { /* An existent entry. */
+ fle6 = (struct flow6_entry *)fle;
fle6->f.bytes += plen;
fle6->f.packets ++;
@@ -883,8 +880,9 @@ ng_netflow_flow6_add(priv_p priv, fib_export_p fe, struct ip6_hdr *ip6, caddr_t
*/
if (tcp_flags & TH_FIN || tcp_flags & TH_RST || AGED(fle6) ||
(fle6->f.bytes >= (CNTR_MAX - IF_MAXMTU)) ) {
- TAILQ_REMOVE(&hsh6->head, fle6, fle6_hash);
- expire_flow(priv, priv_to_fib(priv, fle6->f.r.fib), (struct flow_entry *)fle6, NG_QUEUE);
+ TAILQ_REMOVE(&hsh->head, fle, fle_hash);
+ expire_flow(priv, priv_to_fib(priv, fle->f.r.fib), fle,
+ NG_QUEUE);
atomic_add_32(&priv->info.nfinfo_act_exp, 1);
} else {
/*
@@ -892,15 +890,15 @@ ng_netflow_flow6_add(priv_p priv, fib_export_p fe, struct ip6_hdr *ip6, caddr_t
* if it isn't there already. Next search will
* locate it quicker.
*/
- if (fle6 != TAILQ_LAST(&hsh6->head, f6head)) {
- TAILQ_REMOVE(&hsh6->head, fle6, fle6_hash);
- TAILQ_INSERT_TAIL(&hsh6->head, fle6, fle6_hash);
+ if (fle != TAILQ_LAST(&hsh->head, fhead)) {
+ TAILQ_REMOVE(&hsh->head, fle, fle_hash);
+ TAILQ_INSERT_TAIL(&hsh->head, fle, fle_hash);
}
}
} else /* A new flow entry. */
- error = hash6_insert(priv, hsh6, &r, plen, tcp_flags);
+ error = hash6_insert(priv, hsh, &r, plen, tcp_flags);
- mtx_unlock(&hsh6->mtx);
+ mtx_unlock(&hsh->mtx);
return (error);
}
@@ -910,64 +908,109 @@ ng_netflow_flow6_add(priv_p priv, fib_export_p fe, struct ip6_hdr *ip6, caddr_t
* Return records from cache to userland.
*
* TODO: matching particular IP should be done in kernel, here.
- * XXX: IPv6 flows will return random data
*/
int
-ng_netflow_flow_show(priv_p priv, uint32_t last, struct ng_mesg *resp)
+ng_netflow_flow_show(priv_p priv, struct ngnf_show_header *req,
+struct ngnf_show_header *resp)
{
struct flow_hash_entry *hsh;
struct flow_entry *fle;
- struct ngnf_flows *data;
- int i;
+ struct flow_entry_data *data = (struct flow_entry_data *)(resp + 1);
+#ifdef INET6
+ struct flow6_entry_data *data6 = (struct flow6_entry_data *)(resp + 1);
+#endif
+ int i, max;
- data = (struct ngnf_flows *)resp->data;
- data->last = 0;
- data->nentries = 0;
+ i = req->hash_id;
+ if (i > NBUCKETS-1)
+ return (EINVAL);
- /* Check if this is a first run */
- if (last == 0) {
- hsh = priv->hash;
- i = 0;
- } else {
- if (last > NBUCKETS-1)
- return (EINVAL);
- hsh = priv->hash + last;
- i = last;
- }
+#ifdef INET6
+ if (req->version == 6) {
+ resp->version = 6;
+ hsh = priv->hash6 + i;
+ max = NREC6_AT_ONCE;
+ } else
+#endif
+ if (req->version == 4) {
+ resp->version = 4;
+ hsh = priv->hash + i;
+ max = NREC_AT_ONCE;
+ } else
+ return (EINVAL);
/*
* We will transfer not more than NREC_AT_ONCE. More data
* will come in next message.
- * We send current hash index to userland, and userland should
- * return it back to us. Then, we will restart with new entry.
+ * We send current hash index and current record number in list
+ * to userland, and userland should return it back to us.
+ * Then, we will restart with new entry.
*
- * The resulting cache snapshot is inaccurate for the
- * following reasons:
- * - we skip locked hash entries
- * - we bail out, if someone wants our entry
- * - we skip rest of entry, when hit NREC_AT_ONCE
+ * The resulting cache snapshot can be inaccurate if flow expiration
+ * is taking place on hash item between userland data requests for
+ * this hash item id.
*/
+ resp->nentries = 0;
for (; i < NBUCKETS; hsh++, i++) {
- if (mtx_trylock(&hsh->mtx) == 0)
- continue;
+ int list_id;
+ if (mtx_trylock(&hsh->mtx) == 0) {
+ /*
+ * Requested hash index is not available,
+ * relay decision to skip or re-request data
+ * to userland.
+ */
+ resp->hash_id = i;
+ resp->list_id = 0;
+ return (0);
+ }
+
+ list_id = 0;
TAILQ_FOREACH(fle, &hsh->head, fle_hash) {
- if (hsh->mtx.mtx_lock & MTX_CONTESTED)
- break;
+ if (hsh->mtx.mtx_lock & MTX_CONTESTED) {
+ resp->hash_id = i;
+ resp->list_id = list_id;
+ mtx_unlock(&hsh->mtx);
+ return (0);
+ }
+
+ list_id++;
+ /* Search for particular record in list. */
+ if (req->list_id > 0) {
+ if (list_id < req->list_id)
+ continue;
- bcopy(&fle->f, &(data->entries[data->nentries]),
- sizeof(fle->f));
- data->nentries++;
- if (data->nentries == NREC_AT_ONCE) {
+ /* Requested list position found. */
+ req->list_id = 0;
+ }
+#ifdef INET6
+ if (req->version == 6) {
+ struct flow6_entry *fle6;
+
+ fle6 = (struct flow6_entry *)fle;
+ bcopy(&fle6->f, data6 + resp->nentries,
+ sizeof(fle6->f));
+ } else
+#endif
+ bcopy(&fle->f, data + resp->nentries,
+ sizeof(fle->f));
+ resp->nentries++;
+ if (resp->nentries == max) {
+ resp->hash_id = i;
+ /*
+ * If it was the last item in list
+ * we simply skip to next hash_id.
+ */
+ resp->list_id = list_id + 1;
mtx_unlock(&hsh->mtx);
- if (++i < NBUCKETS)
- data->last = i;
return (0);
}
}
mtx_unlock(&hsh->mtx);
}
+ resp->hash_id = resp->list_id = 0;
+
return (0);
}
@@ -1057,10 +1100,6 @@ ng_netflow_expire(void *arg)
{
struct flow_entry *fle, *fle1;
struct flow_hash_entry *hsh;
-#ifdef INET6
- struct flow6_entry *fle6, *fle61;
- struct flow6_hash_entry *hsh6;
-#endif
priv_p priv = (priv_p )arg;
uint32_t used;
int i;
@@ -1103,20 +1142,23 @@ ng_netflow_expire(void *arg)
}
#ifdef INET6
- for (hsh6 = priv->hash6, i = 0; i < NBUCKETS; hsh6++, i++) {
+ for (hsh = priv->hash6, i = 0; i < NBUCKETS; hsh++, i++) {
+ struct flow6_entry *fle6;
+
/*
* Skip entries, that are already being worked on.
*/
- if (mtx_trylock(&hsh6->mtx) == 0)
+ if (mtx_trylock(&hsh->mtx) == 0)
continue;
used = atomic_load_acq_32(&priv->info.nfinfo_used6);
- TAILQ_FOREACH_SAFE(fle6, &hsh6->head, fle6_hash, fle61) {
+ TAILQ_FOREACH_SAFE(fle, &hsh->head, fle_hash, fle1) {
+ fle6 = (struct flow6_entry *)fle;
/*
* Interrupt thread wants this entry!
* Quick! Quick! Bail out!
*/
- if (hsh6->mtx.mtx_lock & MTX_CONTESTED)
+ if (hsh->mtx.mtx_lock & MTX_CONTESTED)
break;
/*
@@ -1128,13 +1170,14 @@ ng_netflow_expire(void *arg)
if ((INACTIVE(fle6) && (SMALL(fle6) ||
(used > (NBUCKETS*2)))) || AGED(fle6)) {
- TAILQ_REMOVE(&hsh6->head, fle6, fle6_hash);
- expire_flow(priv, priv_to_fib(priv, fle6->f.r.fib), (struct flow_entry *)fle6, NG_NOFLAGS);
+ TAILQ_REMOVE(&hsh->head, fle, fle_hash);
+ expire_flow(priv, priv_to_fib(priv,
+ fle->f.r.fib), fle, NG_NOFLAGS);
used--;
atomic_add_32(&priv->info.nfinfo_inact_exp, 1);
}
}
- mtx_unlock(&hsh6->mtx);
+ mtx_unlock(&hsh->mtx);
}
#endif
OpenPOWER on IntegriCloud