| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: ether_sw_offload.c,v 1.4 2018/12/13 20:54:50 rin Exp $ */ | | 1 | /* $NetBSD: ether_sw_offload.c,v 1.5 2018/12/15 07:29:44 rin Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 2018 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 2018 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Rin Okuyama. | | 8 | * by Rin Okuyama. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
| @@ -24,92 +24,108 @@ | | | @@ -24,92 +24,108 @@ |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. | | 29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ | | 30 | */ |
31 | | | 31 | |
32 | #ifdef _KERNEL_OPT | | 32 | #ifdef _KERNEL_OPT |
33 | #include "opt_inet.h" | | 33 | #include "opt_inet.h" |
34 | #endif | | 34 | #endif |
35 | | | 35 | |
36 | #include <sys/cdefs.h> | | 36 | #include <sys/cdefs.h> |
37 | __KERNEL_RCSID(0, "$NetBSD: ether_sw_offload.c,v 1.4 2018/12/13 20:54:50 rin Exp $"); | | 37 | __KERNEL_RCSID(0, "$NetBSD: ether_sw_offload.c,v 1.5 2018/12/15 07:29:44 rin Exp $"); |
38 | | | 38 | |
39 | #include <sys/param.h> | | 39 | #include <sys/param.h> |
40 | #include <sys/types.h> | | 40 | #include <sys/types.h> |
41 | #include <sys/mbuf.h> | | 41 | #include <sys/mbuf.h> |
| | | 42 | #include <sys/syslog.h> |
| | | 43 | #include <sys/time.h> |
42 | | | 44 | |
43 | #include <net/if.h> | | 45 | #include <net/if.h> |
44 | #include <net/if_ether.h> | | 46 | #include <net/if_ether.h> |
45 | #include <net/ether_sw_offload.h> | | 47 | #include <net/ether_sw_offload.h> |
46 | | | 48 | |
47 | #include <netinet/in.h> | | 49 | #include <netinet/in.h> |
48 | #include <netinet/in_offload.h> | | 50 | #include <netinet/in_offload.h> |
49 | #include <netinet/ip.h> | | 51 | #include <netinet/ip.h> |
50 | #include <netinet/tcp.h> | | 52 | #include <netinet/tcp.h> |
51 | #include <netinet/udp.h> | | 53 | #include <netinet/udp.h> |
52 | | | 54 | |
53 | #ifdef INET6 | | 55 | #ifdef INET6 |
54 | #include <netinet/ip6.h> | | 56 | #include <netinet/ip6.h> |
55 | #include <netinet6/in6.h> | | 57 | #include <netinet6/in6.h> |
56 | #include <netinet6/in6_offload.h> | | 58 | #include <netinet6/in6_offload.h> |
57 | #endif | | 59 | #endif |
58 | | | 60 | |
59 | /* | | 61 | /* |
| | | 62 | * Limit error messages at most once per 10 seconds. |
| | | 63 | */ |
| | | 64 | static const struct timeval eso_err_interval = { |
| | | 65 | .tv_sec = 10, |
| | | 66 | .tv_usec = 0, |
| | | 67 | }; |
| | | 68 | static struct timeval eso_err_lasttime; |
| | | 69 | |
| | | 70 | /* |
60 | * Handle TX offload in software. For TSO, split the packet into | | 71 | * Handle TX offload in software. For TSO, split the packet into |
61 | * chanks with payloads of size MSS. For chekcsum offload, update | | 72 | * chanks with payloads of size MSS. For chekcsum offload, update |
62 | * required checksum fields. The results are more than one packet | | 73 | * required checksum fields. The results are more than one packet |
63 | * in general. Return a mbuf chain consists of them. | | 74 | * in general. Return a mbuf chain consists of them. |
64 | */ | | 75 | */ |
65 | | | 76 | |
66 | struct mbuf * | | 77 | struct mbuf * |
67 | ether_sw_offload_tx(struct ifnet *ifp, struct mbuf *m) | | 78 | ether_sw_offload_tx(struct ifnet *ifp, struct mbuf *m) |
68 | { | | 79 | { |
69 | struct ether_header *ep; | | 80 | struct ether_header *ep; |
70 | int flags, ehlen; | | 81 | int flags, ehlen; |
| | | 82 | uint16_t type; |
71 | #ifdef INET6 | | 83 | #ifdef INET6 |
72 | bool v6; | | 84 | bool v6; |
73 | #else | | 85 | #else |
74 | bool v6 __diagused; | | 86 | bool v6 __diagused; |
75 | #endif | | 87 | #endif |
76 | | | 88 | |
77 | KASSERT(m->m_flags & M_PKTHDR); | | 89 | KASSERT(m->m_flags & M_PKTHDR); |
78 | flags = m->m_pkthdr.csum_flags; | | 90 | flags = m->m_pkthdr.csum_flags; |
79 | if (flags == 0) | | 91 | if (flags == 0) |
80 | goto done; | | 92 | goto done; |
81 | | | 93 | |
82 | /* Sanity check */ | | 94 | /* Sanity check */ |
83 | if (!TX_OFFLOAD_SUPPORTED(ifp->if_csum_flags_tx, flags)) | | 95 | if (!TX_OFFLOAD_SUPPORTED(ifp->if_csum_flags_tx, flags)) |
84 | goto quit; | | 96 | goto quit; |
85 | | | 97 | |
86 | KASSERT(m->m_pkthdr.len >= sizeof(*ep)); | | 98 | KASSERT(m->m_pkthdr.len >= sizeof(*ep)); |
87 | if (m->m_len < sizeof(*ep)) { | | 99 | if (m->m_len < sizeof(*ep)) { |
88 | m = m_pullup(m, sizeof(*ep)); | | 100 | m = m_pullup(m, sizeof(*ep)); |
89 | if (m == NULL) | | 101 | if (m == NULL) |
90 | return NULL; | | 102 | return NULL; |
91 | } | | 103 | } |
92 | ep = mtod(m, struct ether_header *); | | 104 | ep = mtod(m, struct ether_header *); |
93 | switch (ntohs(ep->ether_type)) { | | 105 | switch (type = ntohs(ep->ether_type)) { |
94 | case ETHERTYPE_IP: | | 106 | case ETHERTYPE_IP: |
95 | case ETHERTYPE_IPV6: | | 107 | case ETHERTYPE_IPV6: |
96 | ehlen = ETHER_HDR_LEN; | | 108 | ehlen = ETHER_HDR_LEN; |
97 | break; | | 109 | break; |
98 | case ETHERTYPE_VLAN: | | 110 | case ETHERTYPE_VLAN: |
99 | ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; | | 111 | ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; |
100 | break; | | 112 | break; |
101 | default: | | 113 | default: |
102 | panic("%s: unexpected frame type", __func__); | | 114 | if (ratecheck(&eso_err_lasttime, &eso_err_interval)) |
| | | 115 | log(LOG_ERR, "%s: %s: dropping invalid frame " |
| | | 116 | "type 0x%04hx csum_flags 0x%08x\n", |
| | | 117 | __func__, ifp->if_xname, type, flags); |
| | | 118 | goto quit; |
103 | } | | 119 | } |
104 | KASSERT(m->m_pkthdr.len >= ehlen); | | 120 | KASSERT(m->m_pkthdr.len >= ehlen); |
105 | | | 121 | |
106 | v6 = flags & (M_CSUM_TSOv6 | M_CSUM_TCPv6 | M_CSUM_UDPv6); | | 122 | v6 = flags & (M_CSUM_TSOv6 | M_CSUM_TCPv6 | M_CSUM_UDPv6); |
107 | #ifndef INET6 | | 123 | #ifndef INET6 |
108 | KASSERT(!v6); | | 124 | KASSERT(!v6); |
109 | #endif | | 125 | #endif |
110 | | | 126 | |
111 | if (flags & (M_CSUM_TSOv4 | M_CSUM_TSOv6)) { | | 127 | if (flags & (M_CSUM_TSOv4 | M_CSUM_TSOv6)) { |
112 | /* | | 128 | /* |
113 | * tcp[46]_segment() assume that size of payloads is | | 129 | * tcp[46]_segment() assume that size of payloads is |
114 | * a multiple of MSS. Further, tcp6_segment() assumes | | 130 | * a multiple of MSS. Further, tcp6_segment() assumes |
115 | * no extention headers. | | 131 | * no extention headers. |