Skip to content

Commit 4422cc0

Browse files
committed
Merge branch 'sctp-refactor-MTU-handling'
Marcelo Ricardo Leitner says: ==================== sctp: refactor MTU handling Currently MTU handling is spread over SCTP stack. There are multiple places doing same/similar calculations and updating them is error prone as one spot can easily be left out. This patchset converges it into a more concise and consistent code. In general, it moves MTU handling from functions with bigger objectives, such as sctp_assoc_add_peer(), to specific functions. It's also a preparation for the next patchset, which removes the duplication between sctp_make_op_error_space and sctp_make_op_error_fixed and relies on sctp_mtu_payload introduced here. More details on each patch. ==================== Reviewed-by: Xin Long <lucien.xin@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2 parents 5a643c8 + 38687b5 commit 4422cc0

File tree

8 files changed

+105
-134
lines changed

8 files changed

+105
-134
lines changed

include/net/sctp/constants.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -254,11 +254,10 @@ enum { SCTP_ARBITRARY_COOKIE_ECHO_LEN = 200 };
254254
#define SCTP_TSN_MAP_SIZE 4096
255255

256256
/* We will not record more than this many duplicate TSNs between two
257-
* SACKs. The minimum PMTU is 576. Remove all the headers and there
258-
* is enough room for 131 duplicate reports. Round down to the
257+
* SACKs. The minimum PMTU is 512. Remove all the headers and there
258+
* is enough room for 117 duplicate reports. Round down to the
259259
* nearest power of 2.
260260
*/
261-
enum { SCTP_MIN_PMTU = 576 };
262261
enum { SCTP_MAX_DUP_TSNS = 16 };
263262
enum { SCTP_MAX_GABS = 16 };
264263

include/net/sctp/sctp.h

Lines changed: 19 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -428,32 +428,6 @@ static inline int sctp_list_single_entry(struct list_head *head)
428428
return (head->next != head) && (head->next == head->prev);
429429
}
430430

