1272027Shselasky/* $OpenBSD: if_trunk.c,v 1.30 2007/01/31 06:20:19 reyk Exp $ */ 2272027Shselasky 3272027Shselasky/* 4272027Shselasky * Copyright (c) 2005, 2006 Reyk Floeter <reyk@openbsd.org> 5272027Shselasky * Copyright (c) 2007 Andrew Thompson <thompsa@FreeBSD.org> 6272027Shselasky * 7272027Shselasky * Permission to use, copy, modify, and distribute this software for any 8272027Shselasky * purpose with or without fee is hereby granted, provided that the above 9272027Shselasky * copyright notice and this permission notice appear in all copies. 10272027Shselasky * 11272027Shselasky * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12272027Shselasky * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13272027Shselasky * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14272027Shselasky * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15272027Shselasky * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16272027Shselasky * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17272027Shselasky * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18272027Shselasky */ 19272027Shselasky 20272027Shselasky#include <sys/cdefs.h> 21272027Shselasky__FBSDID("$FreeBSD$"); 22272027Shselasky 23272027Shselasky#include "opt_inet.h" 24272027Shselasky#include "opt_inet6.h" 25272027Shselasky 26272027Shselasky#include <sys/param.h> 27272027Shselasky#include <sys/kernel.h> 28272027Shselasky#include <sys/malloc.h> 29272027Shselasky#include <sys/mbuf.h> 30272027Shselasky#include <sys/queue.h> 31272027Shselasky#include <sys/socket.h> 32272027Shselasky#include <sys/sockio.h> 33272027Shselasky#include <sys/sysctl.h> 34272027Shselasky#include <sys/module.h> 35272027Shselasky#include <sys/priv.h> 36272027Shselasky#include <sys/systm.h> 37272027Shselasky#include <sys/proc.h> 38272027Shselasky#include <sys/hash.h> 39272027Shselasky#include <sys/lock.h> 40272027Shselasky#include <sys/rmlock.h> 41272027Shselasky#include <sys/taskqueue.h> 42272027Shselasky#include <sys/eventhandler.h> 43272027Shselasky 44272027Shselasky#include <net/ethernet.h> 45272027Shselasky#include <net/if.h> 46272027Shselasky#include <net/if_clone.h> 47272027Shselasky#include <net/if_arp.h> 48272027Shselasky#include <net/if_dl.h> 49272027Shselasky#include <net/if_llc.h> 50272027Shselasky#include <net/if_media.h> 51272027Shselasky#include <net/if_types.h> 52272027Shselasky#include <net/if_var.h> 53272027Shselasky#include <net/bpf.h> 54272027Shselasky 55272027Shselasky#if defined(INET) || defined(INET6) 56272027Shselasky#include <netinet/in.h> 57272027Shselasky#endif 58272027Shselasky#ifdef INET 59272027Shselasky#include <netinet/in_systm.h> 60272027Shselasky#include <netinet/if_ether.h> 61272027Shselasky#include <netinet/ip.h> 62272027Shselasky#endif 63272027Shselasky 64272027Shselasky#ifdef INET6 65272027Shselasky#include <netinet/ip6.h> 66272027Shselasky#include <netinet6/in6_var.h> 67272027Shselasky#include <netinet6/in6_ifattach.h> 68272027Shselasky#endif 69272027Shselasky 70272027Shselasky#include <net/if_vlan_var.h> 71272027Shselasky 72272027Shselasky#include "utils.h" 73272027Shselasky 74272027Shselasky/* XXX this code should be factored out */ 75272027Shselasky/* XXX copied from if_lagg.c */ 76272027Shselasky 77272027Shselaskystatic const void * 78272027Shselaskymlx4_en_gethdr(struct mbuf *m, u_int off, u_int len, void *buf) 79272027Shselasky{ 80272027Shselasky if (m->m_pkthdr.len < (off + len)) { 81272027Shselasky return (NULL); 82272027Shselasky } else if (m->m_len < (off + len)) { 83272027Shselasky m_copydata(m, off, len, buf); 84272027Shselasky return (buf); 85272027Shselasky } 86272027Shselasky return (mtod(m, char *) + off); 87272027Shselasky} 88272027Shselasky 89272027Shselaskyuint32_t 90272027Shselaskymlx4_en_hashmbuf(uint32_t flags, struct mbuf *m, uint32_t key) 91272027Shselasky{ 92272027Shselasky uint16_t etype; 93272027Shselasky uint32_t p = key; 94272027Shselasky int off; 95272027Shselasky struct ether_header *eh; 96272027Shselasky const struct ether_vlan_header *vlan; 97272027Shselasky#ifdef INET 98272027Shselasky const struct ip *ip; 99272027Shselasky const uint32_t *ports; 100272027Shselasky int iphlen; 101272027Shselasky#endif 102272027Shselasky#ifdef INET6 103272027Shselasky const struct ip6_hdr *ip6; 104272027Shselasky uint32_t flow; 105272027Shselasky#endif 106272027Shselasky union { 107272027Shselasky#ifdef INET 108272027Shselasky struct ip ip; 109272027Shselasky#endif 110272027Shselasky#ifdef INET6 111272027Shselasky struct ip6_hdr ip6; 112272027Shselasky#endif 113272027Shselasky struct ether_vlan_header vlan; 114272027Shselasky uint32_t port; 115272027Shselasky } buf; 116272027Shselasky 117272027Shselasky 118272027Shselasky off = sizeof(*eh); 119272027Shselasky if (m->m_len < off) 120272027Shselasky goto out; 121272027Shselasky eh = mtod(m, struct ether_header *); 122272027Shselasky etype = ntohs(eh->ether_type); 123272027Shselasky if (flags & MLX4_F_HASHL2) { 124272027Shselasky p = hash32_buf(&eh->ether_shost, ETHER_ADDR_LEN, p); 125272027Shselasky p = hash32_buf(&eh->ether_dhost, ETHER_ADDR_LEN, p); 126272027Shselasky } 127272027Shselasky 128272027Shselasky /* Special handling for encapsulating VLAN frames */ 129272027Shselasky if ((m->m_flags & M_VLANTAG) && (flags & MLX4_F_HASHL2)) { 130272027Shselasky p = hash32_buf(&m->m_pkthdr.ether_vtag, 131272027Shselasky sizeof(m->m_pkthdr.ether_vtag), p); 132272027Shselasky } else if (etype == ETHERTYPE_VLAN) { 133272027Shselasky vlan = mlx4_en_gethdr(m, off, sizeof(*vlan), &buf); 134272027Shselasky if (vlan == NULL) 135272027Shselasky goto out; 136272027Shselasky 137272027Shselasky if (flags & MLX4_F_HASHL2) 138272027Shselasky p = hash32_buf(&vlan->evl_tag, sizeof(vlan->evl_tag), p); 139272027Shselasky etype = ntohs(vlan->evl_proto); 140272027Shselasky off += sizeof(*vlan) - sizeof(*eh); 141272027Shselasky } 142272027Shselasky 143272027Shselasky switch (etype) { 144272027Shselasky#ifdef INET 145272027Shselasky case ETHERTYPE_IP: 146272027Shselasky ip = mlx4_en_gethdr(m, off, sizeof(*ip), &buf); 147272027Shselasky if (ip == NULL) 148272027Shselasky goto out; 149272027Shselasky 150272027Shselasky if (flags & MLX4_F_HASHL3) { 151272027Shselasky p = hash32_buf(&ip->ip_src, sizeof(struct in_addr), p); 152272027Shselasky p = hash32_buf(&ip->ip_dst, sizeof(struct in_addr), p); 153272027Shselasky } 154272027Shselasky if (!(flags & MLX4_F_HASHL4)) 155272027Shselasky break; 156272027Shselasky switch (ip->ip_p) { 157272027Shselasky case IPPROTO_TCP: 158272027Shselasky case IPPROTO_UDP: 159272027Shselasky case IPPROTO_SCTP: 160272027Shselasky iphlen = ip->ip_hl << 2; 161272027Shselasky if (iphlen < sizeof(*ip)) 162272027Shselasky break; 163272027Shselasky off += iphlen; 164272027Shselasky ports = mlx4_en_gethdr(m, off, sizeof(*ports), &buf); 165272027Shselasky if (ports == NULL) 166272027Shselasky break; 167272027Shselasky p = hash32_buf(ports, sizeof(*ports), p); 168272027Shselasky break; 169272027Shselasky } 170272027Shselasky break; 171272027Shselasky#endif 172272027Shselasky#ifdef INET6 173272027Shselasky case ETHERTYPE_IPV6: 174272027Shselasky if (!(flags & MLX4_F_HASHL3)) 175272027Shselasky break; 176272027Shselasky ip6 = mlx4_en_gethdr(m, off, sizeof(*ip6), &buf); 177272027Shselasky if (ip6 == NULL) 178272027Shselasky goto out; 179272027Shselasky 180272027Shselasky p = hash32_buf(&ip6->ip6_src, sizeof(struct in6_addr), p); 181272027Shselasky p = hash32_buf(&ip6->ip6_dst, sizeof(struct in6_addr), p); 182272027Shselasky flow = ip6->ip6_flow & IPV6_FLOWLABEL_MASK; 183272027Shselasky p = hash32_buf(&flow, sizeof(flow), p); /* IPv6 flow label */ 184272027Shselasky break; 185272027Shselasky#endif 186272027Shselasky } 187272027Shselaskyout: 188272027Shselasky return (p); 189272027Shselasky} 190