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 }; ...@@ -267,7 +267,8 @@ enum { SCTP_ARBITRARY_COOKIE_ECHO_LEN = 200 };
* nearest power of 2. * nearest power of 2.
*/ */
enum { SCTP_MIN_PMTU = 576 }; enum { SCTP_MIN_PMTU = 576 };
enum { SCTP_MAX_DUP_TSNS = 128 }; enum { SCTP_MAX_DUP_TSNS = 16 };
enum { SCTP_MAX_GABS = 16 };
typedef enum { typedef enum {
SCTP_COUNTER_INIT_ERROR, SCTP_COUNTER_INIT_ERROR,
......
/* SCTP kernel reference Implementation Copyright (C) 1999-2001 /* SCTP kernel reference Implementation
* Cisco, Motorola, Intel, and International Business Machines Corp. * 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 * This file is part of the SCTP kernel reference Implementation
* *
...@@ -97,13 +100,16 @@ struct sctp_tsnmap { ...@@ -97,13 +100,16 @@ struct sctp_tsnmap {
/* Data chunks pending receipt. used by SCTP_STATUS sockopt */ /* Data chunks pending receipt. used by SCTP_STATUS sockopt */
__u16 pending_data; __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 * every SACK. Store up to SCTP_MAX_DUP_TSNS worth of
* information. * information.
*/ */
__u32 dup_tsns[SCTP_MAX_DUP_TSNS]; __u32 dup_tsns[SCTP_MAX_DUP_TSNS];
__u16 num_dup_tsns; __u16 num_dup_tsns;
/* Record gap ack block information here. */
struct sctp_gap_ack_block gabs[SCTP_MAX_GABS];
int malloced; int malloced;
__u8 raw_map[0]; __u8 raw_map[0];
...@@ -140,12 +146,18 @@ int sctp_tsnmap_check(const struct sctp_tsnmap *, __u32 tsn); ...@@ -140,12 +146,18 @@ int sctp_tsnmap_check(const struct sctp_tsnmap *, __u32 tsn);
void sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn); void sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn);
/* Retrieve the Cumulative TSN ACK Point. */ /* 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. */ /* 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) static inline __u16 sctp_tsnmap_num_dups(struct sctp_tsnmap *map)
{ {
return map->num_dup_tsns; return map->num_dup_tsns;
...@@ -158,6 +170,27 @@ static inline __u32 *sctp_tsnmap_get_dups(struct sctp_tsnmap *map) ...@@ -158,6 +170,27 @@ static inline __u32 *sctp_tsnmap_get_dups(struct sctp_tsnmap *map)
return map->dup_tsns; 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 /* Mark a duplicate TSN. Note: limit the storage of duplicate TSN
* information. * information.
*/ */
......
...@@ -589,27 +589,17 @@ struct sctp_chunk *sctp_make_data_empty(struct sctp_association *asoc, ...@@ -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 *sctp_make_sack(const struct sctp_association *asoc)
{ {
struct sctp_chunk *retval; struct sctp_chunk *retval;
sctp_sackhdr_t sack; struct sctp_sackhdr sack;
sctp_gap_ack_block_t gab; int len;
int length;
__u32 ctsn; __u32 ctsn;
struct sctp_tsnmap_iter iter;
__u16 num_gabs, num_dup_tsns; __u16 num_gabs, num_dup_tsns;
struct sctp_tsnmap *map = (struct sctp_tsnmap *)&asoc->peer.tsn_map; struct sctp_tsnmap *map = (struct sctp_tsnmap *)&asoc->peer.tsn_map;
ctsn = sctp_tsnmap_get_ctsn(map); ctsn = sctp_tsnmap_get_ctsn(map);
SCTP_DEBUG_PRINTK("sackCTSNAck sent is 0x%x.\n", ctsn); SCTP_DEBUG_PRINTK("sackCTSNAck sent: 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++;
}
/* How much room is needed in the chunk? */
num_gabs = sctp_tsnmap_num_gabs(map);
num_dup_tsns = sctp_tsnmap_num_dups(map); num_dup_tsns = sctp_tsnmap_num_dups(map);
/* Initialize the SACK header. */ /* Initialize the SACK header. */
...@@ -618,12 +608,12 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc) ...@@ -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_gap_ack_blocks = htons(num_gabs);
sack.num_dup_tsns = htons(num_dup_tsns); sack.num_dup_tsns = htons(num_dup_tsns);
length = sizeof(sack) len = sizeof(sack)
+ sizeof(sctp_gap_ack_block_t) * num_gabs + sizeof(struct sctp_gap_ack_block) * num_gabs
+ sizeof(__u32) * num_dup_tsns; + sizeof(__u32) * num_dup_tsns;
/* Create the chunk. */ /* 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) if (!retval)
goto nodata; goto nodata;
...@@ -662,21 +652,15 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc) ...@@ -662,21 +652,15 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
retval->subh.sack_hdr = retval->subh.sack_hdr =
sctp_addto_chunk(retval, sizeof(sack), &sack); sctp_addto_chunk(retval, sizeof(sack), &sack);
/* Put the Gap Ack Blocks into the chunk. */ /* Add the gap ack block information. */
if (num_gabs) { if (num_gabs)
sctp_tsnmap_iter_init(map, &iter); sctp_addto_chunk(retval, sizeof(__u32) * num_gabs,
while(sctp_tsnmap_next_gap_ack(map, &iter, sctp_tsnmap_get_gabs(map));
&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);
}
}
/* Register the duplicates. */ /* Add the duplicate TSN information. */
sctp_addto_chunk(retval, sizeof(__u32) * num_dup_tsns, if (num_dup_tsns)
sctp_tsnmap_get_dups(map)); sctp_addto_chunk(retval, sizeof(__u32) * num_dup_tsns,
sctp_tsnmap_get_dups(map));
nodata: nodata:
return retval; return retval;
......
...@@ -2299,7 +2299,8 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval, ...@@ -2299,7 +2299,8 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval,
status.sstat_state = asoc->state; status.sstat_state = asoc->state;
status.sstat_rwnd = asoc->peer.rwnd; status.sstat_rwnd = asoc->peer.rwnd;
status.sstat_unackdata = asoc->unack_data; 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_instrms = asoc->c.sinit_max_instreams;
status.sstat_outstrms = asoc->c.sinit_num_ostreams; status.sstat_outstrms = asoc->c.sinit_num_ostreams;
/* Just in time frag_point update. */ /* Just in time frag_point update. */
......
...@@ -46,7 +46,6 @@ ...@@ -46,7 +46,6 @@
#include <net/sctp/sm.h> #include <net/sctp/sm.h>
static void sctp_tsnmap_update(struct sctp_tsnmap *map); 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, static void sctp_tsnmap_find_gap_ack(__u8 *map, __u16 off,
__u16 len, __u16 base, __u16 len, __u16 base,
int *started, __u16 *start, int *started, __u16 *start,
...@@ -92,7 +91,6 @@ struct sctp_tsnmap *sctp_tsnmap_init(struct sctp_tsnmap *map, __u16 len, ...@@ -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->cumulative_tsn_ack_point = initial_tsn - 1;
map->max_tsn_seen = map->cumulative_tsn_ack_point; map->max_tsn_seen = map->cumulative_tsn_ack_point;
map->malloced = 0; map->malloced = 0;
map->pending_data = 0;
map->num_dup_tsns = 0; map->num_dup_tsns = 0;
return map; return map;
...@@ -135,14 +133,6 @@ int sctp_tsnmap_check(const struct sctp_tsnmap *map, __u32 tsn) ...@@ -135,14 +133,6 @@ int sctp_tsnmap_check(const struct sctp_tsnmap *map, __u32 tsn)
return dup; 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. */ /* Mark this TSN as seen. */
void sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn) void sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn)
...@@ -176,21 +166,6 @@ 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); 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. */ /* Dispose of a tsnmap. */
void sctp_tsnmap_free(struct sctp_tsnmap *map) void sctp_tsnmap_free(struct sctp_tsnmap *map)
...@@ -304,10 +279,11 @@ static void sctp_tsnmap_update(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]); } while (map->tsn_map[ctsn - map->base_tsn]);
map->cumulative_tsn_ack_point = ctsn - 1; /* Back up one. */ 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 cum_tsn = map->cumulative_tsn_ack_point;
__u32 max_tsn = map->max_tsn_seen; __u32 max_tsn = map->max_tsn_seen;
...@@ -339,7 +315,7 @@ static void sctp_tsnmap_update_pending_data(struct sctp_tsnmap *map) ...@@ -339,7 +315,7 @@ static void sctp_tsnmap_update_pending_data(struct sctp_tsnmap *map)
} }
out: out:
map->pending_data = pending_data; return pending_data;
} }
/* This is a private helper for finding Gap Ack Blocks. It searches a /* 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, ...@@ -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. * early if we have found the end of the Gap Ack Block.
*/ */
/* Also, stop looking past the maximum TSN seen. */
/* Look for the start. */ /* Look for the start. */
if (!(*started)) { if (!(*started)) {
for (; i < len; i++) { for (; i < len; i++) {
...@@ -404,3 +382,26 @@ void sctp_tsnmap_renege(struct sctp_tsnmap *map, __u32 tsn) ...@@ -404,3 +382,26 @@ void sctp_tsnmap_renege(struct sctp_tsnmap *map, __u32 tsn)
else else
map->overflow_map[gap - map->len] = 0; 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