Ok, here's the updated tcp template removal patch. It's functionally the same, which is why I'm not including an updated -stable patch. Also, I did test it with IPv6, and it seems good. No IPSEC testing, but I see no reason why it would break if v4/v6 didn't. What did change: - Formatting all fixed (most of the problems were due to my hasty -stable patch. The -current patch was less quirky.) - t_template has been replaced with unused in the tcpcb to make sure nobody uses it accidently. I renamed rather than removed it because removal would probably break userland tools expecting the existing structure. - All t_templates = NULLs and checks to make sure it was null have been removed. I think it's ready for commit now, please review. Thanks, Mike "Silby" Silbersack
diff -u -r netinet.old/tcp_input.c netinet/tcp_input.c --- netinet.old/tcp_input.c Mon Jun 18 20:45:07 2001 +++ netinet/tcp_input.c Wed Jun 20 15:17:43 2001 @@ -1127,12 +1127,6 @@ } FREE(sin, M_SONAME); } - tp->t_template = tcp_template(tp); - if (tp->t_template == 0) { - tp = tcp_drop(tp, ENOBUFS); - dropsocket = 0; /* socket is already gone */ - goto drop; - } if ((taop = tcp_gettaocache(inp)) == NULL) { taop = &tao_noncached; bzero(taop, sizeof(*taop)); diff -u -r netinet.old/tcp_output.c netinet/tcp_output.c --- netinet.old/tcp_output.c Mon Jun 18 20:45:07 2001 +++ netinet/tcp_output.c Thu Jun 21 21:37:57 2001 @@ -632,16 +632,11 @@ m->m_len = hdrlen; } m->m_pkthdr.rcvif = (struct ifnet *)0; - if (tp->t_template == 0) - panic("tcp_output"); #ifdef INET6 if (isipv6) { ip6 = mtod(m, struct ip6_hdr *); th = (struct tcphdr *)(ip6 + 1); - bcopy((caddr_t)tp->t_template->tt_ipgen, (caddr_t)ip6, - sizeof(struct ip6_hdr)); - bcopy((caddr_t)&tp->t_template->tt_t, (caddr_t)th, - sizeof(struct tcphdr)); + tcp_fillheaders(tp, ip6, th); } else #endif /* INET6 */ { @@ -649,10 +644,7 @@ ipov = (struct ipovly *)ip; th = (struct tcphdr *)(ip + 1); /* this picks up the pseudo header (w/o the length) */ - bcopy((caddr_t)tp->t_template->tt_ipgen, (caddr_t)ip, - sizeof(struct ip)); - bcopy((caddr_t)&tp->t_template->tt_t, (caddr_t)th, - sizeof(struct tcphdr)); + tcp_fillheaders(tp, ip, th); } /* diff -u -r netinet.old/tcp_subr.c netinet/tcp_subr.c --- netinet.old/tcp_subr.c Mon Jun 18 20:45:07 2001 +++ netinet/tcp_subr.c Thu Jun 21 21:43:39 2001 @@ -218,31 +218,24 @@ } /* - * Create template to be used to send tcp packets on a connection. - * Call after host entry created, allocates an mbuf and fills - * in a skeletal tcp/ip header, minimizing the amount of work - * necessary when the connection is used. + * Fill in the IP and TCP headers for an outgoing packet, given the tcpcb. + * tcp_template used to store this data in mbufs, but we now recopy it out + * of the tcpcb each time to conserve mbufs. */ -struct tcptemp * -tcp_template(tp) +void +tcp_fillheaders(tp, ip_ptr, tcp_ptr) struct tcpcb *tp; + void *ip_ptr; + void *tcp_ptr; { - register struct inpcb *inp = tp->t_inpcb; - register struct mbuf *m; - register struct tcptemp *n; + struct inpcb *inp = tp->t_inpcb; + struct tcphdr *tcp_hdr = (struct tcphdr *)tcp_ptr; - if ((n = tp->t_template) == 0) { - m = m_get(M_DONTWAIT, MT_HEADER); - if (m == NULL) - return (0); - m->m_len = sizeof (struct tcptemp); - n = mtod(m, struct tcptemp *); - } #ifdef INET6 if ((inp->inp_vflag & INP_IPV6) != 0) { - register struct ip6_hdr *ip6; + struct ip6_hdr *ip6; - ip6 = (struct ip6_hdr *)n->tt_ipgen; + ip6 = (struct ip6_hdr *)ip_ptr; ip6->ip6_flow = (ip6->ip6_flow & ~IPV6_FLOWINFO_MASK) | (inp->in6p_flowinfo & IPV6_FLOWINFO_MASK); ip6->ip6_vfc = (ip6->ip6_vfc & ~IPV6_VERSION_MASK) | @@ -251,29 +244,51 @@ ip6->ip6_plen = sizeof(struct tcphdr); ip6->ip6_src = inp->in6p_laddr; ip6->ip6_dst = inp->in6p_faddr; - n->tt_t.th_sum = 0; + tcp_hdr->th_sum = 0; } else #endif - { - struct ip *ip = (struct ip *)n->tt_ipgen; + { + struct ip *ip = (struct ip *) ip_ptr; - bzero(ip, sizeof(struct ip)); /* XXX overkill? */ + bzero(ip, sizeof(struct ip)); /* XXX overkill? */ ip->ip_vhl = IP_VHL_BORING; ip->ip_p = IPPROTO_TCP; ip->ip_src = inp->inp_laddr; ip->ip_dst = inp->inp_faddr; - n->tt_t.th_sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, - htons(sizeof(struct tcphdr) + IPPROTO_TCP)); - } - n->tt_t.th_sport = inp->inp_lport; - n->tt_t.th_dport = inp->inp_fport; - n->tt_t.th_seq = 0; - n->tt_t.th_ack = 0; - n->tt_t.th_x2 = 0; - n->tt_t.th_off = 5; - n->tt_t.th_flags = 0; - n->tt_t.th_win = 0; - n->tt_t.th_urp = 0; + tcp_hdr->th_sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, + htons(sizeof(struct tcphdr) + IPPROTO_TCP)); + } + + tcp_hdr->th_sport = inp->inp_lport; + tcp_hdr->th_dport = inp->inp_fport; + tcp_hdr->th_seq = 0; + tcp_hdr->th_ack = 0; + tcp_hdr->th_x2 = 0; + tcp_hdr->th_off = 5; + tcp_hdr->th_flags = 0; + tcp_hdr->th_win = 0; + tcp_hdr->th_urp = 0; +} + +/* + * Create template to be used to send tcp packets on a connection. + * Allocates an mbuf and fills in a skeletal tcp/ip header. The only + * use for this function is in keepalives, which use tcp_respond. + */ +struct tcptemp * +tcp_maketemplate(tp) + struct tcpcb *tp; +{ + struct mbuf *m; + struct tcptemp *n; + + m = m_get(M_DONTWAIT, MT_HEADER); + if (m == NULL) + return (0); + m->m_len = sizeof(struct tcptemp); + n = mtod(m, struct tcptemp *); + + tcp_fillheaders(tp, (void *)&n->tt_ipgen, (void *)&n->tt_t); return (n); } @@ -282,10 +297,9 @@ * the given TCP/IP header. If m == 0, then we make a copy * of the tcpiphdr at ti and send directly to the addressed host. * This is used to force keep alive messages out using the TCP - * template for a connection tp->t_template. If flags are given - * then we send a message back to the TCP which originated the - * segment ti, and discard the mbuf containing it and any other - * attached mbufs. + * template for a connection. If flags are given then we send + * a message back to the TCP which originated the * segment ti, + * and discard the mbuf containing it and any other attached mbufs. * * In any case the ack and sequence number of the transmitted * segment are as specified by the parameters. @@ -701,8 +715,6 @@ m_freem(q->tqe_m); FREE(q, M_TSEGQ); } - if (tp->t_template) - (void) m_free(dtom(tp->t_template)); inp->inp_ppcb = NULL; soisdisconnected(so); #ifdef INET6 @@ -1339,7 +1351,7 @@ #endif /* INET6 */ struct tcphdr *th; - if (!tp || !tp->t_template || !(inp = tp->t_inpcb)) + if ((tp == NULL) || ((inp = tp->t_inpcb) == NULL)) return 0; MGETHDR(m, M_DONTWAIT, MT_DATA); if (!m) @@ -1351,10 +1363,7 @@ th = (struct tcphdr *)(ip6 + 1); m->m_pkthdr.len = m->m_len = sizeof(struct ip6_hdr) + sizeof(struct tcphdr); - bcopy((caddr_t)tp->t_template->tt_ipgen, (caddr_t)ip6, - sizeof(struct ip6_hdr)); - bcopy((caddr_t)&tp->t_template->tt_t, (caddr_t)th, - sizeof(struct tcphdr)); + tcp_fillheaders(tp, ip6, th); hdrsiz = ipsec6_hdrsiz(m, IPSEC_DIR_OUTBOUND, inp); } else #endif /* INET6 */ @@ -1362,10 +1371,7 @@ ip = mtod(m, struct ip *); th = (struct tcphdr *)(ip + 1); m->m_pkthdr.len = m->m_len = sizeof(struct tcpiphdr); - bcopy((caddr_t)tp->t_template->tt_ipgen, (caddr_t)ip, - sizeof(struct ip)); - bcopy((caddr_t)&tp->t_template->tt_t, (caddr_t)th, - sizeof(struct tcphdr)); + tcp_fillheaders(tp, ip, th); ip->ip_vhl = IP_VHL_BORING; hdrsiz = ipsec4_hdrsiz(m, IPSEC_DIR_OUTBOUND, inp); } Only in netinet.old/: tcp_subr.c.new diff -u -r netinet.old/tcp_timer.c netinet/tcp_timer.c --- netinet.old/tcp_timer.c Mon Jun 18 20:45:07 2001 +++ netinet/tcp_timer.c Thu Jun 21 21:43:59 2001 @@ -41,6 +41,7 @@ #include <sys/param.h> #include <sys/systm.h> #include <sys/kernel.h> +#include <sys/mbuf.h> #include <sys/sysctl.h> #include <sys/socket.h> #include <sys/socketvar.h> @@ -222,6 +223,7 @@ void *xtp; { struct tcpcb *tp = xtp; + struct tcptemp *t_template; int s; #ifdef TCPDEBUG int ostate; @@ -259,9 +261,13 @@ * correspondent TCP to respond. */ tcpstat.tcps_keepprobe++; - tcp_respond(tp, tp->t_template->tt_ipgen, - &tp->t_template->tt_t, (struct mbuf *)NULL, - tp->rcv_nxt, tp->snd_una - 1, 0); + t_template = tcp_maketemplate(tp); + if (t_template) { + tcp_respond(tp, t_template->tt_ipgen, + &t_template->tt_t, (struct mbuf *)NULL, + tp->rcv_nxt, tp->snd_una - 1, 0); + (void) m_free(dtom(t_template)); + } callout_reset(tp->tt_keep, tcp_keepintvl, tcp_timer_keep, tp); } else callout_reset(tp->tt_keep, tcp_keepidle, tcp_timer_keep, tp); diff -u -r netinet.old/tcp_usrreq.c netinet/tcp_usrreq.c --- netinet.old/tcp_usrreq.c Mon Jun 18 20:45:07 2001 +++ netinet/tcp_usrreq.c Wed Jun 20 15:18:33 2001 @@ -749,12 +749,6 @@ inp->inp_fport = sin->sin_port; in_pcbrehash(inp); - tp->t_template = tcp_template(tp); - if (tp->t_template == 0) { - in_pcbdisconnect(inp); - return ENOBUFS; - } - /* Compute window scaling to request. */ while (tp->request_r_scale < TCP_MAX_WINSHIFT && (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat) @@ -840,12 +834,6 @@ if ((sin6->sin6_flowinfo & IPV6_FLOWINFO_MASK) != NULL) inp->in6p_flowinfo = sin6->sin6_flowinfo; in_pcbrehash(inp); - - tp->t_template = tcp_template(tp); - if (tp->t_template == 0) { - in6_pcbdisconnect(inp); - return ENOBUFS; - } /* Compute window scaling to request. */ while (tp->request_r_scale < TCP_MAX_WINSHIFT && diff -u -r netinet.old/tcp_var.h netinet/tcp_var.h --- netinet.old/tcp_var.h Mon Jun 18 20:45:07 2001 +++ netinet/tcp_var.h Wed Jun 20 15:17:31 2001 @@ -66,7 +66,7 @@ struct tcpcb { struct tsegqe_head t_segq; int t_dupacks; /* consecutive dup acks recd */ - struct tcptemp *t_template; /* skeletal packet for transmit */ + struct tcptemp *unused; /* unused */ struct callout *tt_rexmt; /* retransmit timer */ struct callout *tt_persist; /* retransmit persistence */ @@ -400,7 +400,8 @@ void tcp_setpersist __P((struct tcpcb *)); void tcp_slowtimo __P((void)); struct tcptemp * - tcp_template __P((struct tcpcb *)); + tcp_maketemplate __P((struct tcpcb *)); +void tcp_fillheaders __P((struct tcpcb *, void *, void *)); struct tcpcb * tcp_timers __P((struct tcpcb *, int)); void tcp_trace __P((int, int, struct tcpcb *, void *, struct tcphdr *,