From d5b577b2662ba7973ad73fc3692a7d8607f1035b Mon Sep 17 00:00:00 2001 From: Michael Blizek Date: Wed, 26 May 2010 18:46:52 +0200 Subject: [PATCH] kernel packet ack gen bugfix, empty retransmit queue on conn reset --- net/cor/common.c | 44 ++++++++++++++++++++++++-------------------- net/cor/cor.h | 2 ++ net/cor/kpacket_gen.c | 6 +++--- net/cor/kpacket_parse.c | 37 ++++++++++++++++++++++++------------- net/cor/snd.c | 49 +++++++++++++++++++++++++++++++++++++++++++------ 5 files changed, 96 insertions(+), 42 deletions(-) diff --git a/net/cor/common.c b/net/cor/common.c index 3f8feb22121..7ba96fd903c 100644 --- a/net/cor/common.c +++ b/net/cor/common.c @@ -201,29 +201,29 @@ int htable_delete(struct htable *ht, __u32 key, char **element; char **next; int rc = 0; - + if (unlikely(ht->htable == 0)) return 1; - + local_irq_save(iflags); - + element = get_element_nounlock(ht, key, searcheditem); BUG_ON(0 == element); - + if (unlikely(*element == 0)) { /* key not in table */ rc = 1; goto out; } - + next = next_element(ht, *element); kref_put(element_kref(ht, *element), free); *element = *next; - + out: unlock_element(ht, key); local_irq_restore(iflags); - + return rc; } @@ -231,21 +231,21 @@ void htable_insert(struct htable *ht, char *newelement, __u32 key) { unsigned long iflags; char **element; - + if (unlikely(ht->htable == 0)) return; - + BUG_ON(*next_element(ht, newelement) != 0); local_irq_save(iflags); - + element = get_element_nounlock(ht, key, 0); - + BUG_ON(element == 0); BUG_ON(*element != 0); - + *element = newelement; kref_get(element_kref(ht, newelement)); - + unlock_element(ht, key); local_irq_restore(iflags); } @@ -653,7 +653,7 @@ static int _reset_conn(struct conn *conn) int isreset = atomic_cmpxchg(&(conn->isreset), 0, 2); if (isreset == 1) isreset = atomic_cmpxchg(&(conn->isreset), 1, 2); - + if (isreset == 2 || isreset == 3) return 0; @@ -664,9 +664,9 @@ static int _reset_conn(struct conn *conn) mutex_lock(&(conn->source.in.nb->conn_list_lock)); list_del(&(conn->source.in.nb_list)); mutex_unlock(&(conn->source.in.nb->conn_list_lock)); - + krefput++; - + if (conn->source.in.conn_id != 0) { if (htable_delete(&connid_table, conn->source.in.conn_id, @@ -678,26 +678,30 @@ static int _reset_conn(struct conn *conn) } else if (conn->sourcetype == SOURCE_SOCK) { wake_up_interruptible(&(conn->source.sock.wait)); } - + if (conn->targettype == TARGET_OUT) { mutex_lock(&(conn->target.out.nb->conn_list_lock)); list_del(&(conn->target.out.nb_list)); mutex_unlock(&(conn->target.out.nb->conn_list_lock)); - + krefput++; - + if (isreset == 0 && conn->target.out.conn_id != 0) { struct control_msg_out *cm = alloc_control_msg(); if (likely(cm != 0)) send_reset_conn(cm, conn->target.out.nb, conn->target.out.conn_id); } + + cancel_retrans(conn); } else if (conn->targettype == TARGET_SOCK) { wake_up_interruptible(&(conn->target.sock.wait)); } + databuf_free(&(conn->buf)); + mutex_unlock(&(conn->rcv_lock)); - + return krefput; } diff --git a/net/cor/cor.h b/net/cor/cor.h index 921db9cf55e..6384f1f4aee 100644 --- a/net/cor/cor.h +++ b/net/cor/cor.h @@ -661,6 +661,8 @@ extern void parse(struct conn *rconn); extern struct sk_buff *create_packet(struct neighbor *nb, int size, gfp_t alloc_flags, __u32 conn_id, __u32 seqno); +extern void cancel_retrans(struct conn *rconn); + extern void retransmit_conn_timerfunc(struct work_struct *work); extern void conn_ack_rcvd(__u32 kpacket_seqno, struct conn *rconn, __u32 seqno, diff --git a/net/cor/kpacket_gen.c b/net/cor/kpacket_gen.c index ac857152827..4552f31dfa6 100644 --- a/net/cor/kpacket_gen.c +++ b/net/cor/kpacket_gen.c @@ -278,7 +278,7 @@ void kern_ack_rcvd(struct neighbor *nb, __u32 seqno) if (unlikely(htable_delete(&retransmits, rm_to_key(&rm), &rm, free_control_retrans))) BUG(); - + BUG_ON(cr->nb != nb); list_del(&(cr->timeout_list)); @@ -780,7 +780,7 @@ void send_ack(struct control_msg_out *cm, struct neighbor *nb, __u32 seqno) void send_ack_conn(struct control_msg_out *cm, struct neighbor *nb, __u32 conn_id, __u32 seqno, __u8 window) { - cm->type = MSGTYPE_ACK; + cm->type = MSGTYPE_ACK_CONN; cm->msg.ack_conn.conn_id = conn_id; cm->msg.ack_conn.seqno = seqno; cm->msg.ack_conn.window = window; @@ -793,7 +793,7 @@ void send_ack_conn_ooo(struct control_msg_out *cm, struct neighbor *nb, __u32 conn_id, __u32 seqno, __u8 window, __u32 seqno_ooo, __u32 length) { - cm->type = MSGTYPE_ACK; + cm->type = MSGTYPE_ACK_CONN_OOO; cm->msg.ack_conn_ooo.conn_id = conn_id; cm->msg.ack_conn_ooo.seqno = seqno; cm->msg.ack_conn_ooo.window = window; diff --git a/net/cor/kpacket_parse.c b/net/cor/kpacket_parse.c index caf627fa3db..cddf8ec4c46 100644 --- a/net/cor/kpacket_parse.c +++ b/net/cor/kpacket_parse.c @@ -207,20 +207,20 @@ static void parse_connect(struct neighbor *nb, struct sk_buff *skb) struct conn *rconn; __u32 conn_id = pull_u32(skb, 1); struct control_msg_out *cm = alloc_control_msg(); - + if (unlikely(cm == 0)) return; - + rconn = alloc_conn(GFP_KERNEL); - + if (unlikely(rconn == 0)) goto err; - + if (unlikely(conn_init_out(rconn->reversedir, nb))) goto err; rconn->reversedir->target.out.conn_id = conn_id; - + send_connect_success(cm, nb, rconn->reversedir->target.out.conn_id, rconn->source.in.conn_id); @@ -232,7 +232,7 @@ err: #warning todo set window on connect/connect_success static void kernel_packet2(struct neighbor *nb, struct sk_buff *skb, - __u32 seqno) + __u32 seqno1) { struct control_msg_out *cm = alloc_control_msg(); int ack = 0; @@ -242,6 +242,11 @@ static void kernel_packet2(struct neighbor *nb, struct sk_buff *skb, while (1) { struct control_msg_out *cm_tmp; + + __u32 seqno2; + + __u32 conn_id; + __u32 cookie; __u32 respdelay; @@ -270,16 +275,16 @@ static void kernel_packet2(struct neighbor *nb, struct sk_buff *skb, ack = 1; break; case KP_ACK: - seqno = pull_u32(skb, 1); - kern_ack_rcvd(nb, seqno); + seqno2 = pull_u32(skb, 1); + kern_ack_rcvd(nb, seqno2); break; case KP_ACK_CONN: - conn_cmd(nb, skb, seqno, code, parse_ack_conn, + conn_cmd(nb, skb, seqno1, code, parse_ack_conn, discard_ack_conn); ack = 1; break; case KP_ACK_CONN_OOO: - conn_cmd(nb, skb, seqno, code, parse_ack_conn_ooo, + conn_cmd(nb, skb, seqno1, code, parse_ack_conn_ooo, discard_ack_conn_ooo); ack = 1; break; @@ -288,7 +293,7 @@ static void kernel_packet2(struct neighbor *nb, struct sk_buff *skb, ack = 1; break; case KP_CONNECT_SUCCESS: - conn_cmd(nb, skb, seqno, code, parse_conn_success, + conn_cmd(nb, skb, seqno1, code, parse_conn_success, discard_conn_success); ack = 1; break; @@ -297,7 +302,12 @@ static void kernel_packet2(struct neighbor *nb, struct sk_buff *skb, ack = 1; break; case KP_RESET_CONN: - conn_cmd(nb, skb, seqno, code, parse_reset, 0); + conn_cmd(nb, skb, seqno1, code, parse_reset, 0); + ack = 1; + break; + case KP_CONNID_UNKNOWN: + conn_id = pull_u32(skb, 1); + #warning todo ack = 1; break; default: @@ -306,7 +316,7 @@ static void kernel_packet2(struct neighbor *nb, struct sk_buff *skb, } if (ack) - send_ack(cm, nb, seqno); + send_ack(cm, nb, seqno1); else free_control_msg(cm); } @@ -368,6 +378,7 @@ void kernel_packet(struct neighbor *nb, struct sk_buff *skb, __u32 seqno) goto discard; break; case KP_RESET_CONN: + case KP_CONNID_UNKNOWN: if (cor_pull_skb(skb2, 4) == 0) goto discard; break; diff --git a/net/cor/snd.c b/net/cor/snd.c index b690f16baab..095431059f2 100644 --- a/net/cor/snd.c +++ b/net/cor/snd.c @@ -227,6 +227,29 @@ out: return ret; } +/* rcvlock *must* be held while calling this */ +void cancel_retrans(struct conn *rconn) +{ + unsigned long iflags; + struct neighbor *nb = rconn->target.out.nb; + + spin_lock_irqsave( &(nb->retrans_lock), iflags ); + + while (list_empty(&(rconn->target.out.retrans_list)) == 0) { + struct conn_retrans *cr = container_of( + rconn->target.out.retrans_list.next, + struct conn_retrans, conn_list); + BUG_ON(cr->rconn != rconn); + + list_del(&(cr->timeout_list)); + list_del(&(cr->conn_list)); + cr->ackrcvd = 1; + kref_put(&(cr->ref), free_connretrans); + } + + spin_unlock_irqrestore( &(nb->retrans_lock), iflags ); +} + static void send_retrans(struct neighbor *nb, struct conn_retrans *cr) { int targetmss = mss(nb); @@ -237,6 +260,16 @@ static void send_retrans(struct neighbor *nb, struct conn_retrans *cr) int dontsend; mutex_lock(&(cr->rconn->rcv_lock)); + + BUG_ON(cr->rconn->targettype != TARGET_OUT); + BUG_ON(cr->rconn->target.out.nb != nb); + + kref_get(&(cr->rconn->ref)); + + if (unlikely(atomic_read(&(cr->rconn->isreset)) != 0)) { + cancel_retrans(cr->rconn); + goto out; + } while (cr->length >= targetmss) { struct sk_buff *skb; @@ -290,9 +323,10 @@ static void send_retrans(struct neighbor *nb, struct conn_retrans *cr) send_conndata(cm, nb, cr->rconn->target.out.conn_id, cr->seqno, buf, buf, cr->length); } - out: mutex_unlock(&(cr->rconn->rcv_lock)); + + kref_put(&(cr->rconn->ref), free_conn); } void retransmit_conn_timerfunc(struct work_struct *work) @@ -512,14 +546,17 @@ void flush_out(struct conn *rconn) { int targetmss = mss(rconn->target.out.nb); __u32 seqno; - + #warning todo honor window size - + BUG_ON(rconn->targettype != TARGET_OUT); - + if (unlikely(rconn->target.out.conn_id == 0)) return; + if (unlikely(atomic_read(&(rconn->isreset)) != 0)) + return; + while (rconn->buf.read_remaining >= targetmss) { struct sk_buff *skb; char *dst; @@ -541,7 +578,7 @@ void flush_out(struct conn *rconn) rconn->target.out.seqno_nextsend += targetmss; dev_queue_xmit(skb); } - + if (rconn->buf.read_remaining > 0) { struct control_msg_out *cm; __u32 len = rconn->buf.read_remaining; @@ -572,7 +609,7 @@ void flush_out(struct conn *rconn) } wake_sender(rconn); - + if (0) { oom: #warning todo flush later -- 2.11.4.GIT