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