Add simple IP/UDP fragmentation support
PATCH 1/1 Add simple IP/UDP fragmentation support
From: Frank Haverkamp <[email protected]>
http://tools.ietf.org/html/rfc2348 describes the TFTP block size option which allows larger packtes than the 512 byte default. This reduces the number of TFTP ACKs significantly and improves performance.
To get the most benefit out of the tftp block size option the support of defragementation of IP/UDP packet is helpful. The current implemenation should work even with packets received out of order. To enable the large packet size the user should set "tftp_block_size" so a value like 16352.
We experimented with different packet sizes and found that more than those 16KiB do not contribute much to the performance anymore. Therefor I limited the defragmentation buffer to 16KiB no too waste memory.
--- include/net.h | 17 ++++++ net/net.c | 156 ++++++++++++++++++++++++++++++++++++++++++++++++++-------- net/tftp.c | 22 ++++++++ net/tftp.h | 10 +++ 4 files changed, 185 insertions(+), 20 deletions(-)
include/net.h +17 -0
@@ -200,6 +200,13 @@ typedef struct {ushort udp_xsum;/* Checksum */ } IP_t; +#define IP_OFFS 0x1FFF/* ip offset *= 8 */ +#define IP_OFFS_SHIFT 3/* in 8 byte steps */ +#define IP_FLAGS 0xE000/* first 3 bits */ +#define IP_FLAGS_RES 0x8000/* reserved */ +#define IP_FLAGS_DFRAG 0x4000/* don't fragments */ +#define IP_FLAGS_MFRAG 0x2000/* more fragments */ +#define IP_HDR_SIZE_NO_UDP (sizeof (IP_t) - 8)#define IP_HDR_SIZE (sizeof (IP_t))
@@ -282,6 +289,16 @@ typedef struct icmphdr {#define PKTSIZE_ALIGN 1536/*#define PKTSIZE 608*/ +/* +* IP/UDP Fragmentation support +* See: http://en.wikipedia.org/wiki/IPv4#Fragmentation_and_reassembly +* MAX possible UDP packet size is 64 KiB, if there is memory available. +*/ +#define NET_ETH_MTU 1500 +#define NET_FRAG_BUF_SIZE (16 * 1024)/* MAX is 64 KiB */ +#define NET_UDP_FRAG_SIZE (NET_ETH_MTU - IP_HDR_SIZE_NO_UDP)/* 1480 */ +#define NET_FRAG_BUF_USED (NET_FRAG_BUF_SIZE / NET_UDP_FRAG_SIZE + 1) +/* * Maximum receive ring size; that is, the number of packets * we can buffer before overflow happens. Basically, this just
net/net.c +136 -20
201 lines not on this page · raw message
net/tftp.c +22 -0
@@ -456,6 +456,7 @@ TftpTimeout (void)void TftpStart (void ) { +char *s, *err;#ifdef CONFIG_TFTP_PORT char *ep;/* Environment pointer */ #endif
@@ -518,6 +519,27 @@ TftpStart (void)puts ("Loading: *\b" ); +/* Get alternate tftp_block_size */ +if ((s =getenv ("tftp_block_size" )) !=NULL ) { + err =NULL ; + + TftpBlkSizeOption =simple_strtoul (s, &err,10 ); +if (*err) { +printf ("ERR: \"tftp_block_size\" is not a number\n" ); + TftpBlkSizeOption =TFTP_BLOCK_SIZE ; + } +/* +* Reject values which require extensive handling. +* block size of 1428 octets (Ethernet MTU, less +* the TFTP, UDP and IP header lengths). +*/ +if (TftpBlkSizeOption >TFTP_BLOCK_SIZE_MAX ) { +printf ("ERR: tftp_block_sizes larger than %d not " +"supported\n" ,TFTP_BLOCK_SIZE_MAX ); + TftpBlkSizeOption =TFTP_BLOCK_SIZE ; + } + } +NetSetTimeout (TIMEOUT *CFG_HZ , TftpTimeout);NetSetHandler (TftpHandler);
net/tftp.h +10 -0
@@ -8,11 +8,21 @@#ifndef __TFTP_H__#define __TFTP_H__ +#include <net.h> +/**********************************************************************/ /* * Global functions and variables. */ +/* +* Maximum TFTP block size bound to max size of fragmented IP/UDP +* packets minus TFTP and UDP/IP overhead. TFTP overhead is 2 byte +* opcode and 2 byte block-number. +*/ +#define TFTP_BLOCK_SIZE_MAX (NET_FRAG_BUF_SIZE - sizeof(IP_t) - 4) + +/* tftp.c */ extern void TftpStart (void );/* Begin TFTP get */
PATCH 1/1 Add simple IP/UDP fragmentation support
Quoted 11 lines · Josh Boyer
From: Frank Haverkamp <[email protected]>
http://tools.ietf.org/html/rfc2348 describes the TFTP block size option which allows larger packtes than the 512 byte default. This reduces the number of TFTP ACKs significantly and improves performance.
To get the most benefit out of the tftp block size option the support of defragementation of IP/UDP packet is helpful. The current implemenation should work even with packets received out of order. To enable the large packet size the user should set "
tftp_block_size" so a value like 16352.
Quoted 8 lines
We experimented with different packet sizes and found that more than those 16KiB do not contribute much to the performance anymore. Therefor I limited the defragmentation buffer to 16KiB no too waste memory.
Signed-off-by Frank Haverkamp <[email protected]>Signed-off-by Josh Boyer <[email protected]>---
Thanks. This looks like a good feature. I'll try to digest it tonight.
regards,
Ben
PATCH 1/1 Add simple IP/UDP fragmentation support
In reply to Josh BoyerHi Josh & Frank,
A few nits. Overall a nice patch.
One question: Will multicast TFTP still work when this is applied?
Quoted 5 lines · Josh Boyer
From: Frank Haverkamp <[email protected]>
http://tools.ietf.org/html/rfc2348 describes the TFTP block size option which allows larger packtes than the 512 byte default. This reduces the
s/packtes/packets/
Quoted 5 lines
number of TFTP ACKs significantly and improves performance.
To get the most benefit out of the tftp block size option the support of defragementation of IP/UDP packet is helpful. The current implemenation
s/defragementation/defragmentation/
s/implemenation/implementation/
Quoted 4 lines
should work even with packets received out of order. To enable the large packet size the user should set "
tftp_block_size" so a value like 16352.
s/so/to/
Quoted 3 lines
We experimented with different packet sizes and found that more than those 16KiB do not contribute much to the performance anymore. Therefor I limited
s/Therefor/Therefore/
Quoted 3 lines
the defragmentation buffer to 16KiB no too waste memory.
so as to not waste memory
Quoted 14 lines
Signed-off-by Frank Haverkamp <[email protected]>Signed-off-by Josh Boyer <[email protected]>--- include/net.h | 17 ++++++ net/net.c | 156 ++++++++++++++++++++++++++++++++++++++++++++++++++-------- net/tftp.c | 22 ++++++++ net/tftp.h | 10 +++ 4 files changed, 185 insertions(+), 20 deletions(-)include/net.h +0
-0@@ -200,6 +200,13 @@ typedef struct {ushort udp_xsum;/* Checksum */
include/net.h typedef struct { · line 210
Quoted 10 lines
include/net.h +7
-0} IP_t; +#define IP_OFFS 0x1FFF/* ip offset *= 8 */ +#define IP_OFFS_SHIFT 3/* in 8 byte steps */ +#define IP_FLAGS 0xE000/* first 3 bits */ +#define IP_FLAGS_RES 0x8000/* reserved */ +#define IP_FLAGS_DFRAG 0x4000/* don't fragments */ +#define IP_FLAGS_MFRAG 0x2000/* more fragments */ +
Please align these better. After applying, it's:
#define IP_OFFS 0x1FFF /* ip offset *= 8 */
#define IP_OFFS_SHIFT 3 /* in 8 byte steps */
#define IP_FLAGS 0xE000 /* first 3 bits */
#define IP_FLAGS_RES 0x8000 /* reserved */
#define IP_FLAGS_DFRAG 0x4000 /* don't fragments */
#define IP_FLAGS_MFRAG 0x2000 /* more fragments */
Quoted 54 lines
include/net.h +10
-0#define IP_HDR_SIZE_NO_UDP (sizeof (IP_t) - 8)#define IP_HDR_SIZE (sizeof (IP_t))@@ -282,6 +289,16 @@ typedef struct icmphdr {#define PKTSIZE_ALIGN 1536/*#define PKTSIZE 608*/ +/* +* IP/UDP Fragmentation support +* See: http://en.wikipedia.org/wiki/IPv4#Fragmentation_and_reassembly +* MAX possible UDP packet size is 64 KiB, if there is memory available. +*/ +#define NET_ETH_MTU 1500 +#define NET_FRAG_BUF_SIZE (16 * 1024)/* MAX is 64 KiB */ +#define NET_UDP_FRAG_SIZE (NET_ETH_MTU - IP_HDR_SIZE_NO_UDP)/* 1480 */ +#define NET_FRAG_BUF_USED (NET_FRAG_BUF_SIZE / NET_UDP_FRAG_SIZE + 1) +/* * Maximum receive ring size; that is, the number of packets * we can buffer before overflow happens. Basically, this just net/net.c +16
-0@@ -192,6 +192,15 @@ volatile uchar PktBuf[(PKTBUFSRX+1) * PKvolatile uchar *NetRxPackets[PKTBUFSRX ];/* Receive packets */ +/* Packet fragmentation support */ +static uint16_t ip_id =0 ;/* sequence number */ +static uint16_t udp_len =0 ; +static uint16_t udp_src =0 ; +static uint16_t udp_dst =0 ; +static int max_idx =0 ; +static uchar NetFragBuf[NET_FRAG_BUF_SIZE ]; +static char NetFragBufUsed[NET_FRAG_BUF_USED ] = {0 , }; +static rxhand_f *packetHandler;/* Current RX packet handler */ static thand_f *timeHandler;/* Current timeout handler */ static ulong timeStart;/* Time base value */ @@ -288,6 +297,13 @@ NetLoop(proto_t protocol) {bd_t *bd = gd->bd; +/* Packet fragmentation support */ + ip_id = udp_len = udp_src = udp_dst = max_idx =0 ; +memset (NetFragBuf,0xFF ,sizeof (NetFragBuf)); +memset (NetFragBufUsed,0 ,sizeof (NetFragBufUsed)); +printf ("NetFragBuf @ %08x max tftp_block_size=%d udp_frag_size=%d\n" , + NetFragBuf,TFTP_BLOCK_SIZE_MAX ,NET_UDP_FRAG_SIZE ); +#ifdef CONFIG_NET_MULTI NetRestarted =0 ; NetDevExists =0 ;@@ -1150,6 +1166,39 @@ static void CDPStart(void) }
net/net.c static void CDPStart(void) · line 1176
Quoted 10 lines
net/net.c +7
-0#endif +#ifdef CONFIG_UDP_CHECKSUM +/* +* @sumptr: Points to UDP data +* @sumlen: Size of UDP data +* @xsum: UDP checksum across IP source, destination address, protocol and size +* +* Returns 0 when checksum is correct and 1 if it is not
Can you return -1 on failure? Not a big deal, just more conventional.
Quoted 30 lines
net/net.c +26
-0+*/ +static int udp_checksum (ushort *sumptr,ushort sumlen,ulong xsum) +{ +while (sumlen >1 ) { +ushort sumdata; + + sumdata = *sumptr++; + xsum +=ntohs (sumdata); + sumlen -=2 ; + } +if (sumlen >0 ) { +ushort sumdata; + + sumdata = *(unsigned char *) sumptr; + sumdata = (sumdata <<8 ) &0xff00 ; + xsum += sumdata; + } +while ((xsum >>16 ) !=0 ) { + xsum = (xsum &0x0000ffff ) + ((xsum >>16 ) &0x0000ffff ); + } +if ((xsum !=0x00000000 ) && (xsum !=0x0000ffff )) +return 1 ; + +return 0 ; +} +#endif /* CONFIG_UDP_CHECKSUM */ void
NetReceive(volatile uchar * inpkt, int len)
net/net.c NetReceive(volatile uchar * inpkt, int l · line 1217
Quoted 5 lines
net/net.c +1
-0@@ -1164,6 +1213,7 @@ NetReceive(volatile uchar * inpkt, int lint iscdp;#endif ushort cti =0 , vlanid =VLAN_NONE , myvlanid, mynvlanid; +uint32_t off;/* ip_off for fragmentation */
Can you pick a better variable name than 'off'? 'offset' maybe?
net/net.c NetReceive(volatile uchar * inpkt, int l · line 1462
Quoted 13 lines
net/net.c +2
-0#ifdef ET_DEBUG printf ("packet received\n" );@@ -1404,9 +1454,11 @@ NetReceive(volatile uchar * inpkt, int lif ((ip->ip_hl_v &0xf0 ) !=0x40 ) {return ; } +#if 0 /* Obsolete after adding the fragmentation support */ if (ip->ip_off &htons (0x1fff )) {/* Can't deal w/ fragments */ return ; } +#endif
Please delete this block if it's now dead code.
Quoted 37 lines
net/net.c +0
-0/* can't deal with headers > 20 bytes */ if ((ip->ip_hl_v &0x0f ) >0x05 ) {net/net.c +30
-0return ;@@ -1422,6 +1474,88 @@ NetReceive(volatile uchar * inpkt, int l#endif return ; } + +/* +* Fragmentation support. We need to check the ip_id +* and if all fragments were received correctly. +*/ + off = (ntohs (ip->ip_off) &IP_OFFS ) <<IP_OFFS_SHIFT ; +if ((off !=0 ) || (ip->ip_off &htons (IP_FLAGS_MFRAG ))) { +int size, idx, complete; +char *start; + +/* New fragmented packet arrived, clear data. */ +if (ntohs (ip->ip_id) != ip_id) { + ip_id =ntohs (ip->ip_id); +memset (NetFragBufUsed,0 ,sizeof (NetFragBufUsed)); + udp_len = udp_src = udp_dst = max_idx =0 ; + } + + idx = off /NET_UDP_FRAG_SIZE ; + +/* Packet does not fit into IP/UDP fragmentation buf */ +if (idx >=NET_FRAG_BUF_USED ) { +return ; + } + + NetFragBufUsed[idx] =1 ; + +/* Copy the UDP hdr with the data for 1st +fragment, else copy just payload */ +if (off ==0 ) { + udp_len =ntohs (ip->udp_len);
net/net.c NetReceive(volatile uchar * inpkt, int l · line 1516
Quoted 10 lines
net/net.c +9
-0+ udp_src =ntohs (ip->udp_src); + udp_dst =ntohs (ip->udp_dst); + } + size =ntohs (ip->ip_len) -IP_HDR_SIZE_NO_UDP ; + start = (char *)ip +IP_HDR_SIZE_NO_UDP ; +memcpy (NetFragBuf + off, start, size); + +/* +* When last fragement has been received we
s/fragement/fragment/
Quoted 31 lines
net/net.c +31
-0+* know the number of fragments we expect. If +* all have arrived we process the packet. +*/ +if (((off !=0 ) && !(ip->ip_off &htons (IP_FLAGS_MFRAG )))) + max_idx = idx; + +if (max_idx ==0 ) +return ; + + complete =1 ; +for (idx =0 ; idx < max_idx; idx++) { +if (NetFragBufUsed[idx] ==0 ) { + complete =0 ; +break ; + } + } +if (!complete) +return ; +#ifdef CONFIG_UDP_CHECKSUM +if (ip->udp_xsum !=0 ) { +ulong xsum = ip->ip_p; +uint16_t *sumptr; + + xsum += udp_len; + xsum += (ntohl (ip->ip_src) >>16 ) &0xffff ; + xsum += (ntohl (ip->ip_src) >>0 ) &0xffff ; + xsum += (ntohl (ip->ip_dst) >>16 ) &0xffff ; + xsum += (ntohl (ip->ip_dst) >>0 ) &0xffff ; + sumptr = (ushort *)NetFragBuf; + +if (udp_checksum (sumptr, udp_len, xsum)) {
net/net.c NetReceive(volatile uchar * inpkt, int l
Quoted 10 lines
net/net.c +9
-0+putc ('U' ); + return; + } + } +#endif /* CONFIG_UDP_CHECKSUM */ + (*packetHandler)(NetFragBuf +8 , + udp_dst, + udp_src, + udp_len -8 );
Can some of these arguments share lines?
Quoted 46 lines
net/net.c +3
-0+return ; + } +/* net/net.c +2
-20* watch for ICMP host redirects * @@ -1502,26 +1636,8 @@ NetReceive(volatile uchar * inpkt, int l sumlen =ntohs (ip->udp_len); sumptr = (ushort *) &(ip->udp_src); -while (sumlen >1 ) { -ushort sumdata; - - sumdata = *sumptr++; - xsum +=ntohs (sumdata); - sumlen -=2 ; - } -if (sumlen >0 ) { -ushort sumdata; - - sumdata = *(unsigned char *) sumptr; - sumdata = (sumdata <<8 ) &0xff00 ; - xsum += sumdata; - } -while ((xsum >>16 ) !=0 ) { - xsum = (xsum &0x0000ffff ) + ((xsum >>16 ) &0x0000ffff ); - } -if ((xsum !=0x00000000 ) && (xsum !=0x0000ffff )) { -printf (" UDP wrong checksum %08lx %08x\n" , - xsum,ntohs (ip->udp_xsum)); +if (udp_checksum (sumptr, sumlen, xsum)) { +putc ('U' );return ; } }net/tftp.c +1
-0@@ -456,6 +456,7 @@ TftpTimeout (void)void TftpStart (void ) { +char *s, *err;#ifdef CONFIG_TFTP_PORT char *ep;/* Environment pointer */ #endif
net/tftp.c TftpStart (void) · line 524
Quoted 6 lines
net/tftp.c +2
-0@@ -518,6 +519,27 @@ TftpStart (void)puts ("Loading: *\b" ); +/* Get alternate tftp_block_size */ +if ((s =getenv ("tftp_block_size" )) !=NULL ) {
Kind of a long environment variable name. Maybe "tftp_bs"?
Quoted 38 lines
net/tftp.c +19
-0+ err =NULL ; + + TftpBlkSizeOption =simple_strtoul (s, &err,10 ); +if (*err) { +printf ("ERR: \"tftp_block_size\" is not a number\n" ); + TftpBlkSizeOption =TFTP_BLOCK_SIZE ; + } +/* +* Reject values which require extensive handling. +* block size of 1428 octets (Ethernet MTU, less +* the TFTP, UDP and IP header lengths). +*/ +if (TftpBlkSizeOption >TFTP_BLOCK_SIZE_MAX ) { +printf ("ERR: tftp_block_sizes larger than %d not " +"supported\n" ,TFTP_BLOCK_SIZE_MAX ); + TftpBlkSizeOption =TFTP_BLOCK_SIZE ; + } + } +NetSetTimeout (TIMEOUT *CFG_HZ , TftpTimeout);NetSetHandler (TftpHandler);net/tftp.h +3
-0@@ -8,11 +8,21 @@#ifndef __TFTP_H__#define __TFTP_H__ +#include <net.h> +/**********************************************************************/ /* * Global functions and variables. */ +/*
net/tftp.h line 28
Quoted 10 lines
net/tftp.h +7
-0+* Maximum TFTP block size bound to max size of fragmented IP/UDP +* packets minus TFTP and UDP/IP overhead. TFTP overhead is 2 byte +* opcode and 2 byte block-number. +*/ +#define TFTP_BLOCK_SIZE_MAX (NET_FRAG_BUF_SIZE - sizeof(IP_t) - 4) + +/* tftp.c */ extern void TftpStart (void );/* Begin TFTP get */
regards,
Ben
PATCH 1/1 Add simple IP/UDP fragmentation support
Subject: U-Boot: Add simple IP/UDP fragmentation support
From: Frank Haverkamp <[email protected]>
http://tools.ietf.org/html/rfc2348 describes the TFTP block size option which allows larger packets than the 512 byte default. This reduces the number of TFTP ACKs significantly and improves performance.
To get the most benefit out of the tftp block size option the support of defragmentation of IP/UDP packet is helpful. The current implementation
should work even with packets received out of order. To enable the large packet size the user should set "tftp_bsize" to a value like 16352.
We experimented with different packet sizes and found that more than those
16KiB do not contribute much to the performance anymore. Therefore I limited
the defragmentation buffer to 16KiB as not to not waste memory.
Multicast TFTP is not yet tested with this patch. Would be nice if someone who has set this up could give it a try.
--- include/net.h | 17 ++++++ net/net.c | 155 +++++++++++++++++++++++++++++++++++++++++++++++++--------- net/tftp.c | 22 ++++++++ net/tftp.h | 10 +++ 4 files changed, 182 insertions(+), 22 deletions(-)
include/net.h +11 -0
@@ -200,6 +200,13 @@ typedef struct {ushort udp_xsum;/* Checksum */ } IP_t; +#define IP_OFFS 0x1FFF/* ip offset *= 8 */ +#define IP_OFFS_SHIFT 3/* in 8 byte steps */ +#define IP_FLAGS 0xE000/* first 3 bits */ +#define IP_FLAGS_RES 0x8000/* reserved */ +#define IP_FLAGS_DFRAG 0x4000/* don't fragments */ +#define IP_FLAGS_MFRAG 0x2000/* more fragments */ +#define IP_HDR_SIZE_NO_UDP (sizeof (IP_t) - 8)#define IP_HDR_SIZE (sizeof (IP_t))
@@ -282,6 +289,16 @@ typedef struct icmphdr {#define PKTSIZE_ALIGN 1536/*#define PKTSIZE 608*/ +/* +* IP/UDP Fragmentation support +* See: http://en.wikipedia.org/wiki/IPv4#Fragmentation_and_reassembly +* MAX possible UDP packet size is 64 KiB, if there is memory
available.
+ */
+#define NET_ETH_MTU 1500
+#define NET_FRAG_BUF_SIZE (16 * 1024) /* MAX is 64 KiB */
+#define NET_UDP_FRAG_SIZE (NET_ETH_MTU - IP_HDR_SIZE_NO_UDP) /* 1480 */
+#define NET_FRAG_BUF_USED (NET_FRAG_BUF_SIZE / NET_UDP_FRAG_SIZE + 1)
+
/*
* Maximum receive ring size; that is, the number of packets
* we can buffer before overflow happens. Basically, this just
net/net.c +21 -0
@@ -192,6 +192,15 @@ volatile uchar PktBuf[(PKTBUFSRX+1) * PKvolatile uchar *NetRxPackets[PKTBUFSRX ];/* Receive packets */ +/* Packet fragmentation support */ +static uint16_t ip_id =0 ;/* sequence number */ +static uint16_t udp_len =0 ; +static uint16_t udp_src =0 ; +static uint16_t udp_dst =0 ; +static int max_idx =0 ; +static uchar NetFragBuf[NET_FRAG_BUF_SIZE ]; +static char NetFragBufUsed[NET_FRAG_BUF_USED ] = {0 , }; +static rxhand_f *packetHandler;/* Current RX packet handler */ static thand_f *timeHandler;/* Current timeout handler */ static ulong timeStart;/* Time base value */
@@ -288,6 +297,13 @@ NetLoop(proto_t protocol) {bd_t *bd = gd->bd; +/* Packet fragmentation support */ + ip_id = udp_len = udp_src = udp_dst = max_idx =0 ; +memset (NetFragBuf,0xFF ,sizeof (NetFragBuf)); +memset (NetFragBufUsed,0 ,sizeof (NetFragBufUsed)); +printf ("NetFragBuf @ %08x max tftp_bsize=%d udp_frag_size=%d\n" , + NetFragBuf,TFTP_BLOCK_SIZE_MAX ,NET_UDP_FRAG_SIZE ); +#ifdef CONFIG_NET_MULTI NetRestarted =0 ; NetDevExists =0 ;
@@ -1150,6 +1166,39 @@ static void CDPStart(void) }#endif +#ifdef CONFIG_UDP_CHECKSUM +/* +* @sumptr: Points to UDP data +* @sumlen: Size of UDP data +* @xsum: UDP checksum across IP source, destination address, protocol
and size
+ *
+ * Returns 0 when checksum is correct and -1 if it is not.
+ */
+static int udp_checksum(ushort *sumptr, ushort sumlen, ulong xsum) +{
+ while (sumlen > 1) {
+ ushort sumdata;
+
+ sumdata = *sumptr++; + xsum += ntohs(sumdata); + sumlen -= 2;
+ }
+ if (sumlen > 0) {
+ ushort sumdata;
+
+ sumdata = *(unsigned char *) sumptr; + sumdata = (sumdata << 8) & 0xff00; + xsum += sumdata;
+ }
+ while ((xsum >> 16) != 0) {
+ xsum = (xsum & 0x0000ffff) + ((xsum >> 16) & 0x0000ffff);
+ }
+ if ((xsum != 0x00000000) && (xsum != 0x0000ffff))
+ return -1;
+
+ return 0;
+}
+#endif /* CONFIG_UDP_CHECKSUM */
void
NetReceive(volatile uchar * inpkt, int len)
@@ -1164,6 +1213,7 @@ NetReceive(volatile uchar * inpkt, int l
int iscdp;
#endif
ushort cti = 0, vlanid = VLAN_NONE, myvlanid, mynvlanid;
+ uint32_t ip_off; /* ip_off for fragmentation */
#ifdef ET_DEBUG
printf("packet received\n");
@@ -1404,9 +1454,7 @@ NetReceive(volatile uchar * inpkt, int l
if ((ip->ip_hl_v & 0xf0) != 0x40) {
return;
}
- if (ip->ip_off & htons(0x1fff)) { /* Can't deal w/ fragments */
- return;
- }
+
/* can't deal with headers > 20 bytes */ if ((ip->ip_hl_v & 0x0f) > 0x05) {
return;
@@ -1422,6 +1470,86 @@ NetReceive(volatile uchar * inpkt, int l
#endif
return;
}
+
+ /*
+ * Fragmentation support. We need to check the ip_id
+ * and if all fragments were received correctly.
+ */
+ ip_off = (ntohs(ip->ip_off) & IP_OFFS) << IP_OFFS_SHIFT;
+ if ((ip_off != 0) || (ip->ip_off & htons(IP_FLAGS_MFRAG))) {
+ int size, idx, complete;
+ char *start;
+
+ /* New fragmented packet arrived, clear data. */
+ if (ntohs(ip->ip_id) != ip_id) {
+ ip_id = ntohs(ip->ip_id);
+ memset(NetFragBufUsed, 0, sizeof(NetFragBufUsed));
+ udp_len = udp_src = udp_dst = max_idx = 0;
+ }
+
+ idx = ip_off / NET_UDP_FRAG_SIZE;
+
+ /* Packet does not fit into IP/UDP fragmentation buf */
+ if (idx >= NET_FRAG_BUF_USED) {
+ return;
+ }
+
+ NetFragBufUsed[idx] = 1;
+
+ /* Copy the UDP hdr with the data for 1st
+ fragment, else copy just payload */
+ if (ip_off == 0) {
+ udp_len = ntohs(ip->udp_len);
+ udp_src = ntohs(ip->udp_src);
+ udp_dst = ntohs(ip->udp_dst);
+ }
+ size = ntohs(ip->ip_len) - IP_HDR_SIZE_NO_UDP;
+ start = (char *)ip + IP_HDR_SIZE_NO_UDP;
+ memcpy(NetFragBuf + ip_off, start, size);
+
+ /*
+ * When last fragment has been received we
+ * know the number of fragments we expect. If
+ * all have arrived we process the packet.
+ */
+ if (((ip_off != 0) && !(ip->ip_off & htons(IP_FLAGS_MFRAG))))
+ max_idx = idx;
+
+ if (max_idx == 0)
+ return;
+
+ complete = 1;
+ for (idx = 0; idx < max_idx; idx++) {
+ if (NetFragBufUsed[idx] == 0) {
+ complete = 0;
+ break;
+ }
+ }
+ if (!complete)
+ return;
+#ifdef CONFIG_UDP_CHECKSUM
+ if (ip->udp_xsum != 0) {
+ ulong xsum = ip->ip_p;
+ uint16_t *sumptr;
+
+ xsum += udp_len;
+ xsum += (ntohl(ip->ip_src) >> 16) & 0xffff;
+ xsum += (ntohl(ip->ip_src) >> 0) & 0xffff;
+ xsum += (ntohl(ip->ip_dst) >> 16) & 0xffff;
+ xsum += (ntohl(ip->ip_dst) >> 0) & 0xffff;
+ sumptr = (ushort *)NetFragBuf;
+
+ if (udp_checksum(sumptr, udp_len, xsum)) {
+ putc('U');
+ return;
+ }
+ }
+#endif /* CONFIG_UDP_CHECKSUM */
+ (*packetHandler)(NetFragBuf + 8, udp_dst, udp_src,
+ udp_len - 8);
+ return;
+ }
+
/*
* watch for ICMP host redirects
*
@@ -1502,26 +1630,9 @@ NetReceive(volatile uchar * inpkt, int l
sumlen = ntohs(ip->udp_len); sumptr = (ushort *) &(ip->udp_src);
- while (sumlen > 1) {
- ushort sumdata;
-
- sumdata = *sumptr++;
- xsum += ntohs(sumdata);
- sumlen -= 2;
- }
- if (sumlen > 0) {
- ushort sumdata;
- sumdata = *(unsigned char *) sumptr;
- sumdata = (sumdata << 8) & 0xff00;
- xsum += sumdata;
- }
- while ((xsum >> 16) != 0) {
- xsum = (xsum & 0x0000ffff) + ((xsum >> 16) & 0x0000ffff);
- }
- if ((xsum != 0x00000000) && (xsum != 0x0000ffff)) {
- printf(" UDP wrong checksum %08lx %08x\n",
- xsum, ntohs(ip->udp_xsum));
+ if (udp_checksum(sumptr, sumlen, xsum)) {
+ putc('U');
return;
}
}
net/tftp.c +22 -0
@@ -456,6 +456,7 @@ TftpTimeout (void)void TftpStart (void ) { +char *s, *err;#ifdef CONFIG_TFTP_PORT char *ep;/* Environment pointer */ #endif
@@ -518,6 +519,27 @@ TftpStart (void)puts ("Loading: *\b" ); +/* Get alternate tftp_bsize */ +if ((s =getenv ("tftp_bsize" )) !=NULL ) { + err =NULL ; + + TftpBlkSizeOption =simple_strtoul (s, &err,10 ); +if (*err) { +printf ("ERR: \"tftp_bsize\" is not a number\n" ); + TftpBlkSizeOption =TFTP_BLOCK_SIZE ; + } +/* +* Reject values which require extensive handling. +* block size of 1428 octets (Ethernet MTU, less +* the TFTP, UDP and IP header lengths). +*/ +if (TftpBlkSizeOption >TFTP_BLOCK_SIZE_MAX ) { +printf ("ERR: tftp_bsize larger than %d not supported\n" , +TFTP_BLOCK_SIZE_MAX ); + TftpBlkSizeOption =TFTP_BLOCK_SIZE ; + } + } +NetSetTimeout (TIMEOUT *CFG_HZ , TftpTimeout);NetSetHandler (TftpHandler);
net/tftp.h +10 -0
@@ -8,11 +8,21 @@#ifndef __TFTP_H__#define __TFTP_H__ +#include <net.h> +/**********************************************************************/ /* * Global functions and variables. */ +/* +* Maximum TFTP block size bound to max size of fragmented IP/UDP +* packets minus TFTP and UDP/IP overhead. TFTP overhead is 2 byte +* opcode and 2 byte block-number. +*/ +#define TFTP_BLOCK_SIZE_MAX (NET_FRAG_BUF_SIZE - sizeof(IP_t) - 4) + +/* tftp.c */ extern void TftpStart (void );/* Begin TFTP get */
Signature · 8 lines
IBM Systems & Technology Group, Integrated Systems Development / Open Systems Firmware Development, IBM Deutschland Schoenaicher Str. 220 71032 Boeblingen Phone: +49-7031-16-5133 E-Mail: haverkam at de.ibm.com IBM Deutschland Research & Development GmbH / Vorsitzender des Aufsichtsrats: Martin Jetter, Gesch?ftsf?hrung: Erich Baier, Sitz der Gesellschaft: B?blingen / Registergericht: Amtsgericht Stuttgart, HRB 243294
PATCH 1/1 Add simple IP/UDP fragmentation support
Dear Ben,
Quoted 2 lines · In message <1220460631.17453.3.camel@august> Frank Haverkamp wrote:
Subject: U-Boot: Add simple IP/UDP fragmentation support
From: Frank Haverkamp <[email protected]>
You replied:
| I know you guys posted this one a couple of months ago and I apologize | for not being more active. I've put this in the net/testing repo with | the hope that people will smack it around a bit.
What to do with this now?
Best regards,
Wolfgang Denk
Signature · 5 lines
DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de Philosophy is a game with objectives and no rules. Mathematics is a game with rules and no objectives.
PATCH 1/1 Add simple IP/UDP fragmentation support
Quoted 14 lines · Wolfgang Denk
Dear Ben,
Quoted 3 lines · In message <1220460631.17453.3.camel@august> Frank Haverkamp wrote:
Subject: U-Boot: Add simple IP/UDP fragmentation support
From: Frank Haverkamp <[email protected]>You replied:
| I know you guys posted this one a couple of months ago and I apologize | for not being more active. I've put this in the net/testing repo with | the hope that people will smack it around a bit.
Quoted 7 lines
What to do with this now?
Best regards,
Wolfgang Denk
We may as well pull it in. I have quite a bit of net-related stuff in the next few days and will include this patch.
regards,
Ben
PATCH 1/1 Add simple IP/UDP fragmentation support
In reply to Josh BoyerHi Josh,
Quoted 11 lines · Josh Boyer
From: Frank Haverkamp <[email protected]>
http://tools.ietf.org/html/rfc2348 describes the TFTP block size option which allows larger packtes than the 512 byte default. This reduces the number of TFTP ACKs significantly and improves performance.
To get the most benefit out of the tftp block size option the support of defragementation of IP/UDP packet is helpful. The current implemenation should work even with packets received out of order. To enable the large packet size the user should set "
tftp_block_size" so a value like 16352.
Quoted 7 lines
We experimented with different packet sizes and found that more than those 16KiB do not contribute much to the performance anymore. Therefor I limited the defragmentation buffer to 16KiB no too waste memory.
Signed-off-by Frank Haverkamp <[email protected]>Signed-off-by Josh Boyer <[email protected]>
I know you guys posted this one a couple of months ago and I apologize for not being more active. I've put this in the net/testing repo with the hope that people will smack it around a bit.
regards,
Ben
PATCH 1/1 Add simple IP/UDP fragmentation support
In reply to Josh BoyerJosh & Frank,
Sorry again for dropping the ball on this one. This is a useful feature that we should add to U-boot, but I'm concerned about the memory footprint.
Quoted 63 lines · Josh Boyer
From: Frank Haverkamp <[email protected]>
http://tools.ietf.org/html/rfc2348 describes the TFTP block size option which allows larger packtes than the 512 byte default. This reduces the number of TFTP ACKs significantly and improves performance.
To get the most benefit out of the tftp block size option the support of defragementation of IP/UDP packet is helpful. The current implemenation should work even with packets received out of order. To enable the large packet size the user should set "
tftp_block_size" so a value like 16352.We experimented with different packet sizes and found that more than those 16KiB do not contribute much to the performance anymore. Therefor I limited the defragmentation buffer to 16KiB no too waste memory.
Signed-off-by Frank Haverkamp <[email protected]>Signed-off-by Josh Boyer <[email protected]>--- include/net.h | 17 ++++++ net/net.c | 156 ++++++++++++++++++++++++++++++++++++++++++++++++++-------- net/tftp.c | 22 ++++++++ net/tftp.h | 10 +++ 4 files changed, 185 insertions(+), 20 deletions(-)include/net.h +17
-0@@ -200,6 +200,13 @@ typedef struct {ushort udp_xsum;/* Checksum */ } IP_t; +#define IP_OFFS 0x1FFF/* ip offset *= 8 */ +#define IP_OFFS_SHIFT 3/* in 8 byte steps */ +#define IP_FLAGS 0xE000/* first 3 bits */ +#define IP_FLAGS_RES 0x8000/* reserved */ +#define IP_FLAGS_DFRAG 0x4000/* don't fragments */ +#define IP_FLAGS_MFRAG 0x2000/* more fragments */ +#define IP_HDR_SIZE_NO_UDP (sizeof (IP_t) - 8)#define IP_HDR_SIZE (sizeof (IP_t))@@ -282,6 +289,16 @@ typedef struct icmphdr {#define PKTSIZE_ALIGN 1536/*#define PKTSIZE 608*/ +/* +* IP/UDP Fragmentation support +* See: http://en.wikipedia.org/wiki/IPv4#Fragmentation_and_reassembly +* MAX possible UDP packet size is 64 KiB, if there is memory available. +*/ +#define NET_ETH_MTU 1500 +#define NET_FRAG_BUF_SIZE (16 * 1024)/* MAX is 64 KiB */ +#define NET_UDP_FRAG_SIZE (NET_ETH_MTU - IP_HDR_SIZE_NO_UDP)/* 1480 */ +#define NET_FRAG_BUF_USED (NET_FRAG_BUF_SIZE / NET_UDP_FRAG_SIZE + 1) +/* * Maximum receive ring size; that is, the number of packets * we can buffer before overflow happens. Basically, this just net/net.c +0
-0@@ -192,6 +192,15 @@ volatile uchar PktBuf[(PKTBUFSRX+1) * PK
net/net.c volatile uchar PktBuf[(PKTBUFSRX+1) * PK · line 202
Quoted 10 lines
net/net.c +7
-0volatile uchar *NetRxPackets[PKTBUFSRX ];/* Receive packets */ +/* Packet fragmentation support */ +static uint16_t ip_id =0 ;/* sequence number */ +static uint16_t udp_len =0 ; +static uint16_t udp_src =0 ; +static uint16_t udp_dst =0 ; +static int max_idx =0 ; +static uchar NetFragBuf[NET_FRAG_BUF_SIZE ];
Allocating a 16k buffer should be optional. Please consider wrapping this feature in a CONFIG.
Quoted 6 lines
net/net.c +2
-0+static char NetFragBufUsed[NET_FRAG_BUF_USED ] = {0 , }; +static rxhand_f *packetHandler;/* Current RX packet handler */ static thand_f *timeHandler;/* Current timeout handler */ static ulong timeStart; /* Time base value */
net/net.c NetLoop(proto_t protocol) · line 306
Quoted 10 lines
net/net.c +6
-0@@ -288,6 +297,13 @@ NetLoop(proto_t protocol) {bd_t *bd = gd->bd; +/* Packet fragmentation support */ + ip_id = udp_len = udp_src = udp_dst = max_idx =0 ; +memset (NetFragBuf,0xFF ,sizeof (NetFragBuf)); +memset (NetFragBufUsed,0 ,sizeof (NetFragBufUsed)); +printf ("NetFragBuf @ %08x max tftp_block_size=%d udp_frag_size=%d\n" , + NetFragBuf,TFTP_BLOCK_SIZE_MAX ,NET_UDP_FRAG_SIZE );
I get a compiler warning here that a simple cast should fix:net.c: In function 'NetLoop':
net.c:300: warning: format '%08x' expects type 'unsigned int', but argument 2 has type 'uchar *'
regards,
Ben