431-
/* Break down data chunks at this point. */
432-
static inline int sctp_frag_point(const struct sctp_association *asoc, int pmtu)
433-
{
434-
struct sctp_sock *sp = sctp_sk(asoc->base.sk);
435-
struct sctp_af *af = sp->pf->af;
436-
int frag = pmtu;
437-
438-
frag -= af->ip_options_len(asoc->base.sk);
439-
frag -= af->net_header_len;
440-
frag -= sizeof(struct sctphdr) + sctp_datachk_len(&asoc->stream);
441-
442-
if (asoc->user_frag)
443-
frag = min_t(int, frag, asoc->user_frag);
444-
445-
frag = SCTP_TRUNC4(min_t(int, frag, SCTP_MAX_CHUNK_LEN -
446-
sctp_datachk_len(&asoc->stream)));
447-
448-
return frag;
449-
}
450-
451-
static inline void sctp_assoc_pending_pmtu(struct sctp_association *asoc)
452-
{
453-
sctp_assoc_sync_pmtu(asoc);
454-
asoc->pmtu_pending = 0;
455-
}
456-
457431
static inline bool sctp_chunk_pending(const struct sctp_chunk *chunk)
458432
{
459433
return !list_empty(&chunk->list);
@@ -607,17 +581,29 @@ static inline struct dst_entry *sctp_transport_dst_check(struct sctp_transport *
607581
return t->dst;
608582
}
609583

610-
static inline bool sctp_transport_pmtu_check(struct sctp_transport *t)
584+
/* Calculate max payload size given a MTU, or the total overhead if
585+
* given MTU is zero
586+
*/
587+
static inline __u32 sctp_mtu_payload(const struct sctp_sock *sp,
588+
__u32 mtu, __u32 extra)
611589
{
612-
__u32 pmtu = max_t(size_t, SCTP_TRUNC4(dst_mtu(t->dst)),
613-
SCTP_DEFAULT_MINSEGMENT);
590+
__u32 overhead = sizeof(struct sctphdr) + extra;
614591

615-
if (t->pathmtu == pmtu)
616-
return true;
592+
if (sp)
593+
overhead += sp->pf->af->net_header_len;
594+
else
595+
overhead += sizeof(struct ipv6hdr);
617596

618-
t->pathmtu = pmtu;
597+
if (WARN_ON_ONCE(mtu && mtu <= overhead))
598+
mtu = overhead;
619599

620-
return false;
600+
return mtu ? mtu - overhead : overhead;
601+
}
602+
603+
static inline __u32 sctp_dst_mtu(const struct dst_entry *dst)
604+
{
605+
return SCTP_TRUNC4(max_t(__u32, dst_mtu(dst),
606+
SCTP_DEFAULT_MINSEGMENT));
621607
}
622608

623609
#endif /* __net_sctp_h__ */

include/net/sctp/structs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2097,6 +2097,8 @@ int sctp_assoc_update(struct sctp_association *old,
20972097

20982098
__u32 sctp_association_get_next_tsn(struct sctp_association *);
20992099

2100+
void sctp_assoc_update_frag_point(struct sctp_association *asoc);
2101+
void sctp_assoc_set_pmtu(struct sctp_association *asoc, __u32 pmtu);
21002102
void sctp_assoc_sync_pmtu(struct sctp_association *asoc);
21012103
void sctp_assoc_rwnd_increase(struct sctp_association *, unsigned int);
21022104
void sctp_assoc_rwnd_decrease(struct sctp_association *, unsigned int);

net/sctp/associola.c

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -652,33 +652,20 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
652652
*/
653653
peer->param_flags = asoc->param_flags;
654654

655-
sctp_transport_route(peer, NULL, sp);
656-
657655
/* Initialize the pmtu of the transport. */
658-
if (peer->param_flags & SPP_PMTUD_DISABLE) {
659-
if (asoc->pathmtu)
660-
peer->pathmtu = asoc->pathmtu;
661-
else
662-
peer->pathmtu = SCTP_DEFAULT_MAXSEGMENT;
663-
}
656+
sctp_transport_route(peer, NULL, sp);
664657

665658
/* If this is the first transport addr on this association,
666659
* initialize the association PMTU to the peer's PMTU.
667660
* If not and the current association PMTU is higher than the new
668661
* peer's PMTU, reset the association PMTU to the new peer's PMTU.
669662
*/
670-
if (asoc->pathmtu)
671-
asoc->pathmtu = min_t(int, peer->pathmtu, asoc->pathmtu);
672-
else
673-
asoc->pathmtu = peer->pathmtu;
674-
675-
pr_debug("%s: association:%p PMTU set to %d\n", __func__, asoc,
676-
asoc->pathmtu);
663+
sctp_assoc_set_pmtu(asoc, asoc->pathmtu ?
664+
min_t(int, peer->pathmtu, asoc->pathmtu) :
665+
peer->pathmtu);
677666

678667
peer->pmtu_pending = 0;
679668

680-
asoc->frag_point = sctp_frag_point(asoc, asoc->pathmtu);
681-
682669
/* The asoc->peer.port might not be meaningful yet, but
683670
* initialize the packet structure anyway.
684671
*/
@@ -1381,6 +1368,31 @@ sctp_assoc_choose_alter_transport(struct sctp_association *asoc,
13811368
}
13821369
}
13831370

1371+
void sctp_assoc_update_frag_point(struct sctp_association *asoc)
1372+
{
1373+
int frag = sctp_mtu_payload(sctp_sk(asoc->base.sk), asoc->pathmtu,
1374+
sctp_datachk_len(&asoc->stream));
1375+
1376+
if (asoc->user_frag)
1377+
frag = min_t(int, frag, asoc->user_frag);
1378+
1379+
frag = min_t(int, frag, SCTP_MAX_CHUNK_LEN -
1380+
sctp_datachk_len(&asoc->stream));
1381+
1382+
asoc->frag_point = SCTP_TRUNC4(frag);
1383+
}
1384+
1385+
void sctp_assoc_set_pmtu(struct sctp_association *asoc, __u32 pmtu)
1386+
{
1387+
if (asoc->pathmtu != pmtu) {
1388+
asoc->pathmtu = pmtu;
1389+
sctp_assoc_update_frag_point(asoc);
1390+
}
1391+
1392+
pr_debug("%s: asoc:%p, pmtu:%d, frag_point:%d\n", __func__, asoc,
1393+
asoc->pathmtu, asoc->frag_point);
1394+
}
1395+
13841396
/* Update the association's pmtu and frag_point by going through all the
13851397
* transports. This routine is called when a transport's PMTU has changed.
13861398
*/
@@ -1393,24 +1405,16 @@ void sctp_assoc_sync_pmtu(struct sctp_association *asoc)
13931405
return;
13941406

13951407
/* Get the lowest pmtu of all the transports. */
1396-
list_for_each_entry(t, &asoc->peer.transport_addr_list,
1397-
transports) {
1408+
list_for_each_entry(t, &asoc->peer.transport_addr_list, transports) {
13981409
if (t->pmtu_pending && t->dst) {
1399-
sctp_transport_update_pmtu(
1400-
t, SCTP_TRUNC4(dst_mtu(t->dst)));
1410+
sctp_transport_update_pmtu(t, sctp_dst_mtu(t->dst));
14011411
t->pmtu_pending = 0;
14021412
}
14031413
if (!pmtu || (t->pathmtu < pmtu))
14041414
pmtu = t->pathmtu;
14051415
}
14061416

1407-
if (pmtu) {
1408-
asoc->pathmtu = pmtu;
1409-
asoc->frag_point = sctp_frag_point(asoc, pmtu);
1410-
}
1411-
1412-
pr_debug("%s: asoc:%p, pmtu:%d, frag_point:%d\n", __func__, asoc,
1413-
asoc->pathmtu, asoc->frag_point);
1417+
sctp_assoc_set_pmtu(asoc, pmtu);
14141418
}
14151419

14161420
/* Should we send a SACK to update our peer? */

net/sctp/chunk.c

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -172,8 +172,6 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
172172
struct list_head *pos, *temp;
173173
struct sctp_chunk *chunk;
174174
struct sctp_datamsg *msg;
175-
struct sctp_sock *sp;
176-
struct sctp_af *af;
177175
int err;
178176

179177
msg = sctp_datamsg_new(GFP_KERNEL);
@@ -192,12 +190,7 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
192190
/* This is the biggest possible DATA chunk that can fit into
193191
* the packet
194192
*/
195-
sp = sctp_sk(asoc->base.sk);
196-
af = sp->pf->af;
197-
max_data = asoc->pathmtu - af->net_header_len -
198-
sizeof(struct sctphdr) - sctp_datachk_len(&asoc->stream) -
199-
af->ip_options_len(asoc->base.sk);
200-
max_data = SCTP_TRUNC4(max_data);
193+
max_data = asoc->frag_point;
201194

202195
/* If the the peer requested that we authenticate DATA chunks
203196
* we need to account for bundling of the AUTH chunks along with
@@ -222,9 +215,6 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
222215
}
223216
}
224217

225-
/* Check what's our max considering the above */
226-
max_data = min_t(size_t, max_data, asoc->frag_point);
227-
228218
/* Set first_len and then account for possible bundles on first frag */
229219
first_len = max_data;
230220

net/sctp/output.c

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,8 @@ void sctp_packet_config(struct sctp_packet *packet, __u32 vtag,
9090
{
9191
struct sctp_transport *tp = packet->transport;
9292
struct sctp_association *asoc = tp->asoc;
93+
struct sctp_sock *sp = NULL;
9394
struct sock *sk;
94-
size_t overhead = sizeof(struct ipv6hdr) + sizeof(struct sctphdr);
9595

9696
pr_debug("%s: packet:%p vtag:0x%x\n", __func__, packet, vtag);
9797
packet->vtag = vtag;
@@ -102,28 +102,20 @@ void sctp_packet_config(struct sctp_packet *packet, __u32 vtag,
102102

103103
/* set packet max_size with pathmtu, then calculate overhead */
104104
packet->max_size = tp->pathmtu;
105+
105106
if (asoc) {
106-
struct sctp_sock *sp = sctp_sk(asoc->base.sk);
107-
struct sctp_af *af = sp->pf->af;
108-
109-
overhead = af->net_header_len +
110-
af->ip_options_len(asoc->base.sk);
111-
overhead += sizeof(struct sctphdr);
112-
packet->overhead = overhead;
113-
packet->size = overhead;
114-
} else {
115-
packet->overhead = overhead;
116-
packet->size = overhead;
117-
return;
107+
sk = asoc->base.sk;
108+
sp = sctp_sk(sk);
118109
}
110+
packet->overhead = sctp_mtu_payload(sp, 0, 0);
111+
packet->size = packet->overhead;
112+
113+
if (!asoc)
114+
return;
119115

120116
/* update dst or transport pathmtu if in need */
121-
sk = asoc->base.sk;
122117
if (!sctp_transport_dst_check(tp)) {
123-
sctp_transport_route(tp, NULL, sctp_sk(sk));
124-
if (asoc->param_flags & SPP_PMTUD_ENABLE)
125-
sctp_assoc_sync_pmtu(asoc);
126-
} else if (!sctp_transport_pmtu_check(tp)) {
118+
sctp_transport_route(tp, NULL, sp);
127119
if (asoc->param_flags & SPP_PMTUD_ENABLE)
128120
sctp_assoc_sync_pmtu(asoc);
129121
}

net/sctp/socket.c

Lines changed: 19 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -644,16 +644,15 @@ static int sctp_send_asconf_add_ip(struct sock *sk,
644644

645645
list_for_each_entry(trans,
646646
&asoc->peer.transport_addr_list, transports) {
647-
/* Clear the source and route cache */
648-
sctp_transport_dst_release(trans);
649647
trans->cwnd = min(4*asoc->pathmtu, max_t(__u32,
650648
2*asoc->pathmtu, 4380));
651649
trans->ssthresh = asoc->peer.i.a_rwnd;
652650
trans->rto = asoc->rto_initial;
653651
sctp_max_rto(asoc, trans);
654652
trans->rtt = trans->srtt = trans->rttvar = 0;
653+
/* Clear the source and route cache */
655654
sctp_transport_route(trans, NULL,
656-
sctp_sk(asoc->base.sk));
655+
sctp_sk(asoc->base.sk));
657656
}
658657
}
659658
retval = sctp_send_asconf(asoc, chunk);
@@ -896,7 +895,6 @@ static int sctp_send_asconf_del_ip(struct sock *sk,
896895
*/
897896
list_for_each_entry(transport, &asoc->peer.transport_addr_list,
898897
transports) {
899-
sctp_transport_dst_release(transport);
900898
sctp_transport_route(transport, NULL,
901899
sctp_sk(asoc->base.sk));
902900
}
@@ -1895,6 +1893,7 @@ static int sctp_sendmsg_to_asoc(struct sctp_association *asoc,
18951893
struct sctp_sndrcvinfo *sinfo)
18961894
{
18971895
struct sock *sk = asoc->base.sk;
1896+
struct sctp_sock *sp = sctp_sk(sk);
18981897
struct net *net = sock_net(sk);
18991898
struct sctp_datamsg *datamsg;
19001899
bool wait_connect = false;
@@ -1913,13 +1912,16 @@ static int sctp_sendmsg_to_asoc(struct sctp_association *asoc,
19131912
goto err;
19141913
}
19151914

1916-
if (sctp_sk(sk)->disable_fragments && msg_len > asoc->frag_point) {
1915+
if (sp->disable_fragments && msg_len > asoc->frag_point) {
19171916
err = -EMSGSIZE;
19181917
goto err;
19191918
}
19201919

1921-
if (asoc->pmtu_pending)
1922-
sctp_assoc_pending_pmtu(asoc);
1920+
if (asoc->pmtu_pending) {
1921+
if (sp->param_flags & SPP_PMTUD_ENABLE)
1922+
sctp_assoc_sync_pmtu(asoc);
1923+
asoc->pmtu_pending = 0;
1924+
}
19231925

19241926
if (sctp_wspace(asoc) < msg_len)
19251927
sctp_prsctp_prune(asoc, sinfo, msg_len - sctp_wspace(asoc));
@@ -1936,7 +1938,7 @@ static int sctp_sendmsg_to_asoc(struct sctp_association *asoc,
19361938
if (err)
19371939
goto err;
19381940

1939-
if (sctp_sk(sk)->strm_interleave) {
1941+
if (sp->strm_interleave) {
19401942
timeo = sock_sndtimeo(sk, 0);
19411943
err = sctp_wait_for_connect(asoc, &timeo);
19421944
if (err)
@@ -2539,7 +2541,7 @@ static int sctp_apply_peer_addr_params(struct sctp_paddrparams *params,
25392541
trans->pathmtu = params->spp_pathmtu;
25402542
sctp_assoc_sync_pmtu(asoc);
25412543
} else if (asoc) {
2542-
asoc->pathmtu = params->spp_pathmtu;
2544+
sctp_assoc_set_pmtu(asoc, params->spp_pathmtu);
25432545
} else {
25442546
sp->pathmtu = params->spp_pathmtu;
25452547
}
@@ -3209,7 +3211,6 @@ static int sctp_setsockopt_mappedv4(struct sock *sk, char __user *optval, unsign
32093211
static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, unsigned int optlen)
32103212
{
32113213
struct sctp_sock *sp = sctp_sk(sk);
3212-
struct sctp_af *af = sp->pf->af;
32133214
struct sctp_assoc_value params;
32143215
struct sctp_association *asoc;
32153216
int val;
@@ -3231,30 +3232,24 @@ static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, unsigned
32313232
return -EINVAL;
32323233
}
32333234

3235+
asoc = sctp_id2assoc(sk, params.assoc_id);
3236+
32343237
if (val) {
32353238
int min_len, max_len;
3239+
__u16 datasize = asoc ? sctp_datachk_len(&asoc->stream) :
3240+
sizeof(struct sctp_data_chunk);
32363241

3237-
min_len = SCTP_DEFAULT_MINSEGMENT - af->net_header_len;
3238-
min_len -= af->ip_options_len(sk);
3239-
min_len -= sizeof(struct sctphdr) +
3240-
sizeof(struct sctp_data_chunk);
3241-
3242-
max_len = SCTP_MAX_CHUNK_LEN - sizeof(struct sctp_data_chunk);
3242+
min_len = sctp_mtu_payload(sp, SCTP_DEFAULT_MINSEGMENT,
3243+
datasize);
3244+
max_len = SCTP_MAX_CHUNK_LEN - datasize;
32433245

32443246
if (val < min_len || val > max_len)
32453247
return -EINVAL;
32463248
}
32473249

3248-
asoc = sctp_id2assoc(sk, params.assoc_id);
32493250
if (asoc) {
3250-
if (val == 0) {
3251-
val = asoc->pathmtu - af->net_header_len;
3252-
val -= af->ip_options_len(sk);
3253-
val -= sizeof(struct sctphdr) +
3254-
sctp_datachk_len(&asoc->stream);
3255-
}
32563251
asoc->user_frag = val;
3257-
asoc->frag_point = sctp_frag_point(asoc, asoc->pathmtu);
3252+
sctp_assoc_update_frag_point(asoc);
32583253
} else {
32593254
if (params.assoc_id && sctp_style(sk, UDP))
32603255
return -EINVAL;

0 commit comments

Comments
 (0)