Date: Mon, 28 Jan 2008 23:11:44 GMT From: Andre Oppermann <andre@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 134333 for review Message-ID: <200801282311.m0SNBioE048376@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=134333 Change 134333 by andre@andre_flirtbox on 2008/01/28 23:10:52 Add tcptruncate rule option to ipfw. It is used to test and exercise tcp reassembly queue processing and SACK block tracking. From its man page: tcptruncate Modifies TCP packets by truncating their payload. Positive num- bers truncate from the tail of the packet, negative numbers from the head. At least one byte is left in the payload, even if the truncate size is larger than the whole payload. The diff to /src/sbin/ipfw/ipfw2.[c8] is added as file because this branch doesn't contain userland bits. An example truncating 1% each of the incoming segments from tail and head: ipfw add 100 prob 0.01 allow tcp from any to me tcptruncate 10 ipfw add 100 prob 0.0101 allow tcp from any to me tcptruncate -10 Affected files ... .. //depot/projects/tcp_reass/netinet/ip_fw.h#2 edit .. //depot/projects/tcp_reass/netinet/ip_fw2.c#2 edit .. //depot/projects/tcp_reass/netinet/src-sbin-ipfw-tcptruncate.diff#1 add Differences ... ==== //depot/projects/tcp_reass/netinet/ip_fw.h#2 (text+ko) ==== @@ -161,6 +161,7 @@ O_TAG, /* arg1=tag number */ O_TAGGED, /* arg1=tag number */ + O_TCPTRUNCATE, /* arg1=truncate TCP segment */ O_LAST_OPCODE /* not an opcode! */ }; ==== //depot/projects/tcp_reass/netinet/ip_fw2.c#2 (text+ko) ==== @@ -3025,6 +3025,71 @@ } break; + case O_TCPTRUNCATE: + /* Cut off part of the tcp segment. */ + if (proto == IPPROTO_TCP && offset == 0) { + struct tcphdr *tcp; + uint16_t datalen, hdrlen; + int16_t trunc; + int i; + + if (cmdlen != 1) + break; + + /* Initialize. */ + tcp = TCP(ulp); + hdrlen = ((ip->ip_hl + tcp->th_off) << 2); + datalen = ip_len - hdrlen; + trunc = (int16_t)cmd->arg1; + + /* Never make a zero sized segment. */ + if (datalen < 2 || trunc == 0) + break; + + /* + * Trim from end of segment. + * Adjust ip->ip_len. + * Update TCP checksum. + */ + if (trunc > 0) { + /* Truncating from the tail always works. */ + i = min(datalen - 1, datalen - trunc); + m_adj(m, -i); + } else if (m->m_next == NULL) { + /* Single mbuf, the common case. */ + i = min(datalen - 1, datalen - (+trunc)); + bcopy(mtod(m, caddr_t) + hdrlen, mtod(m, caddr_t), i); + m_adj(m, -i); + } else if (m->m_len == hdrlen && m->m_next != NULL) { + /* Header splitting. */ + i = min(datalen - 1, datalen - (+trunc)); + m_adj(m->m_next, i); + } else + break; + + /* Accounting for the changes. */ + ip->ip_len = m->m_pkthdr.len; + pktlen = ip_len = m->m_pkthdr.len; + + /* Updating checksum, not offloaded. */ + tcp->th_sum = 0; + tcp->th_sum = in_pseudo(ip->ip_src.s_addr, + ip->ip_dst.s_addr, + htons(IPPROTO_TCP + ip_len - + (ip->ip_hl << 2))); + tcp->th_sum = in_cksum_skip(m, ip->ip_len, + ip->ip_hl << 2); + ip->ip_len = htons(ip->ip_len); + ip->ip_off = htons(ip->ip_off); + ip->ip_sum = 0; + ip->ip_sum = in_cksum(m, hlen); + ip->ip_len = htons(ip->ip_len); + ip->ip_off = htons(ip->ip_off); + + match = 1; + } + break; + case O_TCPFLAGS: match = (proto == IPPROTO_TCP && offset == 0 && flags_match(cmd, TCP(ulp)->th_flags)); @@ -4133,6 +4198,7 @@ #endif case O_IP4: case O_TAG: + case O_TCPTRUNCATE: if (cmdlen != F_INSN_SIZE(ipfw_insn)) goto bad_size; break;
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200801282311.m0SNBioE048376>