Index: sys/netinet/ip_input.c =================================================================== --- sys/netinet/ip_input.c (revision 230910) +++ sys/netinet/ip_input.c (working copy) @@ -78,6 +78,11 @@ __FBSDID("$FreeBSD$"); #include #endif /* IPSEC */ +#include +#include +#include +#include + #include #include @@ -145,9 +150,13 @@ SYSCTL_VNET_INT(_net_inet_ip, OID_AUTO, check_inte VNET_DEFINE(struct pfil_head, inet_pfil_hook); /* Packet filter hooks */ +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, .nh_policy = NETISR_POLICY_FLOW, }; @@ -305,6 +314,9 @@ ip_init(void) NULL, UMA_ALIGN_PTR, 0); maxnipq_update(); + 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; @@ -390,6 +402,73 @@ ip_fini(void *xtp) callout_stop(&ipport_tick_callout); } +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) + + 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_hashword(key, 3, offset); + m->m_flags |= M_FLOWID; + m->m_pkthdr.flowid = flowid; + + return m; +} + /* * Ip input routine. Checksum and byte swap header. If fragmented * try to reassemble. Process options. Pass to next level.