[pptp-server] Packet reordering patch
Philip Van Baren
phil at vibrationresearch.com
Wed Sep 27 09:47:57 CDT 2000
I made a patch to pptpd-1.1.1 which implements a simple packet reordering
scheme. This made a huge difference on my network which has many
out-of-order packets.
Note that if in addition to your packet order problems you are getting
dropped packets and you have encryption enabled, you will still probably see
the message:
Sep 27 00:03:15 gateway pppd[10544]: rcvd [Compressed data] 10 32 ae 68 c0
8e e1 92 ...
in your log file after a packet gets dropped, after which the link seems to
lock up. The only way I have been able to solve this problem so far is to
disable encryption because pppd doesn't seem to recover from lost packets
when encryption is enabled.
Has anyone found a way to get pppd to recover nicely from lost packets when
using encryption?
(I am using this with pptpd-1.1.1 and pppd-2.3.11 and kernel 2.2.17)
Phil Van Baren
phil at vibrationresearch.com
Here is the patch to add packet reordering:
diff -u pptpd-1.1.1/pptpgre.c pptpd-1.1.1-reorder/pptpgre.c
--- pptpd-1.1.1/pptpgre.c Thu Dec 23 20:03:44 1999
+++ pptpd-1.1.1-reorder/pptpgre.c Wed Sep 27 09:36:20 2000
@@ -73,6 +73,7 @@
memset (gre, 0, sizeof (*gre));
reset_pty_to_gre (gre);
+ gre->seq_recv = -1;
/* Open IP protocol socket */
gre->gre_fd = socket(AF_INET, SOCK_RAW, PPTP_PROTO);
@@ -437,7 +438,8 @@
static int
read_gre (struct gre_state *gre)
{
- int status, offset=0;
+ int status, offset=0,i,j;
+ int recv_time;
unsigned char buffer[GRE_PACKET_SIZE + 64 /* ip header */];
struct gre_rcv_packet *recv_packet;
unsigned char *data;
@@ -449,10 +451,6 @@
memset (buffer, 0x66, sizeof(buffer));
status = read (gre->gre_fd, buffer, sizeof(buffer));
- recv_packet = &gre->window[(gre->gre_current_packet
- + gre->gre_num_packets) %
- (PCKT_RECV_WINDOW_SIZE + 1)];
-
if (status < 0) {
if (errno == EAGAIN || errno == EINTR) {
/*syslog (LOG_INFO, "GRE read() wants retry");*/
@@ -480,11 +478,9 @@
return 0;
}
- memset (recv_packet, 0x11, sizeof(*recv_packet));
- /* FIXME: Too much copying. Should just buffer the IP header. */
- memcpy (recv_packet, &buffer[offset], status);
-
+ recv_packet = (struct gre_rcv_packet *) (buffer+offset);
header = recv_packet->header;
+ recv_time = time(NULL);
/* Validate the packet. */
if ((ntoh8 (header.ver) & ~PPTP_GRE_FLAG_A) != PPTP_GRE_VER
@@ -532,7 +528,8 @@
if (has_payload) {
u_int32_t seq;
- if (gre->gre_num_packets >= PCKT_RECV_WINDOW_SIZE) {
+ /* Keep 8 packets of buffer room for packet reordering */
+ if (gre->gre_num_packets >= (PCKT_RECV_WINDOW_SIZE-PCKT_REORDER_SIZE))
{
syslog (LOG_ERR, "GRE: window overflowed. Dropping packet...");
return 1;
}
@@ -546,15 +543,10 @@
data = recv_packet->body.one.data;
}
- if (pptpctrl_debug && seq != gre->seq_recv + 1) {
- syslog (LOG_INFO, "Unexpected sequence number; got %u after %u",
- seq, gre->seq_recv);
- }
-
/* Check sequence number; discard if out of order */
if (!seq_less_than (gre->seq_recv, seq)) {
syslog (LOG_WARNING,
- "Discarding out-of-order packet %x, already have %x",
+ "Discarding out-of-order packet %u, already have %u",
seq, gre->seq_recv);
return 0;
}
@@ -568,8 +560,108 @@
return 0;
}
- gre->seq_recv = seq;
- gre->gre_num_packets++;
+ i=seq - gre->seq_recv - 1;
+
+ /* If this packet is beyond the reorder buffer,
+ * or if it has been 3 seconds size we last accepted a packet,
+ * stop waiting for the missing packet */
+ if ((i >= PCKT_REORDER_SIZE) || (recv_time >
(gre->gre_last_recv_time+PCKT_REORDER_WAIT_TIME)) ) {
+ if(gre->gre_num_packets > 0) {
+ /* There are still packets in the queue, so we can't skip packets yet */
+ if(pptpctrl_debug) {
+ syslog (LOG_INFO, "Dropping out-of-order packet; got %u after %u",
+ PCKT_REORDER_SIZE,seq, gre->seq_recv);
+ }
+ return 0;
+ }
+ /* Stop waiting for the oldest packet */
+ for(j=0 ; (j<PCKT_REORDER_SIZE) &&
(gre->window[(gre->gre_current_packet+j)%(PCKT_RECV_WINDOW_SIZE+1)].header.p
ayload_len == 0) ; j++);
+
+ /* Missing more than PCKT_REORDER_SIZE consecutive packets - just
ignore them and process this new packet */
+ if(pptpctrl_debug) {
+ if(recv_time > (gre->gre_last_recv_time+PCKT_REORDER_WAIT_TIME)) {
+ /* Hide this message on the first packet because it is meaningless */
+ if(gre->gre_last_recv_time != 0)
+ syslog (LOG_INFO, "Packet reorder timeout.");
+ } else if(j==PCKT_REORDER_SIZE) {
+ syslog (LOG_INFO, "Missing %d consecutive packets; got %u after %u",
+ PCKT_REORDER_SIZE,seq, gre->seq_recv);
+ } else {
+ syslog (LOG_INFO, "Exceeded packet reorder buffer size; got %u after
%u; skipping %d packets",
+ seq, gre->seq_recv,j);
+ }
+ }
+ if(j==PCKT_REORDER_SIZE) {
+
memcpy(&gre->window[gre->gre_current_packet],buffer+offset,status);
+ /*
+ if(pptpctrl_debug) {
+ syslog(LOG_INFO,"Filling packet buffer slot %d with packet
%u",gre->gre_current_packet,seq);
+ }
+ */
+ gre->seq_recv = seq;
+ gre->gre_num_packets++;
+ gre->gre_last_recv_time=recv_time;
+ return 1;
+ }
+
+ /* Else skip forward to the oldest previously received packet */
+ gre->gre_current_packet=(gre->gre_current_packet+j) %
(PCKT_RECV_WINDOW_SIZE+1);
+ gre->seq_recv += j;
+
+ i-=j;
+ }
+ /* Buffer the latest packet if it isn't too far ahead, else just drop
it */
+ if(i < PCKT_REORDER_SIZE) {
+ if(pptpctrl_debug && (i>0)) {
+ syslog (LOG_INFO, "Buffering out-of-order packet; got %u after %u",
+ seq, gre->seq_recv);
+ }
+
memcpy(&gre->window[(gre->gre_current_packet+gre->gre_num_packets+i) %
(PCKT_RECV_WINDOW_SIZE+1)],buffer+offset,status);
+ /*
+ if(pptpctrl_debug) {
+ syslog(LOG_INFO,"Filling packet buffer slot %d with packet %u
(curr=%d,n=%d,i=%d)",(gre->gre_current_packet+gre->gre_num_packets+i) %
(PCKT_RECV_WINDOW_SIZE+1),seq,gre->gre_current_packet,gre->gre_num_packets,i
);
+ }
+ */
+ } else if(pptpctrl_debug) {
+ syslog (LOG_INFO, "Dropping out-of-order packet %u",seq);
+ }
+
+ /* Skip lost packets if we get PCKT_REORDER_SIZE consecutive following
packets */
+
+ if((gre->gre_num_packets==0) &&
(gre->window[gre->gre_current_packet].header.payload_len == 0)) {
+ for(i=0,j=1;(i < (PCKT_REORDER_RESUME_SIZE)) &&
(j<PCKT_REORDER_SIZE);j++) {
+ if(gre->window[(gre->gre_current_packet+j) %
(PCKT_RECV_WINDOW_SIZE+1)].header.payload_len != 0) {
+ i++;
+ } else {
+ i=0;
+ }
+ }
+ if(i >= (PCKT_REORDER_RESUME_SIZE)) {
+ /* Advance counters over the lost packet(s) */
+ for(j=1 ; (j<PCKT_REORDER_SIZE) &&
(gre->window[(gre->gre_current_packet+j)%(PCKT_RECV_WINDOW_SIZE+1)].header.p
ayload_len == 0) ; j++);
+ if(pptpctrl_debug) {
+ syslog (LOG_INFO, "Gave up waiting for %d lost packets",j);
+ }
+
+ gre->gre_current_packet=(gre->gre_current_packet+j) %
(PCKT_RECV_WINDOW_SIZE+1);
+ gre->seq_recv += j;
+ }
+ }
+
+ /* Add all consecutive available packets to the queue */
+ for(j=0 ; (j<PCKT_REORDER_SIZE) &&
(gre->window[(gre->gre_current_packet+gre->gre_num_packets+j)%(PCKT_RECV_WIN
DOW_SIZE+1)].header.payload_len != 0) ; j++);
+ /*
+ if(pptpctrl_debug && (j>1)) {
+ syslog(LOG_INFO,"Adding %d packets to the queue",j);
+ }
+ */
+ gre->seq_recv += j;
+ gre->gre_num_packets += j;
+ if(j>0) {
+ gre->gre_last_recv_time = recv_time;
+ return 1;
+ }
+ return 0;
#if 0
/* Dump start of packet. */
@@ -578,7 +670,6 @@
status, data[0], data[1], data[2], data[3], data[4],
data[5], data[6]);
#endif
- return 1;
}
if (!has_payload && !has_ack)
@@ -627,8 +718,8 @@
packet = &gre->window[gre->gre_current_packet];
header = packet->header;
if (header.protocol != ntoh16(PPTP_GRE_PROTO)) {
- syslog (LOG_ERR, "INTERNAL ERROR: Bad protocol %x in gre_to_hdlc",
- ntoh16(header.protocol));
+ syslog (LOG_ERR, "INTERNAL ERROR: Bad protocol %x in gre_to_hdlc,
buffer slot %d",
+ ntoh16(header.protocol),gre->gre_current_packet);
}
data = (PPTP_GRE_IS_A (ntoh8 (header.ver))
@@ -656,8 +747,8 @@
gre->gre_current_packet = ((gre->gre_current_packet + 1)
% (PCKT_RECV_WINDOW_SIZE + 1));
- /* Fill packet with garbage */
- memset (packet, 0x33, sizeof (*packet));
+ /* Zero out the packet so the payload_len parameter is zero which
indicates this slot is empty */
+ memset (packet, 0x00, sizeof (*packet));
}
/* Send some stuff to the PTY. Return 1 if we wrote something, 0 if
diff -u pptpd-1.1.1/pptpgre.h pptpd-1.1.1-reorder/pptpgre.h
--- pptpd-1.1.1/pptpgre.h Thu Dec 23 16:43:33 1999
+++ pptpd-1.1.1-reorder/pptpgre.h Wed Sep 27 09:36:16 2000
@@ -14,6 +14,26 @@
#define GRE_PACKET_SIZE 2048
#define HDLC_PACKET_SIZE (2*GRE_PACKET_SIZE + 6)
+/* Variables to control the packet reordering scheme:
+ * PCKT_REORDER_SIZE
+ * this is the number of packets ahead of the current packet that
+ * will get buffered while waiting for a packet. If a new packet
+ * comes in more than this far ahead, we stop waiting for the missing
packet
+ *
+ * PCKT_REORDER_RESUME_SIZE
+ * if this many consecutive packets are available in the buffer
+ * while we are waiting for a lost packet, then we will stop waiting
+ * for the missing packet
+ *
+ * PCKT_REORDER_WAIT_TIME
+ * if a new packet comes in and this many seconds have expired since
+ * we last passed on a packet to pppd, then we will stop waiting
+ * for the missing packet
+ */
+#define PCKT_REORDER_SIZE 8
+#define PCKT_REORDER_RESUME_SIZE 4
+#define PCKT_REORDER_WAIT_TIME 3
+
enum gre_header_type { GRE_HEAD_ONE, GRE_HEAD_BOTH };
struct gre_xmit_packet {
@@ -72,6 +92,7 @@
struct gre_rcv_packet window[PCKT_RECV_WINDOW_SIZE+1];
int gre_current_packet;
int gre_num_packets;
+ int gre_last_recv_time;
/* PTY output state */
int pty_fd;
More information about the pptp-server
mailing list