utils.c revision 272407
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