summaryrefslogtreecommitdiffstats
path: root/sys/netinet
diff options
context:
space:
mode:
authorrrs <rrs@FreeBSD.org>2008-08-28 09:44:07 +0000
committerrrs <rrs@FreeBSD.org>2008-08-28 09:44:07 +0000
commita97a9f5233562046294f64d3db07ca1c90e63a35 (patch)
tree4a6ba48264c10107c71cdb81d7b311404516ea68 /sys/netinet
parent8ccd4bd3a18f0d73c17c7096b561febf5d6f93d8 (diff)
downloadFreeBSD-src-a97a9f5233562046294f64d3db07ca1c90e63a35.zip
FreeBSD-src-a97a9f5233562046294f64d3db07ca1c90e63a35.tar.gz
- Make strict-sacks be the default.
- Change it so that without INVARIANTs there are no panics in SCTP. - sctp_timer changes so that we have a recovery mechanism when the sent list is out of order.
Diffstat (limited to 'sys/netinet')
-rw-r--r--sys/netinet/sctp_indata.c11
-rw-r--r--sys/netinet/sctp_lock_bsd.h10
-rw-r--r--sys/netinet/sctp_output.c1
-rw-r--r--sys/netinet/sctp_sysctl.h2
-rw-r--r--sys/netinet/sctp_timer.c61
-rw-r--r--sys/netinet/sctp_var.h32
-rw-r--r--sys/netinet/sctputil.c15
7 files changed, 126 insertions, 6 deletions
diff --git a/sys/netinet/sctp_indata.c b/sys/netinet/sctp_indata.c
index 8a1d057..5e00d14 100644
--- a/sys/netinet/sctp_indata.c
+++ b/sys/netinet/sctp_indata.c
@@ -386,12 +386,21 @@ abandon:
if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
goto abandon;
} else {
+#ifdef INVARIANTS
if ((stcb->asoc.control_pdapi == NULL) || (stcb->asoc.control_pdapi->tail_mbuf == NULL)) {
panic("This should not happen control_pdapi NULL?");
}
/* if we did not panic, it was a EOM */
panic("Bad chunking ??");
- return;
+#else
+ if ((stcb->asoc.control_pdapi == NULL) || (stcb->asoc.control_pdapi->tail_mbuf == NULL)) {
+ SCTP_PRINTF("This should not happen control_pdapi NULL?\n");
+ }
+ SCTP_PRINTF("Bad chunking ??\n");
+ SCTP_PRINTF("Dumping re-assembly queue this will probably hose the association\n");
+
+#endif
+ goto abandon;
}
}
cntDel++;
diff --git a/sys/netinet/sctp_lock_bsd.h b/sys/netinet/sctp_lock_bsd.h
index 6d59d35..6db9057 100644
--- a/sys/netinet/sctp_lock_bsd.h
+++ b/sys/netinet/sctp_lock_bsd.h
@@ -365,14 +365,20 @@ extern int sctp_logoff_stuff;
do { \
atomic_add_int(&SCTP_BASE_INFO(ipi_count_chunk), 1); \
} while (0)
-
+#ifdef INVARIANTS
#define SCTP_DECR_CHK_COUNT() \
do { \
if(SCTP_BASE_INFO(ipi_count_chunk) == 0) \
panic("chunk count to 0?"); \
atomic_subtract_int(&SCTP_BASE_INFO(ipi_count_chunk), 1); \
} while (0)
-
+#else
+#define SCTP_DECR_CHK_COUNT() \
+ do { \
+ if(SCTP_BASE_INFO(ipi_count_chunk) != 0) \
+ atomic_subtract_int(&SCTP_BASE_INFO(ipi_count_chunk), 1); \
+ } while (0)
+#endif
#define SCTP_INCR_READQ_COUNT() \
do { \
atomic_add_int(&SCTP_BASE_INFO(ipi_count_readq),1); \
diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c
index 76ea5f3..5c2a492 100644
--- a/sys/netinet/sctp_output.c
+++ b/sys/netinet/sctp_output.c
@@ -11381,6 +11381,7 @@ sctp_send_operr_to(struct mbuf *m, int iphlen, struct mbuf *scm, uint32_t vtag,
struct ip *iph;
struct udphdr *udp = NULL;
struct mbuf *mout;
+
#ifdef INET6
#ifdef SCTP_DEBUG
struct sockaddr_in6 lsa6, fsa6;
diff --git a/sys/netinet/sctp_sysctl.h b/sys/netinet/sctp_sysctl.h
index f739c96..399bcb0 100644
--- a/sys/netinet/sctp_sysctl.h
+++ b/sys/netinet/sctp_sysctl.h
@@ -152,7 +152,7 @@ struct sctp_sysctl {
#define SCTPCTL_STRICT_SACKS_DESC "Enable SCTP Strict SACK checking"
#define SCTPCTL_STRICT_SACKS_MIN 0
#define SCTPCTL_STRICT_SACKS_MAX 1
-#define SCTPCTL_STRICT_SACKS_DEFAULT 0
+#define SCTPCTL_STRICT_SACKS_DEFAULT 1
/* loopback_nocsum: Enable NO Csum on packets sent on loopback */
#define SCTPCTL_LOOPBACK_NOCSUM_DESC "Enable NO Csum on packets sent on loopback"
diff --git a/sys/netinet/sctp_timer.c b/sys/netinet/sctp_timer.c
index a095c4e..73a1877 100644
--- a/sys/netinet/sctp_timer.c
+++ b/sys/netinet/sctp_timer.c
@@ -561,6 +561,49 @@ sctp_backoff_on_timeout(struct sctp_tcb *stcb,
}
}
+static void
+sctp_recover_sent_list(struct sctp_tcb *stcb)
+{
+ struct sctp_tmit_chunk *chk, *tp2;
+ struct sctp_association *asoc;
+
+ asoc = &stcb->asoc;
+ chk = TAILQ_FIRST(&stcb->asoc.sent_queue);
+ for (; chk != NULL; chk = tp2) {
+ tp2 = TAILQ_NEXT(chk, sctp_next);
+ if ((compare_with_wrap(stcb->asoc.last_acked_seq,
+ chk->rec.data.TSN_seq,
+ MAX_TSN)) ||
+ (stcb->asoc.last_acked_seq == chk->rec.data.TSN_seq)) {
+
+ SCTP_PRINTF("Found chk:%p tsn:%x <= last_acked_seq:%x\n",
+ chk, chk->rec.data.TSN_seq, stcb->asoc.last_acked_seq);
+ TAILQ_REMOVE(&asoc->sent_queue, chk, sctp_next);
+ if (chk->pr_sctp_on) {
+ if (asoc->pr_sctp_cnt != 0)
+ asoc->pr_sctp_cnt--;
+ }
+ if (chk->data) {
+ /* sa_ignore NO_NULL_CHK */
+ sctp_free_bufspace(stcb, asoc, chk, 1);
+ sctp_m_freem(chk->data);
+ if (PR_SCTP_BUF_ENABLED(chk->flags)) {
+ asoc->sent_queue_cnt_removeable--;
+ }
+ }
+ chk->data = NULL;
+ asoc->sent_queue_cnt--;
+ sctp_free_a_chunk(stcb, chk);
+ }
+ }
+ SCTP_PRINTF("after recover order is as follows\n");
+ chk = TAILQ_FIRST(&stcb->asoc.sent_queue);
+ for (; chk != NULL; chk = tp2) {
+ tp2 = TAILQ_NEXT(chk, sctp_next);
+ SCTP_PRINTF("chk:%p TSN:%x\n", chk, chk->rec.data.TSN_seq);
+ }
+}
+
static int
sctp_mark_all_for_resend(struct sctp_tcb *stcb,
struct sctp_nets *net,
@@ -583,6 +626,7 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb,
unsigned int cnt_mk;
uint32_t orig_flight, orig_tf;
uint32_t tsnlast, tsnfirst;
+ int recovery_cnt = 0;
/* none in flight now */
@@ -635,6 +679,7 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb,
/* Now on to each chunk */
num_mk = cnt_mk = 0;
tsnfirst = tsnlast = 0;
+start_again:
chk = TAILQ_FIRST(&stcb->asoc.sent_queue);
for (; chk != NULL; chk = tp2) {
tp2 = TAILQ_NEXT(chk, sctp_next);
@@ -643,8 +688,20 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb,
MAX_TSN)) ||
(stcb->asoc.last_acked_seq == chk->rec.data.TSN_seq)) {
/* Strange case our list got out of order? */
- SCTP_PRINTF("Our list is out of order?\n");
- panic("Out of order list");
+ SCTP_PRINTF("Our list is out of order? last_acked:%x chk:%x",
+ (unsigned int)stcb->asoc.last_acked_seq, (unsigned int)chk->rec.data.TSN_seq);
+ recovery_cnt++;
+#ifdef INVARIANTS
+ panic("last acked >= chk on sent-Q");
+#else
+ SCTP_PRINTF("Recover attempts a restart cnt:%d\n", recovery_cnt);
+ sctp_recover_sent_list(stcb);
+ if (recovery_cnt < 10) {
+ goto start_again;
+ } else {
+ SCTP_PRINTF("Recovery fails %d times??\n", recovery_cnt);
+ }
+#endif
}
if ((chk->whoTo == net) && (chk->sent < SCTP_DATAGRAM_ACKED)) {
/*
diff --git a/sys/netinet/sctp_var.h b/sys/netinet/sctp_var.h
index 77f2ceb..9340c1c 100644
--- a/sys/netinet/sctp_var.h
+++ b/sys/netinet/sctp_var.h
@@ -160,6 +160,9 @@ extern struct pr_usrreqs sctp_usrreqs;
} \
}
+#ifdef INVARIANTS
+
+
#define sctp_sbfree(ctl, stcb, sb, m) { \
uint32_t val; \
val = atomic_fetchadd_int(&(sb)->sb_cc,-(SCTP_BUF_LEN((m)))); \
@@ -186,6 +189,35 @@ extern struct pr_usrreqs sctp_usrreqs;
}
+#else
+
+#define sctp_sbfree(ctl, stcb, sb, m) { \
+ uint32_t val; \
+ val = atomic_fetchadd_int(&(sb)->sb_cc,-(SCTP_BUF_LEN((m)))); \
+ if (val < SCTP_BUF_LEN((m))) { \
+ (sb)->sb_cc = 0;\
+ } \
+ val = atomic_fetchadd_int(&(sb)->sb_mbcnt,-(MSIZE)); \
+ if (val < MSIZE) { \
+ (sb)->sb_mbcnt = 0; \
+ } \
+ if (((ctl)->do_not_ref_stcb == 0) && stcb) {\
+ val = atomic_fetchadd_int(&(stcb)->asoc.sb_cc,-(SCTP_BUF_LEN((m)))); \
+ if (val < SCTP_BUF_LEN((m))) {\
+ (stcb)->asoc.sb_cc = 0; \
+ } \
+ val = atomic_fetchadd_int(&(stcb)->asoc.my_rwnd_control_len,-(MSIZE)); \
+ if (val < MSIZE) { \
+ (stcb)->asoc.my_rwnd_control_len = 0; \
+ } \
+ } \
+ if (SCTP_BUF_TYPE(m) != MT_DATA && SCTP_BUF_TYPE(m) != MT_HEADER && \
+ SCTP_BUF_TYPE(m) != MT_OOBDATA) \
+ atomic_subtract_int(&(sb)->sb_ctl,SCTP_BUF_LEN((m))); \
+}
+
+#endif
+
#define sctp_sballoc(stcb, sb, m) { \
atomic_add_int(&(sb)->sb_cc,SCTP_BUF_LEN((m))); \
atomic_add_int(&(sb)->sb_mbcnt, MSIZE); \
diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c
index dc215bd..20865c4 100644
--- a/sys/netinet/sctputil.c
+++ b/sys/netinet/sctputil.c
@@ -922,7 +922,9 @@ sctp_init_asoc(struct sctp_inpcb *m, struct sctp_tcb *stcb,
asoc->my_vtag = override_tag;
} else {
SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOMEM);
+#ifdef INVARIANTS
panic("Huh is_in_timewait fails");
+#endif
return (ENOMEM);
}
@@ -4848,6 +4850,7 @@ sctp_find_ifa_by_addr(struct sockaddr *addr, uint32_t vrf_id, int holds_lock)
vrf = sctp_find_vrf(vrf_id);
if (vrf == NULL) {
+stage_right:
if (holds_lock == 0)
SCTP_IPI_ADDR_RUNLOCK();
return (NULL);
@@ -4868,7 +4871,13 @@ sctp_find_ifa_by_addr(struct sockaddr *addr, uint32_t vrf_id, int holds_lock)
}
LIST_FOREACH(sctp_ifap, hash_head, next_bucket) {
if (sctp_ifap == NULL) {
+#ifdef INVARIANTS
panic("Huh LIST_FOREACH corrupt");
+ goto stage_right;
+#else
+ SCTP_PRINTF("LIST corrupt of sctp_ifap's?\n");
+ goto stage_right;
+#endif
}
if (addr->sa_family != sctp_ifap->address.sa.sa_family)
continue;
@@ -5918,7 +5927,12 @@ out:
* the atomic add to the refcnt.
*/
if (stcb == NULL) {
+#ifdef INVARIANTS
panic("stcb for refcnt has gone NULL?");
+ goto stage_left;
+#else
+ goto stage_left;
+#endif
}
atomic_add_int(&stcb->asoc.refcnt, -1);
freecnt_applied = 0;
@@ -5940,6 +5954,7 @@ out:
so->so_rcv.sb_cc);
}
}
+stage_left:
if (wakeup_read_socket) {
sctp_sorwakeup(inp, so);
}
OpenPOWER on IntegriCloud