diff options
author | melifaro <melifaro@FreeBSD.org> | 2012-06-18 13:56:36 +0000 |
---|---|---|
committer | melifaro <melifaro@FreeBSD.org> | 2012-06-18 13:56:36 +0000 |
commit | a0b36d5a0f0c40ddf24df49d87f4c3821a55df16 (patch) | |
tree | d964270b7ca705bda10cab664f2f95c517987ec8 | |
parent | 45df7964fe21fb200bbfa053a6f5367cd2dc9a22 (diff) | |
download | FreeBSD-src-a0b36d5a0f0c40ddf24df49d87f4c3821a55df16.zip FreeBSD-src-a0b36d5a0f0c40ddf24df49d87f4c3821a55df16.tar.gz |
Make radix lookup on src and dst flow addresses optional
and configurable on per-interface basis.
Remove __inline__ for several functions being called once per
flow (e.g once per 10-20 packets on common traffic flows).
Update manual page to simplify search for BPF data link types.
Sponsored by Yandex LLC
Reviewed by: glebius
Approved by: ae(mentor)
MFC after: 2 weeks
-rw-r--r-- | share/man/man4/ng_netflow.4 | 47 | ||||
-rw-r--r-- | sys/netgraph/netflow/netflow.c | 178 | ||||
-rw-r--r-- | sys/netgraph/netflow/ng_netflow.c | 13 | ||||
-rw-r--r-- | sys/netgraph/netflow/ng_netflow.h | 14 |
4 files changed, 151 insertions, 101 deletions
diff --git a/share/man/man4/ng_netflow.4 b/share/man/man4/ng_netflow.4 index 9431c62..5985c44 100644 --- a/share/man/man4/ng_netflow.4 +++ b/share/man/man4/ng_netflow.4 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd March 2, 2011 +.Dd June 16, 2012 .Dt NG_NETFLOW 4 .Os .Sh NAME @@ -112,7 +112,18 @@ The hook number is passed as an argument. Sets data link type on the .Va iface Ns Ar N hook. -Currently, supported types are raw IP datagrams and Ethernet. +Currently, supported types are +.Cm DLT_RAW +(raw IP datagrams) and +.Cm DLT_EN10MB +(Ethernet). +DLT_ definitions can be found in +.In net/bpf.h +header. +Currently used values are 1 for +.Cm DLT_EN10MB +and 12 for +.Cm DLT_RAW . This message type uses .Vt "struct ng_netflow_setdlt" as an argument: @@ -180,18 +191,36 @@ struct ng_netflow_setconfig { #define NG_NETFLOW_CONF_EGRESS 2 #define NG_NETFLOW_CONF_ONCE 4 #define NG_NETFLOW_CONF_THISONCE 8 +#define NG_NETFLOW_CONF_NOSRCLOOKUP 16 +#define NG_NETFLOW_CONF_NODSTLOOKUP 32 }; .Ed .Pp Configuration is a bitmask of several options. Option NG_NETFLOW_CONF_INGRESS enabled by default enables ingress NetFlow generation (for data coming from -ifaceX hook). Option NG_NETFLOW_CONF_EGRESS enables egress NetFlow (for data -coming from outX hook). Option NG_NETFLOW_CONF_ONCE defines that packet should -be accounted only once if it several times passes via netflow node. Option -NG_NETFLOW_CONF_THISONCE defines that packet should be accounted only once -if it several times passes via exactly this netflow node. Last two options are -important to avoid duplicate accounting when both ingress and egress NetFlow -are enabled. +ifaceX hook). +Option +.Va NG_NETFLOW_CONF_EGRESS +enables egress NetFlow (for data coming from outX hook). +Option +.Va NG_NETFLOW_CONF_ONCE +defines that packet should be accounted only once if it several times passes +via netflow node. +Option +.Va NG_NETFLOW_CONF_THISONCE +defines that packet should be accounted only once if it several times passes +via exactly this netflow node. +These two options are important to avoid duplicate accounting when both ingress +and egress NetFlow are enabled. +Option +.Va NG_NETFLOW_CONF_NOSRCLOOKUP +skips radix lookup on flow source address used to fill in network mask. +Option +.Va NG_NETFLOW_CONF_NODSTLOOKUP +skips radix lookup on destination (which fills egress interface id, destination +mask and gateway). +If one doesn't need data provided by lookups, he/she can disable them, to reduce +load on routers. .It Dv NGM_NETFLOW_SETTEMPLATE Sets various timeouts to announce data flow templates (NetFlow v9-specific). This message requires diff --git a/sys/netgraph/netflow/netflow.c b/sys/netgraph/netflow/netflow.c index c3443e5..2775756 100644 --- a/sys/netgraph/netflow/netflow.c +++ b/sys/netgraph/netflow/netflow.c @@ -98,9 +98,9 @@ MALLOC_DEFINE(M_NETFLOW_HASH, "netflow_hash", "NetFlow hash"); static int export_add(item_p, struct flow_entry *); 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); +static int hash_insert(priv_p, struct flow_hash_entry *, struct flow_rec *, int, uint8_t, uint8_t); #ifdef INET6 -static int hash6_insert(priv_p, struct flow_hash_entry *, struct flow6_rec *, int, uint8_t); +static int hash6_insert(priv_p, struct flow_hash_entry *, struct flow6_rec *, int, uint8_t, uint8_t); #endif static __inline void expire_flow(priv_p, fib_export_p, struct flow_entry *, int); @@ -325,9 +325,9 @@ ng_netflow_copyinfo(priv_p priv, struct ng_netflow_info *i) * as this was done in previous version. Need to test & profile * to be sure. */ -static __inline int +static int hash_insert(priv_p priv, struct flow_hash_entry *hsh, struct flow_rec *r, - int plen, uint8_t tcp_flags) + int plen, uint8_t flags, uint8_t tcp_flags) { struct flow_entry *fle; struct sockaddr_in sin; @@ -358,44 +358,48 @@ hash_insert(priv_p priv, struct flow_hash_entry *hsh, struct flow_rec *r, * First we do route table lookup on destination address. So we can * fill in out_ifx, dst_mask, nexthop, and dst_as in future releases. */ - bzero(&sin, sizeof(sin)); - sin.sin_len = sizeof(struct sockaddr_in); - sin.sin_family = AF_INET; - sin.sin_addr = fle->f.r.r_dst; - rt = rtalloc1_fib((struct sockaddr *)&sin, 0, 0, r->fib); - if (rt != NULL) { - fle->f.fle_o_ifx = rt->rt_ifp->if_index; - - if (rt->rt_flags & RTF_GATEWAY && - rt->rt_gateway->sa_family == AF_INET) - fle->f.next_hop = - ((struct sockaddr_in *)(rt->rt_gateway))->sin_addr; - - if (rt_mask(rt)) - fle->f.dst_mask = bitcount32(((struct sockaddr_in *) - rt_mask(rt))->sin_addr.s_addr); - else if (rt->rt_flags & RTF_HOST) - /* Give up. We can't determine mask :( */ - fle->f.dst_mask = 32; - - RTFREE_LOCKED(rt); + if ((flags & NG_NETFLOW_CONF_NODSTLOOKUP) == 0) { + bzero(&sin, sizeof(sin)); + sin.sin_len = sizeof(struct sockaddr_in); + sin.sin_family = AF_INET; + sin.sin_addr = fle->f.r.r_dst; + rt = rtalloc1_fib((struct sockaddr *)&sin, 0, 0, r->fib); + if (rt != NULL) { + fle->f.fle_o_ifx = rt->rt_ifp->if_index; + + if (rt->rt_flags & RTF_GATEWAY && + rt->rt_gateway->sa_family == AF_INET) + fle->f.next_hop = + ((struct sockaddr_in *)(rt->rt_gateway))->sin_addr; + + if (rt_mask(rt)) + fle->f.dst_mask = bitcount32(((struct sockaddr_in *) + rt_mask(rt))->sin_addr.s_addr); + else if (rt->rt_flags & RTF_HOST) + /* Give up. We can't determine mask :( */ + fle->f.dst_mask = 32; + + RTFREE_LOCKED(rt); + } } /* Do route lookup on source address, to fill in src_mask. */ - bzero(&sin, sizeof(sin)); - sin.sin_len = sizeof(struct sockaddr_in); - sin.sin_family = AF_INET; - sin.sin_addr = fle->f.r.r_src; - rt = rtalloc1_fib((struct sockaddr *)&sin, 0, 0, r->fib); - if (rt != NULL) { - if (rt_mask(rt)) - fle->f.src_mask = bitcount32(((struct sockaddr_in *) - rt_mask(rt))->sin_addr.s_addr); - else if (rt->rt_flags & RTF_HOST) - /* Give up. We can't determine mask :( */ - fle->f.src_mask = 32; - - RTFREE_LOCKED(rt); + if ((flags & NG_NETFLOW_CONF_NOSRCLOOKUP) == 0) { + bzero(&sin, sizeof(sin)); + sin.sin_len = sizeof(struct sockaddr_in); + sin.sin_family = AF_INET; + sin.sin_addr = fle->f.r.r_src; + rt = rtalloc1_fib((struct sockaddr *)&sin, 0, 0, r->fib); + if (rt != NULL) { + if (rt_mask(rt)) + fle->f.src_mask = bitcount32(((struct sockaddr_in *) + rt_mask(rt))->sin_addr.s_addr); + else if (rt->rt_flags & RTF_HOST) + /* Give up. We can't determine mask :( */ + fle->f.src_mask = 32; + + RTFREE_LOCKED(rt); + } } /* Push new flow at the and of hash. */ @@ -410,10 +414,10 @@ hash_insert(priv_p priv, struct flow_hash_entry *hsh, struct flow_rec *r, bitcount32((x).__u6_addr.__u6_addr32[1]) + \ bitcount32((x).__u6_addr.__u6_addr32[2]) + \ bitcount32((x).__u6_addr.__u6_addr32[3]) -/* XXX: Do we need inline here ? */ -static __inline int +#define RT_MASK6(x) (ipv6_masklen(((struct sockaddr_in6 *)rt_mask(x))->sin6_addr)) +static int hash6_insert(priv_p priv, struct flow_hash_entry *hsh6, struct flow6_rec *r, - int plen, uint8_t tcp_flags) + int plen, uint8_t flags, uint8_t tcp_flags) { struct flow6_entry *fle6; struct sockaddr_in6 *src, *dst; @@ -445,49 +449,55 @@ hash6_insert(priv_p priv, struct flow_hash_entry *hsh6, struct flow6_rec *r, * First we do route table lookup on destination address. So we can * fill in out_ifx, dst_mask, nexthop, and dst_as in future releases. */ - bzero(&rin6, sizeof(struct route_in6)); - dst = (struct sockaddr_in6 *)&rin6.ro_dst; - dst->sin6_len = sizeof(struct sockaddr_in6); - dst->sin6_family = AF_INET6; - dst->sin6_addr = r->dst.r_dst6; - - rin6.ro_rt = rtalloc1_fib((struct sockaddr *)dst, 0, 0, r->fib); - - if (rin6.ro_rt != NULL) { - rt = rin6.ro_rt; - fle6->f.fle_o_ifx = rt->rt_ifp->if_index; - - if (rt->rt_flags & RTF_GATEWAY && - rt->rt_gateway->sa_family == AF_INET6) - fle6->f.n.next_hop6 = - ((struct sockaddr_in6 *)(rt->rt_gateway))->sin6_addr; - - if (rt_mask(rt)) - fle6->f.dst_mask = ipv6_masklen(((struct sockaddr_in6 *)rt_mask(rt))->sin6_addr); - else - fle6->f.dst_mask = 128; + if ((flags & NG_NETFLOW_CONF_NODSTLOOKUP) == 0) + { + bzero(&rin6, sizeof(struct route_in6)); + dst = (struct sockaddr_in6 *)&rin6.ro_dst; + dst->sin6_len = sizeof(struct sockaddr_in6); + dst->sin6_family = AF_INET6; + dst->sin6_addr = r->dst.r_dst6; + + rin6.ro_rt = rtalloc1_fib((struct sockaddr *)dst, 0, 0, r->fib); + + if (rin6.ro_rt != NULL) { + rt = rin6.ro_rt; + fle6->f.fle_o_ifx = rt->rt_ifp->if_index; + + if (rt->rt_flags & RTF_GATEWAY && + rt->rt_gateway->sa_family == AF_INET6) + fle6->f.n.next_hop6 = + ((struct sockaddr_in6 *)(rt->rt_gateway))->sin6_addr; + + if (rt_mask(rt)) + fle6->f.dst_mask = RT_MASK6(rt); + else + fle6->f.dst_mask = 128; - RTFREE_LOCKED(rt); + RTFREE_LOCKED(rt); + } } - /* Do route lookup on source address, to fill in src_mask. */ - bzero(&rin6, sizeof(struct route_in6)); - src = (struct sockaddr_in6 *)&rin6.ro_dst; - src->sin6_len = sizeof(struct sockaddr_in6); - src->sin6_family = AF_INET6; - src->sin6_addr = r->src.r_src6; + if ((flags & NG_NETFLOW_CONF_NODSTLOOKUP) == 0) + { + /* Do route lookup on source address, to fill in src_mask. */ + bzero(&rin6, sizeof(struct route_in6)); + src = (struct sockaddr_in6 *)&rin6.ro_dst; + src->sin6_len = sizeof(struct sockaddr_in6); + src->sin6_family = AF_INET6; + src->sin6_addr = r->src.r_src6; - rin6.ro_rt = rtalloc1_fib((struct sockaddr *)src, 0, 0, r->fib); + rin6.ro_rt = rtalloc1_fib((struct sockaddr *)src, 0, 0, r->fib); - if (rin6.ro_rt != NULL) { - rt = rin6.ro_rt; + if (rin6.ro_rt != NULL) { + rt = rin6.ro_rt; - if (rt_mask(rt)) - fle6->f.src_mask = ipv6_masklen(((struct sockaddr_in6 *)rt_mask(rt))->sin6_addr); - else - fle6->f.src_mask = 128; + if (rt_mask(rt)) + fle6->f.src_mask = RT_MASK6(rt); + else + fle6->f.src_mask = 128; - RTFREE_LOCKED(rt); + RTFREE_LOCKED(rt); + } } /* Push new flow at the and of hash. */ @@ -495,6 +505,8 @@ hash6_insert(priv_p priv, struct flow_hash_entry *hsh6, struct flow6_rec *r, return (0); } +#undef ipv6_masklen +#undef RT_MASK6 #endif @@ -651,7 +663,7 @@ ng_netflow_cache_flush(priv_p priv) /* Insert packet from into flow cache. */ int ng_netflow_flow_add(priv_p priv, fib_export_p fe, struct ip *ip, caddr_t upper_ptr, uint8_t upper_proto, - uint8_t is_frag, unsigned int src_if_index) + uint8_t flags, unsigned int src_if_index) { register struct flow_entry *fle, *fle1; struct flow_hash_entry *hsh; @@ -770,7 +782,7 @@ ng_netflow_flow_add(priv_p priv, fib_export_p fe, struct ip *ip, caddr_t upper_p } } } else /* A new flow entry. */ - error = hash_insert(priv, hsh, &r, plen, tcp_flags); + error = hash_insert(priv, hsh, &r, plen, flags, tcp_flags); mtx_unlock(&hsh->mtx); @@ -781,7 +793,7 @@ ng_netflow_flow_add(priv_p priv, fib_export_p fe, struct ip *ip, caddr_t upper_p /* Insert IPv6 packet from into flow cache. */ 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) + uint8_t flags, unsigned int src_if_index) { register struct flow_entry *fle = NULL, *fle1; register struct flow6_entry *fle6; @@ -811,7 +823,7 @@ ng_netflow_flow6_add(priv_p priv, fib_export_p fe, struct ip6_hdr *ip6, caddr_t #if 0 r.r_tos = ip->ip_tos; #endif - if (is_frag == 0) { + if ((flags & NG_NETFLOW_IS_FRAG) == 0) { switch(upper_proto) { case IPPROTO_TCP: { @@ -896,7 +908,7 @@ ng_netflow_flow6_add(priv_p priv, fib_export_p fe, struct ip6_hdr *ip6, caddr_t } } } else /* A new flow entry. */ - error = hash6_insert(priv, hsh, &r, plen, tcp_flags); + error = hash6_insert(priv, hsh, &r, plen, flags, tcp_flags); mtx_unlock(&hsh->mtx); diff --git a/sys/netgraph/netflow/ng_netflow.c b/sys/netgraph/netflow/ng_netflow.c index 6e6589e..1cb6179 100644 --- a/sys/netgraph/netflow/ng_netflow.c +++ b/sys/netgraph/netflow/ng_netflow.c @@ -560,7 +560,7 @@ ng_netflow_rcvdata (hook_p hook, item_p item) struct ip6_hdr *ip6 = NULL; struct m_tag *mtag; int pullup_len = 0, off; - uint8_t acct = 0, bypass = 0, is_frag = 0, upper_proto = 0; + uint8_t acct = 0, bypass = 0, flags = 0, upper_proto = 0; int error = 0, l3_off = 0; unsigned int src_if_index; caddr_t upper_ptr = NULL; @@ -619,6 +619,9 @@ ng_netflow_rcvdata (hook_p hook, item_p item) } } + /* Import configuration flags related to flow creation */ + flags = iface->info.conf & NG_NETFLOW_FLOW_FLAGS; + NGI_GET_M(item, m); m_old = m; @@ -759,7 +762,7 @@ ng_netflow_rcvdata (hook_p hook, item_p item) } } else if (ip != NULL) { /* Nothing to save except upper layer proto, since this is packet fragment */ - is_frag = 1; + flags |= NG_NETFLOW_IS_FRAG; upper_proto = ip->ip_p; if ((ip->ip_v != IPVERSION) || ((ip->ip_hl << 2) < sizeof(struct ip))) @@ -821,7 +824,7 @@ ng_netflow_rcvdata (hook_p hook, item_p item) upper_proto = ip6f->ip6f_nxt; hdr_off = sizeof(struct ip6_frag); off += hdr_off; - is_frag = 1; + flags |= NG_NETFLOW_IS_FRAG; goto loopend; #if 0 @@ -886,10 +889,10 @@ loopend: } if (ip != NULL) - error = ng_netflow_flow_add(priv, fe, ip, upper_ptr, upper_proto, is_frag, src_if_index); + error = ng_netflow_flow_add(priv, fe, ip, upper_ptr, upper_proto, flags, src_if_index); #ifdef INET6 else if (ip6 != NULL) - error = ng_netflow_flow6_add(priv, fe, ip6, upper_ptr, upper_proto, is_frag, src_if_index); + error = ng_netflow_flow6_add(priv, fe, ip6, upper_ptr, upper_proto, flags, src_if_index); #endif else goto bypass; diff --git a/sys/netgraph/netflow/ng_netflow.h b/sys/netgraph/netflow/ng_netflow.h index bab04c7..ee56c28 100644 --- a/sys/netgraph/netflow/ng_netflow.h +++ b/sys/netgraph/netflow/ng_netflow.h @@ -111,10 +111,16 @@ struct ng_netflow_settimeouts { uint32_t active_timeout; /* flow active timeout */ }; -#define NG_NETFLOW_CONF_INGRESS 1 -#define NG_NETFLOW_CONF_EGRESS 2 -#define NG_NETFLOW_CONF_ONCE 4 -#define NG_NETFLOW_CONF_THISONCE 8 +#define NG_NETFLOW_CONF_INGRESS 0x01 /* Account on ingress */ +#define NG_NETFLOW_CONF_EGRESS 0x02 /* Account on egress */ +#define NG_NETFLOW_CONF_ONCE 0x04 /* Add tag to account only once */ +#define NG_NETFLOW_CONF_THISONCE 0x08 /* Account once in current node */ +#define NG_NETFLOW_CONF_NOSRCLOOKUP 0x10 /* No radix lookup on src */ +#define NG_NETFLOW_CONF_NODSTLOOKUP 0x20 /* No radix lookup on dst */ + +#define NG_NETFLOW_IS_FRAG 0x01 +#define NG_NETFLOW_FLOW_FLAGS (NG_NETFLOW_CONF_NOSRCLOOKUP|\ + NG_NETFLOW_CONF_NODSTLOOKUP) /* This structure is passed to NGM_NETFLOW_SETCONFIG */ struct ng_netflow_setconfig { |