1 /* $OpenBSD: if_trunk.c,v 1.30 2007/01/31 06:20:19 reyk Exp $ */ 2 3 /* 4 * Copyright (c) 2005, 2006 Reyk Floeter <reyk@openbsd.org> 5 * Copyright (c) 2007 Andrew Thompson <thompsa@FreeBSD.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/cdefs.h> 21 __FBSDID("$FreeBSD$"); 22 23 #include "opt_inet.h" 24 #include "opt_inet6.h" 25 26 #include <sys/param.h> 27 #include <sys/mbuf.h> 28 #include <sys/fnv_hash.h> 29 30 #include <net/ethernet.h> 31 #include <net/infiniband.h> 32 33 #if defined(INET) || defined(INET6) 34 #include <netinet/in.h> 35 #endif 36 37 #ifdef INET 38 #include <netinet/ip.h> 39 #endif 40 41 #ifdef INET6 42 #include <netinet/ip6.h> 43 #endif 44 45 static const void * 46 m_common_hash_gethdr(const struct mbuf *m, const u_int off, 47 const u_int len, void *buf) 48 { 49 50 if (m->m_pkthdr.len < (off + len)) { 51 return (NULL); 52 } else if (m->m_len < (off + len)) { 53 m_copydata(m, off, len, buf); 54 return (buf); 55 } 56 return (mtod(m, char *) + off); 57 } 58 59 uint32_t 60 m_ether_tcpip_hash_init(void) 61 { 62 uint32_t seed; 63 64 seed = arc4random(); 65 return (fnv_32_buf(&seed, sizeof(seed), FNV1_32_INIT)); 66 } 67 68 uint32_t 69 m_infiniband_tcpip_hash_init(void) 70 { 71 uint32_t seed; 72 73 seed = arc4random(); 74 return (fnv_32_buf(&seed, sizeof(seed), FNV1_32_INIT)); 75 } 76 77 static inline uint32_t 78 m_tcpip_hash(const uint32_t flags, const struct mbuf *m, 79 uint32_t p, int off, const uint16_t etype) 80 { 81 #if defined(INET) || defined(INET6) 82 union { 83 #ifdef INET 84 struct ip ip; 85 #endif 86 #ifdef INET6 87 struct ip6_hdr ip6; 88 #endif 89 uint32_t port; 90 } buf; 91 #ifdef INET 92 const struct ip *ip; 93 #endif 94 #ifdef INET6 95 const struct ip6_hdr *ip6; 96 #endif 97 #endif 98 switch (etype) { 99 #ifdef INET 100 case ETHERTYPE_IP: 101 ip = m_common_hash_gethdr(m, off, sizeof(*ip), &buf); 102 if (ip == NULL) 103 break; 104 if (flags & MBUF_HASHFLAG_L3) { 105 p = fnv_32_buf(&ip->ip_src, sizeof(struct in_addr), p); 106 p = fnv_32_buf(&ip->ip_dst, sizeof(struct in_addr), p); 107 } 108 if (flags & MBUF_HASHFLAG_L4) { 109 const uint32_t *ports; 110 int iphlen; 111 112 switch (ip->ip_p) { 113 case IPPROTO_TCP: 114 case IPPROTO_UDP: 115 case IPPROTO_SCTP: 116 iphlen = ip->ip_hl << 2; 117 if (iphlen < sizeof(*ip)) 118 break; 119 off += iphlen; 120 ports = m_common_hash_gethdr(m, 121 off, sizeof(*ports), &buf); 122 if (ports == NULL) 123 break; 124 p = fnv_32_buf(ports, sizeof(*ports), p); 125 break; 126 default: 127 break; 128 } 129 } 130 break; 131 #endif 132 #ifdef INET6 133 case ETHERTYPE_IPV6: 134 ip6 = m_common_hash_gethdr(m, off, sizeof(*ip6), &buf); 135 if (ip6 == NULL) 136 break; 137 if (flags & MBUF_HASHFLAG_L3) { 138 p = fnv_32_buf(&ip6->ip6_src, sizeof(struct in6_addr), p); 139 p = fnv_32_buf(&ip6->ip6_dst, sizeof(struct in6_addr), p); 140 } 141 if (flags & MBUF_HASHFLAG_L4) { 142 uint32_t flow; 143 144 /* IPv6 flow label */ 145 flow = ip6->ip6_flow & IPV6_FLOWLABEL_MASK; 146 p = fnv_32_buf(&flow, sizeof(flow), p); 147 } 148 break; 149 #endif 150 default: 151 break; 152 } 153 return (p); 154 } 155 156 uint32_t 157 m_ether_tcpip_hash(const uint32_t flags, const struct mbuf *m, 158 uint32_t p) 159 { 160 union { 161 struct ether_vlan_header vlan; 162 } buf; 163 const struct ether_header *eh; 164 const struct ether_vlan_header *vlan; 165 int off; 166 uint16_t etype; 167 168 off = sizeof(*eh); 169 if (m->m_len < off) 170 return (p); 171 eh = mtod(m, struct ether_header *); 172 etype = ntohs(eh->ether_type); 173 if (flags & MBUF_HASHFLAG_L2) { 174 p = fnv_32_buf(&eh->ether_shost, ETHER_ADDR_LEN, p); 175 p = fnv_32_buf(&eh->ether_dhost, ETHER_ADDR_LEN, p); 176 } 177 /* Special handling for encapsulating VLAN frames */ 178 if ((m->m_flags & M_VLANTAG) && (flags & MBUF_HASHFLAG_L2)) { 179 p = fnv_32_buf(&m->m_pkthdr.ether_vtag, 180 sizeof(m->m_pkthdr.ether_vtag), p); 181 } else if (etype == ETHERTYPE_VLAN) { 182 vlan = m_common_hash_gethdr(m, off, sizeof(*vlan), &buf); 183 if (vlan == NULL) 184 return (p); 185 186 if (flags & MBUF_HASHFLAG_L2) 187 p = fnv_32_buf(&vlan->evl_tag, sizeof(vlan->evl_tag), p); 188 etype = ntohs(vlan->evl_proto); 189 off += sizeof(*vlan) - sizeof(*eh); 190 } 191 return (m_tcpip_hash(flags, m, p, off, etype)); 192 } 193 194 uint32_t 195 m_infiniband_tcpip_hash(const uint32_t flags, const struct mbuf *m, 196 uint32_t p) 197 { 198 const struct infiniband_header *ibh; 199 int off; 200 uint16_t etype; 201 202 off = sizeof(*ibh); 203 if (m->m_len < off) 204 return (p); 205 ibh = mtod(m, struct infiniband_header *); 206 etype = ntohs(ibh->ib_protocol); 207 if (flags & MBUF_HASHFLAG_L2) 208 p = fnv_32_buf(&ibh->ib_hwaddr, INFINIBAND_ADDR_LEN, p); 209 210 return (m_tcpip_hash(flags, m, p, off, etype)); 211 } 212