From c40e45b75eb76d79a05c7fa85c1fa9b5c728a12f Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Fri, 7 Oct 2016 15:10:20 +0200 Subject: Update to FreeBSD head 2016-08-23 Git mirror commit 9fe7c416e6abb28b1398fd3e5687099846800cfd. --- freebsd/sys/kern/uipc_mbufhash.c | 176 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 freebsd/sys/kern/uipc_mbufhash.c (limited to 'freebsd/sys/kern/uipc_mbufhash.c') diff --git a/freebsd/sys/kern/uipc_mbufhash.c b/freebsd/sys/kern/uipc_mbufhash.c new file mode 100644 index 00000000..804510e0 --- /dev/null +++ b/freebsd/sys/kern/uipc_mbufhash.c @@ -0,0 +1,176 @@ +#include + +/* $OpenBSD: if_trunk.c,v 1.30 2007/01/31 06:20:19 reyk Exp $ */ + +/* + * Copyright (c) 2005, 2006 Reyk Floeter + * Copyright (c) 2007 Andrew Thompson + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include + +#include +#include +#include + +#include + +#if defined(INET) || defined(INET6) +#include +#endif + +#ifdef INET +#include +#endif + +#ifdef INET6 +#include +#endif + +static const void * +m_ether_tcpip_hash_gethdr(const struct mbuf *m, const u_int off, + const u_int len, void *buf) +{ + + if (m->m_pkthdr.len < (off + len)) { + return (NULL); + } else if (m->m_len < (off + len)) { + m_copydata(m, off, len, buf); + return (buf); + } + return (mtod(m, char *) + off); +} + +uint32_t +m_ether_tcpip_hash_init(void) +{ + uint32_t seed; + + seed = arc4random(); + return (fnv_32_buf(&seed, sizeof(seed), FNV1_32_INIT)); +} + +uint32_t +m_ether_tcpip_hash(const uint32_t flags, const struct mbuf *m, + const uint32_t key) +{ + union { +#ifdef INET + struct ip ip; +#endif +#ifdef INET6 + struct ip6_hdr ip6; +#endif + struct ether_vlan_header vlan; + uint32_t port; + } buf; + struct ether_header *eh; + const struct ether_vlan_header *vlan; +#ifdef INET + const struct ip *ip; +#endif +#ifdef INET6 + const struct ip6_hdr *ip6; +#endif + uint32_t p; + int off; + uint16_t etype; + + p = key; + off = sizeof(*eh); + if (m->m_len < off) + goto done; + eh = mtod(m, struct ether_header *); + etype = ntohs(eh->ether_type); + if (flags & MBUF_HASHFLAG_L2) { + p = fnv_32_buf(&eh->ether_shost, ETHER_ADDR_LEN, p); + p = fnv_32_buf(&eh->ether_dhost, ETHER_ADDR_LEN, p); + } + /* Special handling for encapsulating VLAN frames */ + if ((m->m_flags & M_VLANTAG) && (flags & MBUF_HASHFLAG_L2)) { + p = fnv_32_buf(&m->m_pkthdr.ether_vtag, + sizeof(m->m_pkthdr.ether_vtag), p); + } else if (etype == ETHERTYPE_VLAN) { + vlan = m_ether_tcpip_hash_gethdr(m, off, sizeof(*vlan), &buf); + if (vlan == NULL) + goto done; + + if (flags & MBUF_HASHFLAG_L2) + p = fnv_32_buf(&vlan->evl_tag, sizeof(vlan->evl_tag), p); + etype = ntohs(vlan->evl_proto); + off += sizeof(*vlan) - sizeof(*eh); + } + switch (etype) { +#ifdef INET + case ETHERTYPE_IP: + ip = m_ether_tcpip_hash_gethdr(m, off, sizeof(*ip), &buf); + if (ip == NULL) + break; + if (flags & MBUF_HASHFLAG_L3) { + p = fnv_32_buf(&ip->ip_src, sizeof(struct in_addr), p); + p = fnv_32_buf(&ip->ip_dst, sizeof(struct in_addr), p); + } + if (flags & MBUF_HASHFLAG_L4) { + const uint32_t *ports; + int iphlen; + + switch (ip->ip_p) { + case IPPROTO_TCP: + case IPPROTO_UDP: + case IPPROTO_SCTP: + iphlen = ip->ip_hl << 2; + if (iphlen < sizeof(*ip)) + break; + off += iphlen; + ports = m_ether_tcpip_hash_gethdr(m, + off, sizeof(*ports), &buf); + if (ports == NULL) + break; + p = fnv_32_buf(ports, sizeof(*ports), p); + break; + default: + break; + } + } + break; +#endif +#ifdef INET6 + case ETHERTYPE_IPV6: + ip6 = m_ether_tcpip_hash_gethdr(m, off, sizeof(*ip6), &buf); + if (ip6 == NULL) + break; + if (flags & MBUF_HASHFLAG_L3) { + p = fnv_32_buf(&ip6->ip6_src, sizeof(struct in6_addr), p); + p = fnv_32_buf(&ip6->ip6_dst, sizeof(struct in6_addr), p); + } + if (flags & MBUF_HASHFLAG_L4) { + uint32_t flow; + + /* IPv6 flow label */ + flow = ip6->ip6_flow & IPV6_FLOWLABEL_MASK; + p = fnv_32_buf(&flow, sizeof(flow), p); + } + break; +#endif + default: + break; + } +done: + return (p); +} -- cgit v1.2.3