summaryrefslogtreecommitdiffstats
path: root/sys/netinet
diff options
context:
space:
mode:
authorandre <andre@FreeBSD.org>2013-06-03 12:55:13 +0000
committerandre <andre@FreeBSD.org>2013-06-03 12:55:13 +0000
commitb706ceb4abd7f12c0ad38c0da053f4523814bcc4 (patch)
tree1234da94faa0d8e5fb8d693bb7883535361a40a4 /sys/netinet
parent4cb7f1fd6f7638e16e52678307df1995d28cad40 (diff)
downloadFreeBSD-src-b706ceb4abd7f12c0ad38c0da053f4523814bcc4.zip
FreeBSD-src-b706ceb4abd7f12c0ad38c0da053f4523814bcc4.tar.gz
Allow drivers to specify a maximum TSO length in bytes if they are
limited in the amount of data they can handle at once. Drivers can set ifp->if_hw_tsomax before calling ether_ifattach() to change the limit. The lowest allowable size is IP_MAXPACKET / 8 (8192 bytes) as anything less wouldn't be very useful anymore. The upper limit is still at IP_MAXPACKET (65536 bytes). Raising it requires further auditing of the IPv4/v6 code path's as the length field in the IP header would overflow leading to confusion in firewalls and others packet handler on the real size of the packet. The placement into "struct ifnet" is a bit hackish but the best place that was found. When the stack/driver boundary is updated it should be handled in a better way. Submitted by: cperciva (earlier version) Reviewed by: cperciva Tested by: cperciva MFC after: 1 week (using spare struct members to preserve ABI)
Diffstat (limited to 'sys/netinet')
-rw-r--r--sys/netinet/tcp_input.c17
-rw-r--r--sys/netinet/tcp_output.c9
-rw-r--r--sys/netinet/tcp_subr.c14
-rw-r--r--sys/netinet/tcp_var.h17
4 files changed, 37 insertions, 20 deletions
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c
index a3122a1..25b320e 100644
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -3434,7 +3434,7 @@ tcp_xmit_timer(struct tcpcb *tp, int rtt)
*/
void
tcp_mss_update(struct tcpcb *tp, int offer, int mtuoffer,
- struct hc_metrics_lite *metricptr, int *mtuflags)
+ struct hc_metrics_lite *metricptr, struct tcp_ifcap *cap)
{
int mss = 0;
u_long maxmtu = 0;
@@ -3461,7 +3461,7 @@ tcp_mss_update(struct tcpcb *tp, int offer, int mtuoffer,
/* Initialize. */
#ifdef INET6
if (isipv6) {
- maxmtu = tcp_maxmtu6(&inp->inp_inc, mtuflags);
+ maxmtu = tcp_maxmtu6(&inp->inp_inc, cap);
tp->t_maxopd = tp->t_maxseg = V_tcp_v6mssdflt;
}
#endif
@@ -3470,7 +3470,7 @@ tcp_mss_update(struct tcpcb *tp, int offer, int mtuoffer,
#endif
#ifdef INET
{
- maxmtu = tcp_maxmtu(&inp->inp_inc, mtuflags);
+ maxmtu = tcp_maxmtu(&inp->inp_inc, cap);
tp->t_maxopd = tp->t_maxseg = V_tcp_mssdflt;
}
#endif
@@ -3605,11 +3605,12 @@ tcp_mss(struct tcpcb *tp, int offer)
struct inpcb *inp;
struct socket *so;
struct hc_metrics_lite metrics;
- int mtuflags = 0;
+ struct tcp_ifcap cap;
KASSERT(tp != NULL, ("%s: tp == NULL", __func__));
-
- tcp_mss_update(tp, offer, -1, &metrics, &mtuflags);
+
+ bzero(&cap, sizeof(cap));
+ tcp_mss_update(tp, offer, -1, &metrics, &cap);
mss = tp->t_maxseg;
inp = tp->t_inpcb;
@@ -3654,8 +3655,10 @@ tcp_mss(struct tcpcb *tp, int offer)
SOCKBUF_UNLOCK(&so->so_rcv);
/* Check the interface for TSO capabilities. */
- if (mtuflags & CSUM_TSO)
+ if (cap.ifcap & CSUM_TSO) {
tp->t_flags |= TF_TSO;
+ tp->t_tsomax = cap.tsomax;
+ }
}
/*
diff --git a/sys/netinet/tcp_output.c b/sys/netinet/tcp_output.c
index 16038cb..b4342f3 100644
--- a/sys/netinet/tcp_output.c
+++ b/sys/netinet/tcp_output.c
@@ -769,12 +769,13 @@ send:
("%s: TSO can't do IP options", __func__));
/*
- * Limit a burst to IP_MAXPACKET minus IP,
+ * Limit a burst to t_tsomax minus IP,
* TCP and options length to keep ip->ip_len
- * from overflowing.
+ * from overflowing or exceeding the maximum
+ * length allowed by the network interface.
*/
- if (len > IP_MAXPACKET - hdrlen) {
- len = IP_MAXPACKET - hdrlen;
+ if (len > tp->t_tsomax - hdrlen) {
+ len = tp->t_tsomax - hdrlen;
sendalot = 1;
}
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c
index 05030fd..c466bf4 100644
--- a/sys/netinet/tcp_subr.c
+++ b/sys/netinet/tcp_subr.c
@@ -1770,7 +1770,7 @@ tcp_mtudisc(struct inpcb *inp, int mtuoffer)
* tcp_mss_update to get the peer/interface MTU.
*/
u_long
-tcp_maxmtu(struct in_conninfo *inc, int *flags)
+tcp_maxmtu(struct in_conninfo *inc, struct tcp_ifcap *cap)
{
struct route sro;
struct sockaddr_in *dst;
@@ -1795,10 +1795,11 @@ tcp_maxmtu(struct in_conninfo *inc, int *flags)
maxmtu = min(sro.ro_rt->rt_rmx.rmx_mtu, ifp->if_mtu);
/* Report additional interface capabilities. */
- if (flags != NULL) {
+ if (cap != NULL) {
if (ifp->if_capenable & IFCAP_TSO4 &&
ifp->if_hwassist & CSUM_TSO)
- *flags |= CSUM_TSO;
+ cap->ifcap |= CSUM_TSO;
+ cap->tsomax = ifp->if_hw_tsomax;
}
RTFREE(sro.ro_rt);
}
@@ -1808,7 +1809,7 @@ tcp_maxmtu(struct in_conninfo *inc, int *flags)
#ifdef INET6
u_long
-tcp_maxmtu6(struct in_conninfo *inc, int *flags)
+tcp_maxmtu6(struct in_conninfo *inc, struct tcp_ifcap *cap)
{
struct route_in6 sro6;
struct ifnet *ifp;
@@ -1832,10 +1833,11 @@ tcp_maxmtu6(struct in_conninfo *inc, int *flags)
IN6_LINKMTU(sro6.ro_rt->rt_ifp));
/* Report additional interface capabilities. */
- if (flags != NULL) {
+ if (cap != NULL) {
if (ifp->if_capenable & IFCAP_TSO6 &&
ifp->if_hwassist & CSUM_TSO)
- *flags |= CSUM_TSO;
+ cap->ifcap |= CSUM_TSO;
+ cap->tsomax = ifp->if_hw_tsomax;
}
RTFREE(sro6.ro_rt);
}
diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h
index eddbd3c..0445d8c 100644
--- a/sys/netinet/tcp_var.h
+++ b/sys/netinet/tcp_var.h
@@ -208,6 +208,8 @@ struct tcpcb {
u_int t_keepintvl; /* interval between keepalives */
u_int t_keepcnt; /* number of keepalives before close */
+ u_int t_tsomax; /* tso burst length limit */
+
uint32_t t_ispare[8]; /* 5 UTO, 3 TBD */
void *t_pspare2[4]; /* 4 TBD */
uint64_t _pad[6]; /* 6 TBD (1-2 CC/RTT?) */
@@ -324,6 +326,15 @@ struct hc_metrics_lite { /* must stay in sync with hc_metrics */
u_long rmx_recvpipe; /* inbound delay-bandwidth product */
};
+/*
+ * Used by tcp_maxmtu() to communicate interface specific features
+ * and limits at the time of connection setup.
+ */
+struct tcp_ifcap {
+ int ifcap;
+ u_int tsomax;
+};
+
#ifndef _NETINET_IN_PCB_H_
struct in_conninfo;
#endif /* _NETINET_IN_PCB_H_ */
@@ -782,10 +793,10 @@ void tcp_reass_flush(struct tcpcb *);
void tcp_reass_destroy(void);
#endif
void tcp_input(struct mbuf *, int);
-u_long tcp_maxmtu(struct in_conninfo *, int *);
-u_long tcp_maxmtu6(struct in_conninfo *, int *);
+u_long tcp_maxmtu(struct in_conninfo *, struct tcp_ifcap *);
+u_long tcp_maxmtu6(struct in_conninfo *, struct tcp_ifcap *);
void tcp_mss_update(struct tcpcb *, int, int, struct hc_metrics_lite *,
- int *);
+ struct tcp_ifcap *);
void tcp_mss(struct tcpcb *, int);
int tcp_mssopt(struct in_conninfo *);
struct inpcb *
OpenPOWER on IntegriCloud