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/kernel.h> 28#include <sys/malloc.h> 29#include <sys/mbuf.h> 30#include <sys/queue.h> 31#include <sys/socket.h> 32#include <sys/sockio.h> 33#include <sys/sysctl.h> 34#include <sys/module.h> 35#include <sys/priv.h> 36#include <sys/systm.h> 37#include <sys/proc.h> 38#include <sys/hash.h> 39#include <sys/lock.h> 40#include <sys/rmlock.h> 41#include <sys/taskqueue.h> 42#include <sys/eventhandler.h> 43 44#include <net/ethernet.h> 45#include <net/if.h> 46#include <net/if_clone.h> 47#include <net/if_arp.h> 48#include <net/if_dl.h> 49#include <net/if_llc.h> 50#include <net/if_media.h> 51#include <net/if_types.h> 52#include <net/if_var.h> 53#include <net/bpf.h> 54 55#if defined(INET) || defined(INET6) 56#include <netinet/in.h> 57#endif 58#ifdef INET 59#include <netinet/in_systm.h> 60#include <netinet/if_ether.h> 61#include <netinet/ip.h> 62#endif 63 64#ifdef INET6 65#include <netinet/ip6.h> 66#include <netinet6/in6_var.h> 67#include <netinet6/in6_ifattach.h> 68#endif 69 70#include <net/if_vlan_var.h> 71 72#include "utils.h" 73 74/* XXX this code should be factored out */ 75/* XXX copied from if_lagg.c */ 76 77static const void * 78mlx4_en_gethdr(struct mbuf *m, u_int off, u_int len, void *buf) 79{ 80 if (m->m_pkthdr.len < (off + len)) { 81 return (NULL); 82 } else if (m->m_len < (off + len)) { 83 m_copydata(m, off, len, buf); 84 return (buf); 85 } 86 return (mtod(m, char *) + off); 87} 88 89uint32_t 90mlx4_en_hashmbuf(uint32_t flags, struct mbuf *m, uint32_t key) 91{ 92 uint16_t etype; 93 uint32_t p = key; 94 int off; 95 struct ether_header *eh; 96 const struct ether_vlan_header *vlan; 97#ifdef INET 98 const struct ip *ip; 99 const uint32_t *ports; 100 int iphlen; 101#endif 102#ifdef INET6 103 const struct ip6_hdr *ip6; 104 uint32_t flow; 105#endif 106 union { 107#ifdef INET 108 struct ip ip; 109#endif 110#ifdef INET6 111 struct ip6_hdr ip6; 112#endif 113 struct ether_vlan_header vlan; 114 uint32_t port; 115 } buf; 116 117 118 off = sizeof(*eh); 119 if (m->m_len < off) 120 goto out; 121 eh = mtod(m, struct ether_header *); 122 etype = ntohs(eh->ether_type); 123 if (flags & MLX4_F_HASHL2) { 124 p = hash32_buf(&eh->ether_shost, ETHER_ADDR_LEN, p); 125 p = hash32_buf(&eh->ether_dhost, ETHER_ADDR_LEN, p); 126 } 127 128 /* Special handling for encapsulating VLAN frames */ 129 if ((m->m_flags & M_VLANTAG) && (flags & MLX4_F_HASHL2)) { 130 p = hash32_buf(&m->m_pkthdr.ether_vtag, 131 sizeof(m->m_pkthdr.ether_vtag), p); 132 } else if (etype == ETHERTYPE_VLAN) { 133 vlan = mlx4_en_gethdr(m, off, sizeof(*vlan), &buf); 134 if (vlan == NULL) 135 goto out; 136 137 if (flags & MLX4_F_HASHL2) 138 p = hash32_buf(&vlan->evl_tag, sizeof(vlan->evl_tag), p); 139 etype = ntohs(vlan->evl_proto); 140 off += sizeof(*vlan) - sizeof(*eh); 141 } 142 143 switch (etype) { 144#ifdef INET 145 case ETHERTYPE_IP: 146 ip = mlx4_en_gethdr(m, off, sizeof(*ip), &buf); 147 if (ip == NULL) 148 goto out; 149 150 if (flags & MLX4_F_HASHL3) { 151 p = hash32_buf(&ip->ip_src, sizeof(struct in_addr), p); 152 p = hash32_buf(&ip->ip_dst, sizeof(struct in_addr), p); 153 } 154 if (!(flags & MLX4_F_HASHL4)) 155 break; 156 switch (ip->ip_p) { 157 case IPPROTO_TCP: 158 case IPPROTO_UDP: 159 case IPPROTO_SCTP: 160 iphlen = ip->ip_hl << 2; 161 if (iphlen < sizeof(*ip)) 162 break; 163 off += iphlen; 164 ports = mlx4_en_gethdr(m, off, sizeof(*ports), &buf); 165 if (ports == NULL) 166 break; 167 p = hash32_buf(ports, sizeof(*ports), p); 168 break; 169 } 170 break; 171#endif 172#ifdef INET6 173 case ETHERTYPE_IPV6: 174 if (!(flags & MLX4_F_HASHL3)) 175 break; 176 ip6 = mlx4_en_gethdr(m, off, sizeof(*ip6), &buf); 177 if (ip6 == NULL) 178 goto out; 179 180 p = hash32_buf(&ip6->ip6_src, sizeof(struct in6_addr), p); 181 p = hash32_buf(&ip6->ip6_dst, sizeof(struct in6_addr), p); 182 flow = ip6->ip6_flow & IPV6_FLOWLABEL_MASK; 183 p = hash32_buf(&flow, sizeof(flow), p); /* IPv6 flow label */ 184 break; 185#endif 186 } 187out: 188 return (p); 189} 190