From owner-svn-src-all@FreeBSD.ORG Tue Jul 5 14:48:40 2011 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 14B32106564A; Tue, 5 Jul 2011 14:48:40 +0000 (UTC) (envelope-from glebius@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 038148FC19; Tue, 5 Jul 2011 14:48:40 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id p65EmdqQ073576; Tue, 5 Jul 2011 14:48:39 GMT (envelope-from glebius@svn.freebsd.org) Received: (from glebius@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id p65EmdUv073572; Tue, 5 Jul 2011 14:48:39 GMT (envelope-from glebius@svn.freebsd.org) Message-Id: <201107051448.p65EmdUv073572@svn.freebsd.org> From: Gleb Smirnoff Date: Tue, 5 Jul 2011 14:48:39 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r223787 - head/sys/netgraph/netflow X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 05 Jul 2011 14:48:40 -0000 Author: glebius Date: Tue Jul 5 14:48:39 2011 New Revision: 223787 URL: http://svn.freebsd.org/changeset/base/223787 Log: o Eliminate flow6_hash_entry in favor of flow_hash_entry. We don't need a separate struct to start a slist of semi-opaque structs. This makes some code more compact. o Rewrite ng_netflow_flow_show() and its API/ABI: - Support for IPv6 is added. - Request and response now use same struct. Structure specifies version (6 or 4), index of last retrieved hash, and also index of last retrieved entry in the hash entry. Modified: head/sys/netgraph/netflow/netflow.c head/sys/netgraph/netflow/ng_netflow.c head/sys/netgraph/netflow/ng_netflow.h Modified: head/sys/netgraph/netflow/netflow.c ============================================================================== --- head/sys/netgraph/netflow/netflow.c Tue Jul 5 14:12:48 2011 (r223786) +++ head/sys/netgraph/netflow/netflow.c Tue Jul 5 14:48:39 2011 (r223787) @@ -100,7 +100,7 @@ static int export_send(priv_p, fib_expor 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_has 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_h } /* 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_ex 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_ex * 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_ex */ 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_ex * 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,107 @@ ng_netflow_flow6_add(priv_p priv, fib_ex * 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; - - /* 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; - } + i = req->hash_id; + if (i > NBUCKETS-1) + return (EINVAL); + +#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; + 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) { - mtx_unlock(&hsh->mtx); - if (++i < NBUCKETS) - data->last = i; + /* 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; return (0); } } mtx_unlock(&hsh->mtx); } + resp->hash_id = resp->list_id = 0; + return (0); } @@ -1057,10 +1098,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 +1140,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 +1168,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 Modified: head/sys/netgraph/netflow/ng_netflow.c ============================================================================== --- head/sys/netgraph/netflow/ng_netflow.c Tue Jul 5 14:12:48 2011 (r223786) +++ head/sys/netgraph/netflow/ng_netflow.c Tue Jul 5 14:48:39 2011 (r223787) @@ -504,19 +504,20 @@ ng_netflow_rcvmsg (node_p node, item_p i } case NGM_NETFLOW_SHOW: { - uint32_t *last; - - if (msg->header.arglen != sizeof(uint32_t)) + if (msg->header.arglen != sizeof(struct ngnf_show_header)) ERROUT(EINVAL); - last = (uint32_t *)msg->data; - NG_MKRESPONSE(resp, msg, NGRESP_SIZE, M_NOWAIT); if (!resp) ERROUT(ENOMEM); - error = ng_netflow_flow_show(priv, *last, resp); + error = ng_netflow_flow_show(priv, + (struct ngnf_show_header *)msg->data, + (struct ngnf_show_header *)resp->data); + + if (error) + NG_FREE_MSG(resp); break; } Modified: head/sys/netgraph/netflow/ng_netflow.h ============================================================================== --- head/sys/netgraph/netflow/ng_netflow.h Tue Jul 5 14:12:48 2011 (r223786) +++ head/sys/netgraph/netflow/ng_netflow.h Tue Jul 5 14:48:39 2011 (r223787) @@ -33,7 +33,7 @@ #define _NG_NETFLOW_H_ #define NG_NETFLOW_NODE_TYPE "netflow" -#define NGM_NETFLOW_COOKIE 1299079728 +#define NGM_NETFLOW_COOKIE 1309868867 #define NG_NETFLOW_MAXIFACES USHRT_MAX @@ -133,6 +133,19 @@ struct ng_netflow_setmtu { uint16_t mtu; /* MTU for packet */ }; +/* This structure is used in NGM_NETFLOW_SHOW request/responce */ +struct ngnf_show_header { + u_char version; /* IPv4 or IPv6 */ + uint32_t hash_id; /* current hash index */ + uint32_t list_id; /* current record number in given hash */ + uint32_t nentries; /* number of records in response */ +}; + +/* XXXGL + * Somewhere flow_rec6 is casted to flow_rec, and flow6_entry_data is + * casted to flow_entry_data. After casting, fle->r.fib is accessed. + * So beginning of these structs up to fib should be kept common. + */ /* This is unique data, which identifies flow */ struct flow_rec { @@ -233,29 +246,24 @@ struct flow6_entry_data { * without overflowing socket receive buffer */ #define NREC_AT_ONCE 1000 -#define NGRESP_SIZE (sizeof(struct ngnf_flows) + (NREC_AT_ONCE * \ +#define NREC6_AT_ONCE (NREC_AT_ONCE * sizeof(struct flow_entry_data) / \ + sizeof(struct flow6_entry_data)) +#define NGRESP_SIZE (sizeof(struct ngnf_show_header) + (NREC_AT_ONCE * \ sizeof(struct flow_entry_data))) #define SORCVBUF_SIZE (NGRESP_SIZE + 2 * sizeof(struct ng_mesg)) -/* This struct is returned to userland, when "show cache ip flow" */ -struct ngnf_flows { - uint32_t nentries; - uint32_t last; - struct flow_entry_data entries[0]; -}; - /* Everything below is for kernel */ #ifdef _KERNEL struct flow_entry { - struct flow_entry_data f; TAILQ_ENTRY(flow_entry) fle_hash; /* entries in hash slot */ + struct flow_entry_data f; }; struct flow6_entry { + TAILQ_ENTRY(flow_entry) fle_hash; /* entries in hash slot */ struct flow6_entry_data f; - TAILQ_ENTRY(flow6_entry) fle6_hash; /* entries in hash slot */ }; /* Parsing declarations */ @@ -402,7 +410,7 @@ struct netflow { /* IPv6 support */ #ifdef INET6 uma_zone_t zone6; - struct flow6_hash_entry *hash6; + struct flow_hash_entry *hash6; #endif /* Multiple FIB support */ fib_export_p fib_data[RT_NUMFIBS]; /* array of pointers to fib-specific data */ @@ -430,11 +438,6 @@ struct flow_hash_entry { TAILQ_HEAD(fhead, flow_entry) head; }; -struct flow6_hash_entry { - struct mtx mtx; - TAILQ_HEAD(f6head, flow6_entry) head; -}; - #define ERROUT(x) { error = (x); goto done; } #define MTAG_NETFLOW 1221656444 @@ -465,7 +468,7 @@ void ng_netflow_copyinfo(priv_p, struct timeout_t ng_netflow_expire; int ng_netflow_flow_add(priv_p, fib_export_p, struct ip *, caddr_t, uint8_t, uint8_t, unsigned int); int ng_netflow_flow6_add(priv_p, fib_export_p, struct ip6_hdr *, caddr_t , uint8_t, uint8_t, unsigned int); -int ng_netflow_flow_show(priv_p, uint32_t last, struct ng_mesg *); +int ng_netflow_flow_show(priv_p, struct ngnf_show_header *req, struct ngnf_show_header *resp); void ng_netflow_v9_cache_init(priv_p); void ng_netflow_v9_cache_flush(priv_p);