Commit 5cab1102 authored by Jon Grimm's avatar Jon Grimm

[SCTP] Shorten SACK generation path.

1) Remove sctp_tsnmap_update_pending from the SACK path.  The
pending_data variable is only used by a socket option, so just
calculate it when needed rather than the I/O path.
2) Instead of walking the tsnmap twice, change the interface to
allow walking once.
3) Only report a fixed number of gabs and reserve this room in the 
association, saving us a kmalloc every sack generation.
TBD: Still need to kick out of tanmap walking early if we get to
max_tsn_seen.   
parent b6d53725
......@@ -267,7 +267,8 @@ enum { SCTP_ARBITRARY_COOKIE_ECHO_LEN = 200 };
* nearest power of 2.
*/
enum { SCTP_MIN_PMTU = 576 };
enum { SCTP_MAX_DUP_TSNS = 128 };
enum { SCTP_MAX_DUP_TSNS = 16 };
enum { SCTP_MAX_GABS = 16 };
typedef enum {
SCTP_COUNTER_INIT_ERROR,
......
/* SCTP kernel reference Implementation Copyright (C) 1999-2001
* Cisco, Motorola, Intel, and International Business Machines Corp.
/* SCTP kernel reference Implementation
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001-2003 International Business Machines, Corp.
* Copyright (c) 2001 Intel Corp.
*
* This file is part of the SCTP kernel reference Implementation
*
......@@ -97,13 +100,16 @@ struct sctp_tsnmap {
/* Data chunks pending receipt. used by SCTP_STATUS sockopt */
__u16 pending_data;
/* We record duplicate TSNs here. We clear this after
/* Record duplicate TSNs here. We clear this after
* every SACK. Store up to SCTP_MAX_DUP_TSNS worth of
* information.
*/
__u32 dup_tsns[SCTP_MAX_DUP_TSNS];
__u16 num_dup_tsns;
/* Record gap ack block information here. */
struct sctp_gap_ack_block gabs[SCTP_MAX_GABS];
int malloced;
__u8 raw_map[0];
......@@ -140,12 +146,18 @@ int sctp_tsnmap_check(const struct sctp_tsnmap *, __u32 tsn);
void sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn);
/* Retrieve the Cumulative TSN ACK Point. */
__u32 sctp_tsnmap_get_ctsn(const struct sctp_tsnmap *);
static inline __u32 sctp_tsnmap_get_ctsn(const struct sctp_tsnmap *map)
{
return map->cumulative_tsn_ack_point;
}
/* Retrieve the highest TSN we've seen. */
__u32 sctp_tsnmap_get_max_tsn_seen(const struct sctp_tsnmap *);
static inline __u32 sctp_tsnmap_get_max_tsn_seen(const struct sctp_tsnmap *map)
{
return map->max_tsn_seen;
}
/* How many Duplicate TSNs are stored? */
/* How many duplicate TSNs are stored? */
static inline __u16 sctp_tsnmap_num_dups(struct sctp_tsnmap *map)
{
return map->num_dup_tsns;
......@@ -158,6 +170,27 @@ static inline __u32 *sctp_tsnmap_get_dups(struct sctp_tsnmap *map)
return map->dup_tsns;
}
/* How many gap ack blocks do we have recorded? */
__u16 sctp_tsnmap_num_gabs(struct sctp_tsnmap *map);
/* Refresh the count on pending data. */
__u16 sctp_tsnmap_pending(struct sctp_tsnmap *map);
/* Return pointer to gap ack blocks as needed by SACK. */
static inline struct sctp_gap_ack_block *sctp_tsnmap_get_gabs(struct sctp_tsnmap *map)
{
return map->gabs;
}
/* Is there a gap in the TSN map? */
static inline int sctp_tsnmap_has_gap(const struct sctp_tsnmap *map)
{
int has_gap;
has_gap = (map->cumulative_tsn_ack_point != map->max_tsn_seen);
return has_gap;
}
/* Mark a duplicate TSN. Note: limit the storage of duplicate TSN
* information.
*/
......
......@@ -589,27 +589,17 @@ struct sctp_chunk *sctp_make_data_empty(struct sctp_association *asoc,
struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
{
struct sctp_chunk *retval;
sctp_sackhdr_t sack;
sctp_gap_ack_block_t gab;
int length;
struct sctp_sackhdr sack;
int len;
__u32 ctsn;
struct sctp_tsnmap_iter iter;
__u16 num_gabs, num_dup_tsns;
struct sctp_tsnmap *map = (struct sctp_tsnmap *)&asoc->peer.tsn_map;
ctsn = sctp_tsnmap_get_ctsn(map);
SCTP_DEBUG_PRINTK("sackCTSNAck sent is 0x%x.\n", ctsn);
/* Count the number of Gap Ack Blocks. */
num_gabs = 0;
if (sctp_tsnmap_has_gap(map)) {
sctp_tsnmap_iter_init(map, &iter);
while (sctp_tsnmap_next_gap_ack(map, &iter,
&gab.start, &gab.end))
num_gabs++;
}
SCTP_DEBUG_PRINTK("sackCTSNAck sent: 0x%x.\n", ctsn);
/* How much room is needed in the chunk? */
num_gabs = sctp_tsnmap_num_gabs(map);
num_dup_tsns = sctp_tsnmap_num_dups(map);
/* Initialize the SACK header. */
......@@ -618,12 +608,12 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
sack.num_gap_ack_blocks = htons(num_gabs);
sack.num_dup_tsns = htons(num_dup_tsns);
length = sizeof(sack)
+ sizeof(sctp_gap_ack_block_t) * num_gabs
len = sizeof(sack)
+ sizeof(struct sctp_gap_ack_block) * num_gabs
+ sizeof(__u32) * num_dup_tsns;
/* Create the chunk. */
retval = sctp_make_chunk(asoc, SCTP_CID_SACK, 0, length);
retval = sctp_make_chunk(asoc, SCTP_CID_SACK, 0, len);
if (!retval)
goto nodata;
......@@ -662,21 +652,15 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
retval->subh.sack_hdr =
sctp_addto_chunk(retval, sizeof(sack), &sack);
/* Put the Gap Ack Blocks into the chunk. */
if (num_gabs) {
sctp_tsnmap_iter_init(map, &iter);
while(sctp_tsnmap_next_gap_ack(map, &iter,
&gab.start, &gab.end)) {
gab.start = htons(gab.start);
gab.end = htons(gab.end);
sctp_addto_chunk(retval, sizeof(sctp_gap_ack_block_t),
&gab);
}
}
/* Add the gap ack block information. */
if (num_gabs)
sctp_addto_chunk(retval, sizeof(__u32) * num_gabs,
sctp_tsnmap_get_gabs(map));
/* Register the duplicates. */
sctp_addto_chunk(retval, sizeof(__u32) * num_dup_tsns,
sctp_tsnmap_get_dups(map));
/* Add the duplicate TSN information. */
if (num_dup_tsns)
sctp_addto_chunk(retval, sizeof(__u32) * num_dup_tsns,
sctp_tsnmap_get_dups(map));
nodata:
return retval;
......
......@@ -2299,7 +2299,8 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval,
status.sstat_state = asoc->state;
status.sstat_rwnd = asoc->peer.rwnd;
status.sstat_unackdata = asoc->unack_data;
status.sstat_penddata = asoc->peer.tsn_map.pending_data;
status.sstat_penddata = sctp_tsnmap_pending(&asoc->peer.tsn_map);
status.sstat_instrms = asoc->c.sinit_max_instreams;
status.sstat_outstrms = asoc->c.sinit_num_ostreams;
/* Just in time frag_point update. */
......
......@@ -46,7 +46,6 @@
#include <net/sctp/sm.h>
static void sctp_tsnmap_update(struct sctp_tsnmap *map);
static void sctp_tsnmap_update_pending_data(struct sctp_tsnmap *map);
static void sctp_tsnmap_find_gap_ack(__u8 *map, __u16 off,
__u16 len, __u16 base,
int *started, __u16 *start,
......@@ -92,7 +91,6 @@ struct sctp_tsnmap *sctp_tsnmap_init(struct sctp_tsnmap *map, __u16 len,
map->cumulative_tsn_ack_point = initial_tsn - 1;
map->max_tsn_seen = map->cumulative_tsn_ack_point;
map->malloced = 0;
map->pending_data = 0;
map->num_dup_tsns = 0;
return map;
......@@ -135,14 +133,6 @@ int sctp_tsnmap_check(const struct sctp_tsnmap *map, __u32 tsn)
return dup;
}
/* Is there a gap in the TSN map? */
int sctp_tsnmap_has_gap(const struct sctp_tsnmap *map)
{
int has_gap;
has_gap = (map->cumulative_tsn_ack_point != map->max_tsn_seen);
return has_gap;
}
/* Mark this TSN as seen. */
void sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn)
......@@ -176,21 +166,6 @@ void sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn)
sctp_tsnmap_update(map);
}
void sctp_tsnmap_report_dup(struct sctp_tsnmap *map, __u32 tsn)
{
}
/* Retrieve the Cumulative TSN Ack Point. */
__u32 sctp_tsnmap_get_ctsn(const struct sctp_tsnmap *map)
{
return map->cumulative_tsn_ack_point;
}
/* Retrieve the highest TSN we've seen. */
__u32 sctp_tsnmap_get_max_tsn_seen(const struct sctp_tsnmap *map)
{
return map->max_tsn_seen;
}
/* Dispose of a tsnmap. */
void sctp_tsnmap_free(struct sctp_tsnmap *map)
......@@ -304,10 +279,11 @@ static void sctp_tsnmap_update(struct sctp_tsnmap *map)
} while (map->tsn_map[ctsn - map->base_tsn]);
map->cumulative_tsn_ack_point = ctsn - 1; /* Back up one. */
sctp_tsnmap_update_pending_data(map);
}
static void sctp_tsnmap_update_pending_data(struct sctp_tsnmap *map)
/* How many data chunks are we missing from our peer?
*/
__u16 sctp_tsnmap_pending(struct sctp_tsnmap *map)
{
__u32 cum_tsn = map->cumulative_tsn_ack_point;
__u32 max_tsn = map->max_tsn_seen;
......@@ -339,7 +315,7 @@ static void sctp_tsnmap_update_pending_data(struct sctp_tsnmap *map)
}
out:
map->pending_data = pending_data;
return pending_data;
}
/* This is a private helper for finding Gap Ack Blocks. It searches a
......@@ -359,6 +335,8 @@ static void sctp_tsnmap_find_gap_ack(__u8 *map, __u16 off,
* early if we have found the end of the Gap Ack Block.
*/
/* Also, stop looking past the maximum TSN seen. */
/* Look for the start. */
if (!(*started)) {
for (; i < len; i++) {
......@@ -404,3 +382,26 @@ void sctp_tsnmap_renege(struct sctp_tsnmap *map, __u32 tsn)
else
map->overflow_map[gap - map->len] = 0;
}
/* How many gap ack blocks do we have recorded? */
__u16 sctp_tsnmap_num_gabs(struct sctp_tsnmap *map)
{
struct sctp_tsnmap_iter iter;
int gabs = 0;
/* Refresh the gap ack information. */
if (sctp_tsnmap_has_gap(map)) {
sctp_tsnmap_iter_init(map, &iter);
while (sctp_tsnmap_next_gap_ack(map, &iter,
&map->gabs[gabs].start,
&map->gabs[gabs].end)) {
map->gabs[gabs].start = htons(map->gabs[gabs].start);
map->gabs[gabs].end = htons(map->gabs[gabs].end);
gabs++;
if (gabs >= SCTP_MAX_GABS)
break;
}
}
return gabs;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment