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
This commit is contained in:
parent
0bd6bb6bb0
commit
36374fcf4b
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=237227
@ -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
|
||||
|
@ -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 ((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->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;
|
||||
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);
|
||||
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;
|
||||
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);
|
||||
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;
|
||||
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);
|
||||
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 (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->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 (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);
|
||||
|
||||
|
@ -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 @@ ng_netflow_rcvdata (hook_p hook, item_p item)
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user