FreeBSD/sys/netgraph/netflow/netflow.c
/* Insert packet from into flow cache. */
Insert packet from into flow cache.
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 flags,
    unsigned int src_if_index)
{
	struct flow_entry	*fle, *fle1;
	struct flow_hash_entry	*hsh;
	struct flow_rec		r;
	int			hlen, plen;
	int			error = 0;
	uint16_t		eproto;
	uint8_t			tcp_flags = 0;
	bzero(&r, sizeof(r));
	if (ip->ip_v != IPVERSION)
		return (EINVAL);
	hlen = ip->ip_hl << 2;
	if (hlen < sizeof(struct ip))
		return (EINVAL);
	eproto = ETHERTYPE_IP;
	r.flow_type = NETFLOW_V9_FLOW_V4_L4;
	r.r_src = ip->ip_src;
	r.r_dst = ip->ip_dst;
	r.fib = fe->fib;
	plen = ntohs(ip->ip_len);
	r.r_ip_p = ip->ip_p;
	r.r_tos = ip->ip_tos;
	r.r_i_ifx = src_if_index;
	if ((ip->ip_off & htons(IP_OFFMASK)) == 0)
		switch(r.r_ip_p) {
		case IPPROTO_TCP:
		    {
			struct tcphdr *tcp;
			tcp = (struct tcphdr *)((caddr_t )ip + hlen);
			r.r_sport = tcp->th_sport;
			r.r_dport = tcp->th_dport;
			tcp_flags = tcp->th_flags;
			break;
		    }
		case IPPROTO_UDP:
			r.r_ports = *(uint32_t *)((caddr_t )ip + hlen);
			break;
		}
	counter_u64_add(priv->nfinfo_packets, 1);
	counter_u64_add(priv->nfinfo_bytes, plen);
	hsh = &priv->hash[ip_hash(&r)];
	mtx_lock(&hsh->mtx);
	TAILQ_FOREACH_REVERSE_SAFE(fle, &hsh->head, fhead, fle_hash, fle1) {
		if (bcmp(&r, &fle->f.r, sizeof(struct flow_rec)) == 0)
			break;
		if ((INACTIVE(fle) && SMALL(fle)) || AGED(fle)) {
			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) {			
		fle->f.bytes += plen;
		fle->f.packets ++;
		fle->f.tcp_flags |= tcp_flags;
		fle->f.last = time_uptime;
		if (tcp_flags & TH_FIN || tcp_flags & TH_RST || AGED(fle) ||
		    (fle->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 = hash_insert(priv, hsh, &r, plen, flags, tcp_flags);
	mtx_unlock(&hsh->mtx);
	return (error);
}
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 flags , unsigned int src_if_index ) { struct flow_entry * fle , * fle1 ; struct flow_hash_entry * hsh ; struct flow_rec r ; int hlen , plen ; int error = 0 ; uint16_t eproto ; uint8_t tcp_flags = 0 ; bzero ( & r , sizeof ( r ) ) ; if ( ip -> ip_v != IPVERSION ) return ( EINVAL ) ; hlen = ip -> ip_hl << 2 ; if ( hlen < sizeof ( struct ip ) ) return ( EINVAL ) ; eproto = ETHERTYPE_IP ; r . flow_type = NETFLOW_V9_FLOW_V4_L4 ; r . r_src = ip -> ip_src ; r . r_dst = ip -> ip_dst ; r . fib = fe -> fib ; plen = ntohs ( ip -> ip_len ) ; r . r_ip_p = ip -> ip_p ; r . r_tos = ip -> ip_tos ; r . r_i_ifx = src_if_index ; if ( ( ip -> ip_off & htons ( IP_OFFMASK ) ) == 0 ) switch ( r . r_ip_p ) { case IPPROTO_TCP : { struct tcphdr * tcp ; tcp = ( struct tcphdr * ) ( ( caddr_t ) ip + hlen ) ; r . r_sport = tcp -> th_sport ; r . r_dport = tcp -> th_dport ; tcp_flags = tcp -> th_flags ; break ; } case IPPROTO_UDP : r . r_ports = * ( uint32_t * ) ( ( caddr_t ) ip + hlen ) ; break ; } counter_u64_add ( priv -> nfinfo_packets , 1 ) ; counter_u64_add ( priv -> nfinfo_bytes , plen ) ; hsh = & priv -> hash [ ip_hash ( & r ) ] ; mtx_lock ( & hsh -> mtx ) ; TAILQ_FOREACH_REVERSE_SAFE ( fle , & hsh -> head , fhead , fle_hash , fle1 ) { if ( bcmp ( & r , & fle -> f . r , sizeof ( struct flow_rec ) ) == 0 ) break ; if ( ( INACTIVE ( fle ) && SMALL ( fle ) ) || AGED ( fle ) ) { 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 ) { fle -> f . bytes += plen ; fle -> f . packets ++ ; fle -> f . tcp_flags |= tcp_flags ; fle -> f . last = time_uptime ; if ( tcp_flags & TH_FIN || tcp_flags & TH_RST || AGED ( fle ) || ( fle -> 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 = hash_insert ( priv , hsh , & r , plen , flags , tcp_flags ) ; mtx_unlock ( & hsh -> mtx ) ; return ( error ) ; }
Insert packet from into flow cache.
Insert packet from into flow cache .
/* Assume L4 template by default */ /*
	 * XXX NOTE: only first fragment of fragmented TCP, UDP and
	 * ICMP packet will be recorded with proper s_port and d_port.
	 * Following fragments will be recorded simply as IP packet with
	 * ip_proto = ip->ip_p and s_port, d_port set to zero.
	 * I know, it looks like bug. But I don't want to re-implement
	 * ip packet assebmling here. Anyway, (in)famous trafd works this way -
	 * and nobody complains yet :)
	 */ /* 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. */