FreeBSD/sys/netgraph/netflow/netflow.c
/* Insert IPv6 packet from into flow cache. */
Insert IPv6 packet from into flow cache.
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 flags,
    unsigned int src_if_index)
{
	struct flow_entry	*fle = NULL, *fle1;
	struct flow6_entry	*fle6;
	struct flow_hash_entry	*hsh;
	struct flow6_rec	r;
	int			plen;
	int			error = 0;
	uint8_t			tcp_flags = 0;
	if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION)
		return (EINVAL);
	bzero(&r, sizeof(r));
	r.src.r_src6 = ip6->ip6_src;
	r.dst.r_dst6 = ip6->ip6_dst;
	r.fib = fe->fib;
	r.flow_type = NETFLOW_V9_FLOW_V6_L4;
	plen = ntohs(ip6->ip6_plen) + sizeof(struct ip6_hdr);
#if 0
	r.r_tos = ip->ip_tos;
#endif
	if ((flags & NG_NETFLOW_IS_FRAG) == 0) {
		switch(upper_proto) {
		case IPPROTO_TCP:
		    {
			struct tcphdr *tcp;
			tcp = (struct tcphdr *)upper_ptr;
			r.r_ports = *(uint32_t *)upper_ptr;
			tcp_flags = tcp->th_flags;
			break;
		    }
 		case IPPROTO_UDP:
		case IPPROTO_SCTP:
			r.r_ports = *(uint32_t *)upper_ptr;
			break;
		}
	}	
	r.r_ip_p = upper_proto;
	r.r_i_ifx = src_if_index;
	counter_u64_add(priv->nfinfo_packets6, 1);
	counter_u64_add(priv->nfinfo_bytes6, plen);
	hsh = &priv->hash6[ip6_hash(&r)];
	mtx_lock(&hsh->mtx);
	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(&hsh->head, fle, fle_hash);
			expire_flow(priv, priv_to_fib(priv, fle->f.r.fib), fle,
			    NG_QUEUE);
			counter_u64_add(priv->nfinfo_act_exp, 1);
		}
	}
	if (fle != NULL) {			
		fle6 = (struct flow6_entry *)fle;
		fle6->f.bytes += plen;
		fle6->f.packets ++;
		fle6->f.tcp_flags |= tcp_flags;
		fle6->f.last = time_uptime;
		if (tcp_flags & TH_FIN || tcp_flags & TH_RST || AGED(fle6) ||
		    (fle6->f.bytes >= (CNTR_MAX - IF_MAXMTU)) ) {
			TAILQ_REMOVE(&hsh->head, fle, fle_hash);
			expire_flow(priv, priv_to_fib(priv, fle->f.r.fib), fle,
			    NG_QUEUE);
			counter_u64_add(priv->nfinfo_act_exp, 1);
		} else {
			if (fle != TAILQ_LAST(&hsh->head, fhead)) {
				TAILQ_REMOVE(&hsh->head, fle, fle_hash);
				TAILQ_INSERT_TAIL(&hsh->head, fle, fle_hash);
			}
		}
	} else				
		error = hash6_insert(priv, hsh, &r, plen, flags, tcp_flags);
	mtx_unlock(&hsh->mtx);
	return (error);
}
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 flags , unsigned int src_if_index ) { struct flow_entry * fle = NULL , * fle1 ; struct flow6_entry * fle6 ; struct flow_hash_entry * hsh ; struct flow6_rec r ; int plen ; int error = 0 ; uint8_t tcp_flags = 0 ; if ( ( ip6 -> ip6_vfc & IPV6_VERSION_MASK ) != IPV6_VERSION ) return ( EINVAL ) ; bzero ( & r , sizeof ( r ) ) ; r . src . r_src6 = ip6 -> ip6_src ; r . dst . r_dst6 = ip6 -> ip6_dst ; r . fib = fe -> fib ; r . flow_type = NETFLOW_V9_FLOW_V6_L4 ; plen = ntohs ( ip6 -> ip6_plen ) + sizeof ( struct ip6_hdr ) ; #if 0 r . r_tos = ip -> ip_tos ; #endif if ( ( flags & NG_NETFLOW_IS_FRAG ) == 0 ) { switch ( upper_proto ) { case IPPROTO_TCP : { struct tcphdr * tcp ; tcp = ( struct tcphdr * ) upper_ptr ; r . r_ports = * ( uint32_t * ) upper_ptr ; tcp_flags = tcp -> th_flags ; break ; } case IPPROTO_UDP : case IPPROTO_SCTP : r . r_ports = * ( uint32_t * ) upper_ptr ; break ; } } r . r_ip_p = upper_proto ; r . r_i_ifx = src_if_index ; counter_u64_add ( priv -> nfinfo_packets6 , 1 ) ; counter_u64_add ( priv -> nfinfo_bytes6 , plen ) ; hsh = & priv -> hash6 [ ip6_hash ( & r ) ] ; mtx_lock ( & hsh -> mtx ) ; 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 ( & hsh -> head , fle , fle_hash ) ; expire_flow ( priv , priv_to_fib ( priv , fle -> f . r . fib ) , fle , NG_QUEUE ) ; counter_u64_add ( priv -> nfinfo_act_exp , 1 ) ; } } if ( fle != NULL ) { fle6 = ( struct flow6_entry * ) fle ; fle6 -> f . bytes += plen ; fle6 -> f . packets ++ ; fle6 -> f . tcp_flags |= tcp_flags ; fle6 -> f . last = time_uptime ; if ( tcp_flags & TH_FIN || tcp_flags & TH_RST || AGED ( fle6 ) || ( fle6 -> f . bytes >= ( CNTR_MAX - IF_MAXMTU ) ) ) { TAILQ_REMOVE ( & hsh -> head , fle , fle_hash ) ; expire_flow ( priv , priv_to_fib ( priv , fle -> f . r . fib ) , fle , NG_QUEUE ) ; counter_u64_add ( priv -> nfinfo_act_exp , 1 ) ; } else { if ( fle != TAILQ_LAST ( & hsh -> head , fhead ) ) { TAILQ_REMOVE ( & hsh -> head , fle , fle_hash ) ; TAILQ_INSERT_TAIL ( & hsh -> head , fle , fle_hash ) ; } } } else error = hash6_insert ( priv , hsh , & r , plen , flags , tcp_flags ) ; mtx_unlock ( & hsh -> mtx ) ; return ( error ) ; }
Insert IPv6 packet from into flow cache.
Insert IPv6 packet from into flow cache .
/* check version */ /* Assume L4 template by default */ /* XXX: set DSCP/CoS value */ /* Find hash slot. */ /*
	 * Go through hash and find our entry. If we encounter an
	 * entry, that should be expired, purge it. We do a reverse
	 * search since most active entries are first, and most
	 * searches are done on most active entries.
	 */ /* An existent entry. */ /*
		 * We have the following reasons to expire flow in active way:
		 * - it hit active timeout
		 * - a TCP connection closed
		 * - it is going to overflow counter
		 */ /*
			 * It is the newest, move it to the tail,
			 * if it isn't there already. Next search will
			 * locate it quicker.
			 */ /* A new flow entry. */