From 46b6a3a9c686b451f5de52982fdbc743b34b59bb Mon Sep 17 00:00:00 2001 From: Jon Grimm Date: Thu, 6 Feb 2003 01:46:09 -0600 Subject: [SCTP] Minor surgery on ulpevent & related cleanups. sndrcvinfo.sinfo_cumtsn is new field added by the latest (05) API I-D. Remove unused fields in ulpevent, minimally to make room for for storing this new field. But I'll clear out even more so I can make room for impending partial data delivery work. See changes in comments for ulpqueue.c. Many naming and typedef removal cleanups. --- net/sctp/protocol.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'net/sctp/protocol.c') diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index cd8e3b1adb34..6a5256478270 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -124,7 +124,6 @@ static void sctp_v4_copy_addrlist(struct list_head *addrlist, /* Add the address to the local list. */ addr = t_new(struct sockaddr_storage_list, GFP_ATOMIC); if (addr) { - INIT_LIST_HEAD(&addr->list); addr->a.v4.sin_family = AF_INET; addr->a.v4.sin_port = 0; addr->a.v4.sin_addr.s_addr = ifa->ifa_local; @@ -557,7 +556,7 @@ static void sctp_inet_msgname(char *msgname, int *addr_len) } /* Copy the primary address of the peer primary address as the msg_name. */ -static void sctp_inet_event_msgname(sctp_ulpevent_t *event, char *msgname, +static void sctp_inet_event_msgname(struct sctp_ulpevent *event, char *msgname, int *addr_len) { struct sockaddr_in *sin, *sinfrom; -- cgit v1.2.3 From f2b48f2eb41188c13d865ca9bc48591e772ed6af Mon Sep 17 00:00:00 2001 From: Sridhar Samudrala Date: Tue, 11 Feb 2003 18:46:31 -0800 Subject: [SCTP] sctp mib statistics update/display support. --- include/net/sctp/sctp.h | 1 + net/sctp/Makefile | 2 +- net/sctp/associola.c | 2 + net/sctp/endpointola.c | 2 + net/sctp/input.c | 7 ++- net/sctp/ipv6.c | 2 + net/sctp/outqueue.c | 8 ++- net/sctp/proc.c | 128 +++++++++++++++++++++++++++++++++++++++++++++++ net/sctp/protocol.c | 19 ++++++- net/sctp/sm_make_chunk.c | 3 ++ net/sctp/sm_statefuns.c | 58 +++++++++++++++++++++ net/sctp/ulpqueue.c | 2 + 12 files changed, 229 insertions(+), 5 deletions(-) create mode 100644 net/sctp/proc.c (limited to 'net/sctp/protocol.c') diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index 4ce62633f2e5..b2e19ebde563 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -214,6 +214,7 @@ DECLARE_SNMP_STAT(struct sctp_mib, sctp_statistics); #define SCTP_INC_STATS(field) SNMP_INC_STATS(sctp_statistics, field) #define SCTP_INC_STATS_BH(field) SNMP_INC_STATS_BH(sctp_statistics, field) #define SCTP_INC_STATS_USER(field) SNMP_INC_STATS_USER(sctp_statistics, field) +#define SCTP_DEC_STATS(field) SNMP_DEC_STATS(sctp_statistics, field) /* Determine if this is a valid kernel address. */ static inline int sctp_is_valid_kaddr(unsigned long addr) diff --git a/net/sctp/Makefile b/net/sctp/Makefile index 162f9b11086f..545fad836084 100644 --- a/net/sctp/Makefile +++ b/net/sctp/Makefile @@ -10,7 +10,7 @@ sctp-y := sm_statetable.o sm_statefuns.o sm_sideeffect.o \ inqueue.o outqueue.o ulpqueue.o command.o \ tsnmap.o bind_addr.o socket.o primitive.o \ output.o input.o hashdriver.o sla1.o \ - debug.o ssnmap.o + debug.o ssnmap.o proc.o ifeq ($(CONFIG_SCTP_ADLER32), y) sctp-y += adler32.o diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 1f8e0b094a73..cc6c951a3356 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -795,6 +795,8 @@ static void sctp_assoc_bh_rcv(sctp_association_t *asoc) */ if (sctp_chunk_is_data(chunk)) asoc->peer.last_data_from = chunk->transport; + else + SCTP_INC_STATS(SctpInCtrlChunks); if (chunk->transport) chunk->transport->last_time_heard = jiffies; diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c index 4932831903aa..5a902a3b7e7c 100644 --- a/net/sctp/endpointola.c +++ b/net/sctp/endpointola.c @@ -369,6 +369,8 @@ static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep) */ if (asoc && sctp_chunk_is_data(chunk)) asoc->peer.last_data_from = chunk->transport; + else + SCTP_INC_STATS(SctpInCtrlChunks); if (chunk->transport) chunk->transport->last_time_heard = jiffies; diff --git a/net/sctp/input.c b/net/sctp/input.c index a6aabd3d36a4..895ea6f1694f 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -90,6 +90,7 @@ static inline int sctp_rcv_checksum(struct sk_buff *skb) if (val != cmp) { /* CRC failure, dump it. */ + SCTP_INC_STATS_BH(SctpChecksumErrors); return -1; } return 0; @@ -115,6 +116,8 @@ int sctp_rcv(struct sk_buff *skb) if (skb->pkt_type!=PACKET_HOST) goto discard_it; + SCTP_INC_STATS_BH(SctpInSCTPPacks); + sh = (struct sctphdr *) skb->h.raw; /* Pull up the IP and SCTP headers. */ @@ -160,8 +163,10 @@ int sctp_rcv(struct sk_buff *skb) */ if (!asoc) { ep = __sctp_rcv_lookup_endpoint(&dest); - if (sctp_rcv_ootb(skb)) + if (sctp_rcv_ootb(skb)) { + SCTP_INC_STATS_BH(SctpOutOfBlues); goto discard_release; + } } /* Retrieve the common input handling substructure. */ diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index afd577b71bdc..2de6ed9811b3 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -132,6 +132,8 @@ static inline int sctp_v6_xmit(struct sk_buff *skb, __FUNCTION__, skb, skb->len, NIP6(fl.fl6_src), NIP6(fl.fl6_dst)); + SCTP_INC_STATS(SctpOutSCTPPacks); + return ip6_xmit(sk, skb, &fl, np->opt); } diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index b1bfe69e61ed..a5019f6d7bdd 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c @@ -193,11 +193,17 @@ int sctp_outq_tail(struct sctp_outq *q, sctp_chunk_t *chunk) : "Illegal Chunk"); skb_queue_tail(&q->out, (struct sk_buff *) chunk); + if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) + SCTP_INC_STATS(SctpOutUnorderChunks); + else + SCTP_INC_STATS(SctpOutOrderChunks); q->empty = 0; break; }; - } else + } else { skb_queue_tail(&q->control, (struct sk_buff *) chunk); + SCTP_INC_STATS(SctpOutCtrlChunks); + } if (error < 0) return error; diff --git a/net/sctp/proc.c b/net/sctp/proc.c new file mode 100644 index 000000000000..9c7d9e489b22 --- /dev/null +++ b/net/sctp/proc.c @@ -0,0 +1,128 @@ +/* SCTP kernel reference Implementation + * Copyright (c) 2003 International Business Machines, Corp. + * + * This file is part of the SCTP kernel reference Implementation + * + * The SCTP reference implementation is free software; + * you can redistribute it and/or modify it under the terms of + * the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * The SCTP reference implementation is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * ************************ + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * Sridhar Samudrala + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + +#include +#include +#include + +static char *sctp_snmp_list[] = { +#define SCTP_SNMP_ENTRY(x) #x + SCTP_SNMP_ENTRY(SctpCurrEstab), + SCTP_SNMP_ENTRY(SctpActiveEstabs), + SCTP_SNMP_ENTRY(SctpPassiveEstabs), + SCTP_SNMP_ENTRY(SctpAborteds), + SCTP_SNMP_ENTRY(SctpShutdowns), + SCTP_SNMP_ENTRY(SctpOutOfBlues), + SCTP_SNMP_ENTRY(SctpChecksumErrors), + SCTP_SNMP_ENTRY(SctpOutCtrlChunks), + SCTP_SNMP_ENTRY(SctpOutOrderChunks), + SCTP_SNMP_ENTRY(SctpOutUnorderChunks), + SCTP_SNMP_ENTRY(SctpInCtrlChunks), + SCTP_SNMP_ENTRY(SctpInOrderChunks), + SCTP_SNMP_ENTRY(SctpInUnorderChunks), + SCTP_SNMP_ENTRY(SctpFragUsrMsgs), + SCTP_SNMP_ENTRY(SctpReasmUsrMsgs), + SCTP_SNMP_ENTRY(SctpOutSCTPPacks), + SCTP_SNMP_ENTRY(SctpInSCTPPacks), +#undef SCTP_SNMP_ENTRY +}; + +/* Return the current value of a particular entry in the mib by adding its + * per cpu counters. + */ +static unsigned long +fold_field(void *mib[], int nr) +{ + unsigned long res = 0; + int i; + + for (i = 0; i < NR_CPUS; i++) { + if (!cpu_possible(i)) + continue; + res += + *((unsigned long *) (((void *) per_cpu_ptr(mib[0], i)) + + sizeof (unsigned long) * nr)); + res += + *((unsigned long *) (((void *) per_cpu_ptr(mib[1], i)) + + sizeof (unsigned long) * nr)); + } + return res; +} + +/* Display sctp snmp mib statistics(/proc/net/sctp/snmp). */ +static int sctp_snmp_seq_show(struct seq_file *seq, void *v) +{ + int i; + + for (i = 0; i < sizeof(sctp_snmp_list) / sizeof(char *); i++) + seq_printf(seq, "%-32s\t%ld\n", sctp_snmp_list[i], + fold_field((void **)sctp_statistics, i)); + + return 0; +} + +/* Initialize the seq file operations for 'snmp' object. */ +static int sctp_snmp_seq_open(struct inode *inode, struct file *file) +{ + return single_open(file, sctp_snmp_seq_show, NULL); +} + +static struct file_operations sctp_snmp_seq_fops = { + .open = sctp_snmp_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +/* Set up the proc fs entry for 'snmp' object. */ +int __init sctp_snmp_proc_init(void) +{ + struct proc_dir_entry *p; + + p = create_proc_entry("snmp", S_IRUGO, proc_net_sctp); + if (!p) + return -ENOMEM; + + p->proc_fops = &sctp_snmp_seq_fops; + + return 0; +} + +/* Cleanup the proc fs entry for 'snmp' object. */ +void sctp_snmp_proc_exit(void) +{ + remove_proc_entry("snmp", proc_net_sctp); +} diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index cd8e3b1adb34..e97b4d443b56 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -75,6 +75,9 @@ static struct sctp_af *sctp_af_v6_specific; extern struct net_proto_family inet_family_ops; +extern int sctp_snmp_proc_init(void); +extern int sctp_snmp_proc_exit(void); + /* Return the address of the control sock. */ struct sock *sctp_get_ctl_sock(void) { @@ -82,21 +85,32 @@ struct sock *sctp_get_ctl_sock(void) } /* Set up the proc fs entry for the SCTP protocol. */ -__init void sctp_proc_init(void) +__init int sctp_proc_init(void) { + int rc = 0; + if (!proc_net_sctp) { struct proc_dir_entry *ent; ent = proc_mkdir("net/sctp", 0); if (ent) { ent->owner = THIS_MODULE; proc_net_sctp = ent; - } + } else + rc = -ENOMEM; } + + if (sctp_snmp_proc_init()) + rc = -ENOMEM; + + return rc; } /* Clean up the proc fs entry for the SCTP protocol. */ void sctp_proc_exit(void) { + + sctp_snmp_proc_exit(); + if (proc_net_sctp) { proc_net_sctp = NULL; remove_proc_entry("net/sctp", 0); @@ -628,6 +642,7 @@ static inline int sctp_v4_xmit(struct sk_buff *skb, NIPQUAD(((struct rtable *)skb->dst)->rt_src), NIPQUAD(((struct rtable *)skb->dst)->rt_dst)); + SCTP_INC_STATS(SctpOutSCTPPacks); return ip_queue_xmit(skb, ipfragok); } diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 487221d46a65..cf752d4d2711 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -1180,6 +1180,9 @@ int sctp_datachunks_from_user(sctp_association_t *asoc, over = msg_len % max; offset = 0; + if (whole && over) + SCTP_INC_STATS_USER(SctpFragUsrMsgs); + /* Create chunks for all the full sized DATA chunks. */ for (i=0, len=first_len; i < whole; i++) { frag = SCTP_DATA_MIDDLE_FRAG; diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 848a48229f17..47a22b9daf11 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -145,6 +145,9 @@ sctp_disposition_t sctp_sf_do_4_C(const sctp_endpoint_t *ep, sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, SCTP_STATE(SCTP_STATE_CLOSED)); + + SCTP_INC_STATS(SctpShutdowns); + SCTP_DEC_STATS(SctpCurrEstab); sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); @@ -223,6 +226,7 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep, if (packet) { sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT, SCTP_PACKET(packet)); + SCTP_INC_STATS(SctpOutCtrlChunks); return SCTP_DISPOSITION_CONSUME; } else { return SCTP_DISPOSITION_NOMEM; @@ -379,6 +383,7 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const sctp_endpoint_t *ep, sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply)); sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, SCTP_STATE(SCTP_STATE_CLOSED)); + SCTP_INC_STATS(SctpAborteds); sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); return SCTP_DISPOSITION_DELETE_TCB; } @@ -388,6 +393,9 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const sctp_endpoint_t *ep, if (!sctp_verify_init(asoc, chunk->chunk_hdr->type, (sctp_init_chunk_t *)chunk->chunk_hdr, chunk, &err_chunk)) { + + SCTP_INC_STATS(SctpAborteds); + /* This chunk contains fatal error. It is to be discarded. * Send an ABORT, with causes if there is any. */ @@ -403,6 +411,7 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const sctp_endpoint_t *ep, if (packet) { sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT, SCTP_PACKET(packet)); + SCTP_INC_STATS(SctpOutCtrlChunks); sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, SCTP_STATE(SCTP_STATE_CLOSED)); sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, @@ -557,6 +566,8 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const sctp_endpoint_t *ep, sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(new_asoc)); sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, SCTP_STATE(SCTP_STATE_ESTABLISHED)); + SCTP_INC_STATS(SctpCurrEstab); + SCTP_INC_STATS(SctpPassiveEstabs); sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_START, SCTP_NULL()); if (new_asoc->autoclose) @@ -648,6 +659,8 @@ sctp_disposition_t sctp_sf_do_5_1E_ca(const sctp_endpoint_t *ep, SCTP_TO(SCTP_EVENT_TIMEOUT_T1_COOKIE)); sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, SCTP_STATE(SCTP_STATE_ESTABLISHED)); + SCTP_INC_STATS(SctpCurrEstab); + SCTP_INC_STATS(SctpActiveEstabs); sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_START, SCTP_NULL()); if (asoc->autoclose) sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START, @@ -719,6 +732,8 @@ sctp_disposition_t sctp_sf_sendbeat_8_3(const sctp_endpoint_t *ep, if (asoc->overall_error_count >= asoc->overall_error_threshold) { /* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */ sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_NULL()); + SCTP_INC_STATS(SctpAborteds); + SCTP_DEC_STATS(SctpCurrEstab); return SCTP_DISPOSITION_DELETE_TCB; } @@ -929,6 +944,8 @@ static int sctp_sf_send_restart_abort(union sctp_addr *ssa, goto out; sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT, SCTP_PACKET(pkt)); + SCTP_INC_STATS(SctpOutCtrlChunks); + /* Discard the rest of the inbound packet. */ sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET, SCTP_NULL()); @@ -1125,6 +1142,7 @@ static sctp_disposition_t sctp_sf_do_unexpected_init( if (packet) { sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT, SCTP_PACKET(packet)); + SCTP_INC_STATS(SctpOutCtrlChunks); retval = SCTP_DISPOSITION_CONSUME; } else { retval = SCTP_DISPOSITION_NOMEM; @@ -1436,6 +1454,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_b(const sctp_endpoint_t *ep, sctp_add_cmd_sf(commands, SCTP_CMD_UPDATE_ASSOC, SCTP_ASOC(new_asoc)); sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, SCTP_STATE(SCTP_STATE_ESTABLISHED)); + SCTP_INC_STATS(SctpCurrEstab); sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_START, SCTP_NULL()); repl = sctp_make_cookie_ack(new_asoc, chunk); @@ -1519,6 +1538,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_d(const sctp_endpoint_t *ep, SCTP_TO(SCTP_EVENT_TIMEOUT_T1_COOKIE)); sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, SCTP_STATE(SCTP_STATE_ESTABLISHED)); + SCTP_INC_STATS(SctpCurrEstab); sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_START, SCTP_NULL()); @@ -1925,6 +1945,8 @@ sctp_disposition_t sctp_sf_do_9_1_abort(const sctp_endpoint_t *ep, /* ASSOC_FAILED will DELETE_TCB. */ sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_NULL()); + SCTP_INC_STATS(SctpAborteds); + SCTP_DEC_STATS(SctpCurrEstab); /* BUG? This does not look complete... */ return SCTP_DISPOSITION_ABORT; @@ -1948,6 +1970,7 @@ sctp_disposition_t sctp_sf_cookie_wait_abort(const sctp_endpoint_t *ep, sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, SCTP_STATE(SCTP_STATE_CLOSED)); + SCTP_INC_STATS(SctpAborteds); sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT)); @@ -2332,6 +2355,8 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep, */ sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET,SCTP_NULL()); sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_NULL()); + SCTP_INC_STATS(SctpAborteds); + SCTP_INC_STATS(SctpCurrEstab); return SCTP_DISPOSITION_CONSUME; } @@ -2340,6 +2365,11 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep, /* Record the fact that we have received this TSN. */ sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_TSN, SCTP_U32(tsn)); + if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) + SCTP_INC_STATS(SctpInUnorderChunks); + else + SCTP_INC_STATS(SctpInOrderChunks); + /* RFC 2960 6.5 Stream Identifier and Stream Sequence Number * * If an endpoint receive a DATA chunk with an invalid stream @@ -2536,6 +2566,8 @@ sctp_disposition_t sctp_sf_eat_data_fast_4_4(const sctp_endpoint_t *ep, */ sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET,SCTP_NULL()); sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_NULL()); + SCTP_INC_STATS(SctpAborteds); + SCTP_INC_STATS(SctpCurrEstab); return SCTP_DISPOSITION_CONSUME; } @@ -2544,6 +2576,11 @@ sctp_disposition_t sctp_sf_eat_data_fast_4_4(const sctp_endpoint_t *ep, /* Record the fact that we have received this TSN. */ sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_TSN, SCTP_U32(tsn)); + if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) + SCTP_INC_STATS(SctpInUnorderChunks); + else + SCTP_INC_STATS(SctpInOrderChunks); + /* RFC 2960 6.5 Stream Identifier and Stream Sequence Number * * If an endpoint receive a DATA chunk with an invalid stream @@ -2705,6 +2742,8 @@ sctp_disposition_t sctp_sf_tabort_8_4_8(const sctp_endpoint_t *ep, sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT, SCTP_PACKET(packet)); + SCTP_INC_STATS(SctpOutCtrlChunks); + return SCTP_DISPOSITION_CONSUME; } @@ -2794,6 +2833,8 @@ sctp_disposition_t sctp_sf_do_9_2_final(const sctp_endpoint_t *ep, sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, SCTP_STATE(SCTP_STATE_CLOSED)); + SCTP_INC_STATS(SctpShutdowns); + SCTP_DEC_STATS(SctpCurrEstab); sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply)); /* ...and remove all record of the association. */ @@ -2834,6 +2875,8 @@ sctp_disposition_t sctp_sf_ootb(const sctp_endpoint_t *ep, __u8 *ch_end; int ootb_shut_ack = 0; + SCTP_INC_STATS(SctpOutOfBlues); + ch = (sctp_chunkhdr_t *) chunk->chunk_hdr; do { ch_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length)); @@ -2901,6 +2944,8 @@ sctp_disposition_t sctp_sf_shut_8_4_5(const sctp_endpoint_t *ep, sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT, SCTP_PACKET(packet)); + SCTP_INC_STATS(SctpOutCtrlChunks); + return SCTP_DISPOSITION_CONSUME; } @@ -3472,6 +3517,10 @@ sctp_disposition_t sctp_sf_do_9_1_prm_abort(const sctp_endpoint_t *ep, /* Delete the established association. */ sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_NULL()); + + SCTP_INC_STATS(SctpAborteds); + SCTP_DEC_STATS(SctpCurrEstab); + return retval; } @@ -3527,6 +3576,8 @@ sctp_disposition_t sctp_sf_cookie_wait_prm_shutdown( sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, SCTP_STATE(SCTP_STATE_CLOSED)); + SCTP_INC_STATS(SctpShutdowns); + sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); return SCTP_DISPOSITION_DELETE_TCB; @@ -3597,6 +3648,8 @@ sctp_disposition_t sctp_sf_cookie_wait_prm_abort(const sctp_endpoint_t *ep, sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, SCTP_STATE(SCTP_STATE_CLOSED)); + SCTP_INC_STATS(SctpAborteds); + /* Even if we can't send the ABORT due to low memory delete the * TCB. This is a departure from our typical NOMEM handling. */ @@ -3929,6 +3982,8 @@ sctp_disposition_t sctp_sf_do_6_3_3_rtx(const sctp_endpoint_t *ep, if (asoc->overall_error_count >= asoc->overall_error_threshold) { /* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */ sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_NULL()); + SCTP_INC_STATS(SctpAborteds); + SCTP_DEC_STATS(SctpCurrEstab); return SCTP_DISPOSITION_DELETE_TCB; } @@ -4096,6 +4151,8 @@ sctp_disposition_t sctp_sf_t2_timer_expire(const sctp_endpoint_t *ep, if (asoc->overall_error_count >= asoc->overall_error_threshold) { /* Note: CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */ sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_NULL()); + SCTP_INC_STATS(SctpAborteds); + SCTP_DEC_STATS(SctpCurrEstab); return SCTP_DISPOSITION_DELETE_TCB; } @@ -4401,6 +4458,7 @@ void sctp_send_stale_cookie_err(const sctp_endpoint_t *ep, sctp_packet_append_chunk(packet, err_chunk); sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT, SCTP_PACKET(packet)); + SCTP_INC_STATS(SctpOutCtrlChunks); } else sctp_free_chunk (err_chunk); } diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c index 04c47bffb8e9..098f86ef2b4f 100644 --- a/net/sctp/ulpqueue.c +++ b/net/sctp/ulpqueue.c @@ -266,6 +266,8 @@ static inline struct sctp_ulpevent *sctp_make_reassembled_event(struct sk_buff * event = (sctp_ulpevent_t *) f_frag->cb; + SCTP_INC_STATS(SctpReasmUsrMsgs); + return event; } -- cgit v1.2.3 From 13970d8e1ff3451967050309ce14ae2b6160bfd5 Mon Sep 17 00:00:00 2001 From: Sridhar Samudrala Date: Mon, 17 Feb 2003 00:33:37 -0800 Subject: [SCTP] Update retransmission path in a round-robin fashion when a retransmission timer expires instead of using the same path until the path error count reaches its threshold value. --- include/net/sctp/structs.h | 1 + net/sctp/associola.c | 36 +++++++++++++++++++++++------------- net/sctp/output.c | 1 + net/sctp/outqueue.c | 5 +++++ net/sctp/protocol.c | 1 - 5 files changed, 30 insertions(+), 14 deletions(-) (limited to 'net/sctp/protocol.c') diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index bcb994fad15b..d136122af892 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -1613,6 +1613,7 @@ void sctp_association_put(sctp_association_t *); void sctp_association_hold(sctp_association_t *); struct sctp_transport *sctp_assoc_choose_shutdown_transport(sctp_association_t *); +void sctp_assoc_update_retran_path(sctp_association_t *); struct sctp_transport *sctp_assoc_lookup_paddr(const sctp_association_t *, const union sctp_addr *); struct sctp_transport *sctp_assoc_add_peer(sctp_association_t *, diff --git a/net/sctp/associola.c b/net/sctp/associola.c index f8f9ed0138bd..916c11d97ac1 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -887,26 +887,19 @@ void sctp_assoc_update(sctp_association_t *asoc, sctp_association_t *new) } -/* Choose the transport for sending a shutdown packet. +/* Update the retran path for sending a retransmitted packet. * Round-robin through the active transports, else round-robin * through the inactive transports as this is the next best thing * we can try. */ -struct sctp_transport *sctp_assoc_choose_shutdown_transport(sctp_association_t *asoc) +void sctp_assoc_update_retran_path(sctp_association_t *asoc) { struct sctp_transport *t, *next; struct list_head *head = &asoc->peer.transport_addr_list; struct list_head *pos; - /* If this is the first time SHUTDOWN is sent, use the active - * path. - */ - if (!asoc->shutdown_last_sent_to) - return asoc->peer.active_path; - - /* Otherwise, find the next transport in a round-robin fashion. */ - - t = asoc->shutdown_last_sent_to; + /* Find the next transport in a round-robin fashion. */ + t = asoc->peer.retran_path; pos = &t->transports; next = NULL; @@ -935,13 +928,30 @@ struct sctp_transport *sctp_assoc_choose_shutdown_transport(sctp_association_t * * other active transports. If so, use the next * transport. */ - if (t == asoc->shutdown_last_sent_to) { + if (t == asoc->peer.retran_path) { t = next; break; } } - return t; + asoc->peer.retran_path = t; +} + +/* Choose the transport for sending a SHUTDOWN packet. */ +struct sctp_transport *sctp_assoc_choose_shutdown_transport(sctp_association_t *asoc) +{ + /* If this is the first time SHUTDOWN is sent, use the active path, + * else use the retran path. If the last SHUTDOWN was sent over the + * retran path, update the retran path and use it. + */ + if (!asoc->shutdown_last_sent_to) + return asoc->peer.active_path; + else { + if (asoc->shutdown_last_sent_to == asoc->peer.retran_path) + sctp_assoc_update_retran_path(asoc); + return asoc->peer.retran_path; + } + } /* Update the association's pmtu and frag_point by going through all the diff --git a/net/sctp/output.c b/net/sctp/output.c index 9dcbc6d38a1f..d7826c2216e6 100644 --- a/net/sctp/output.c +++ b/net/sctp/output.c @@ -419,6 +419,7 @@ int sctp_packet_transmit(sctp_packet_t *packet) dst = transport->dst; /* The 'obsolete' field of dst is set to 2 when a dst is freed. */ if (!dst || (dst->obsolete > 1)) { + dst_release(dst); sctp_transport_route(transport, NULL, sctp_sk(sk)); sctp_assoc_sync_pmtu(asoc); } diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index a5019f6d7bdd..1171984c3e20 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c @@ -321,6 +321,11 @@ void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport, switch(reason) { case SCTP_RETRANSMIT_T3_RTX: sctp_transport_lower_cwnd(transport, SCTP_LOWER_CWND_T3_RTX); + /* Update the retran path if the T3-rtx timer has expired for + * the current retran path. + */ + if (transport == transport->asoc->peer.retran_path) + sctp_assoc_update_retran_path(transport->asoc); break; case SCTP_RETRANSMIT_FAST_RTX: sctp_transport_lower_cwnd(transport, SCTP_LOWER_CWND_FAST_RTX); diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index b69dff403d61..85a5a2941af5 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -449,7 +449,6 @@ struct dst_entry *sctp_v4_get_dst(sctp_association_t *asoc, if (AF_INET == laddr->a.sa.sa_family) { fl.fl4_src = laddr->a.v4.sin_addr.s_addr; - dst = sctp_v4_get_dst(asoc, daddr, &laddr->a); if (!ip_route_output_key(&rt, &fl)) { dst = &rt->u.dst; goto out_unlock; -- cgit v1.2.3