--- sys/netinet/ip_input.c.orig	2016-09-05 01:41:03.050600000 +0700
+++ sys/netinet/ip_input.c	2016-09-07 18:57:26.362171000 +0700
@@ -84,6 +84,11 @@ __FBSDID("$FreeBSD: stable/11/sys/netine
 #endif /* IPSEC */
 #include <netinet/in_rss.h>
 
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
+#include <netinet/sctp.h>
+#include <sys/hash.h>
+
 #include <sys/socketvar.h>
 
 #include <security/mac/mac_framework.h>
@@ -137,9 +142,18 @@ SYSCTL_INT(_net_inet_ip, OID_AUTO, check
 
 VNET_DEFINE(struct pfil_head, inet_pfil_hook);	/* Packet filter hooks */
 
+static VNET_DEFINE(int, skip_flowid_gen) = 0;
+SYSCTL_INT(_net_inet_ip, OID_AUTO, skip_flowid_gen, CTLFLAG_VNET | CTLFLAG_RW,
+    &VNET_NAME(skip_flowid_gen), 0,
+    "Disable flow id generation for input packets");
+
+static VNET_DEFINE(uint32_t, flow_hashjitter);
+#define	V_flow_hashjitter	VNET(flow_hashjitter)
+static struct mbuf * ip_hash_mbuf(struct mbuf *m, uintptr_t source);
 static struct netisr_handler ip_nh = {
 	.nh_name = "ip",
 	.nh_handler = ip_input,
+	.nh_m2flow = ip_hash_mbuf,
 	.nh_proto = NETISR_IP,
 #ifdef	RSS
 	.nh_m2cpuid = rss_soft_m2cpuid_v4,
@@ -311,6 +325,9 @@ ip_init(void)
 	/* Initialize IP reassembly queue. */
 	ipreass_init();
 
+	if (V_flow_hashjitter == 0)
+		V_flow_hashjitter = arc4random();
+
 	/* Initialize packet filter hooks. */
 	V_inet_pfil_hook.ph_type = PFIL_TYPE_AF;
 	V_inet_pfil_hook.ph_af = AF_INET;
@@ -436,6 +453,76 @@ ip_direct_input(struct mbuf *m)
 }
 #endif
 
+static struct mbuf *
+ip_hash_mbuf(struct mbuf *m, uintptr_t source)
+{
+	struct ip *ip;
+	uint8_t proto;
+	int iphlen, offset;
+	uint32_t key[3];
+	struct tcphdr *th;
+	struct udphdr *uh;
+	struct sctphdr *sh;
+	uint16_t sport = 0, dport = 0;
+	uint32_t flowid, pullup_len = 0;
+
+#define	M_CHECK(length)	do {					\
+	pullup_len += length;					\
+	if ((m)->m_pkthdr.len < (pullup_len))			\
+		return (m);					\
+	if ((m)->m_len < (pullup_len) &&			\
+	   (((m) = m_pullup((m),(pullup_len))) == NULL))	\
+		return NULL;					\
+} while (0)
+
+	if (skip_flowid_gen)
+		return m;
+
+	M_CHECK(sizeof(struct ip));
+	ip = mtod(m, struct ip *);
+
+	proto = ip->ip_p;
+	iphlen = ip->ip_hl << 2; /* XXX options? */
+
+	key[0] = 0;
+	key[1] = ip->ip_src.s_addr;
+	key[2] = ip->ip_dst.s_addr;
+
+	switch (proto) {
+	case IPPROTO_TCP:
+		M_CHECK(sizeof(struct tcphdr));
+		th = (struct tcphdr *)((caddr_t)ip + iphlen);
+		sport = th->th_sport;
+		dport = th->th_dport;
+	break;
+	case IPPROTO_UDP:
+		M_CHECK(sizeof(struct udphdr));
+		uh = (struct udphdr *)((caddr_t)ip + iphlen);
+		sport = uh->uh_sport;
+		dport = uh->uh_dport;
+	break;
+	case IPPROTO_SCTP:
+		M_CHECK(sizeof(struct sctphdr));
+		sh = (struct sctphdr *)((caddr_t)ip + iphlen);
+		sport = sh->src_port;
+		dport = sh->dest_port;
+	break;
+	}
+
+	if (sport > 0) {
+		((uint16_t *)key)[0] = sport;
+		((uint16_t *)key)[1] = dport;
+		offset = 0;
+	} else
+		offset = V_flow_hashjitter + proto;
+
+	flowid = jenkins_hash32(key, 3, offset);
+	m->m_pkthdr.flowid = flowid;
+	M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE);
+
+	return m;
+}
+
 /*
  * Ip input routine.  Checksum and byte swap header.  If fragmented
  * try to reassemble.  Process options.  Pass to next level.