Skip to content

Commit fe59379

Browse files
lxindavem330
authored andcommitted
sctp: do the basic send and recv for PLPMTUD probe
This patch does exactly what rfc8899#section-6.2.1.2 says: The SCTP sender needs to be able to determine the total size of a probe packet. The HEARTBEAT chunk could carry a Heartbeat Information parameter that includes, besides the information suggested in [RFC4960], the probe size to help an implementation associate a HEARTBEAT ACK with the size of probe that was sent. The sender could also use other methods, such as sending a nonce and verifying the information returned also contains the corresponding nonce. The length of the PAD chunk is computed by reducing the probing size by the size of the SCTP common header and the HEARTBEAT chunk. Note that HB ACK chunk will carry back whatever HB chunk carried, including the probe_size we put it in; We also check hbinfo->probe_size in the HB ACK against link->pl.probe_size to validate this HB ACK chunk. v1->v2: - Remove the unused 'sp' and add static for sctp_packet_bundle_pad(). Signed-off-by: Xin Long <lucien.xin@gmail.com> Acked-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 92548ec commit fe59379

File tree

6 files changed

+66
-7
lines changed

6 files changed

+66
-7
lines changed

include/net/sctp/sm.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,8 @@ struct sctp_chunk *sctp_make_new_encap_port(
226226
const struct sctp_association *asoc,
227227
const struct sctp_chunk *chunk);
228228
struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *asoc,
229-
const struct sctp_transport *transport);
229+
const struct sctp_transport *transport,
230+
__u32 probe_size);
230231
struct sctp_chunk *sctp_make_heartbeat_ack(const struct sctp_association *asoc,
231232
const struct sctp_chunk *chunk,
232233
const void *payload,

include/net/sctp/structs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,7 @@ struct sctp_sender_hb_info {
386386
union sctp_addr daddr;
387387
unsigned long sent_at;
388388
__u64 hb_nonce;
389+
__u32 probe_size;
389390
};
390391

391392
int sctp_stream_init(struct sctp_stream *stream, __u16 outcnt, __u16 incnt,
@@ -657,6 +658,7 @@ struct sctp_chunk {
657658
data_accepted:1, /* At least 1 chunk accepted */
658659
auth:1, /* IN: was auth'ed | OUT: needs auth */
659660
has_asconf:1, /* IN: have seen an asconf before */
661+
pmtu_probe:1, /* Used by PLPMTUD, can be set in s HB chunk */
660662
tsn_missing_report:2, /* Data chunk missing counter. */
661663
fast_retransmit:2; /* Is this chunk fast retransmitted? */
662664
};

net/sctp/output.c

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,30 @@ enum sctp_xmit sctp_packet_transmit_chunk(struct sctp_packet *packet,
211211
return retval;
212212
}
213213

214+
/* Try to bundle a pad chunk into a packet with a heartbeat chunk for PLPMTUTD probe */
215+
static enum sctp_xmit sctp_packet_bundle_pad(struct sctp_packet *pkt, struct sctp_chunk *chunk)
216+
{
217+
struct sctp_transport *t = pkt->transport;
218+
struct sctp_chunk *pad;
219+
int overhead = 0;
220+
221+
if (!chunk->pmtu_probe)
222+
return SCTP_XMIT_OK;
223+
224+
/* calculate the Padding Data size for the pad chunk */
225+
overhead += sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr);
226+
overhead += sizeof(struct sctp_sender_hb_info) + sizeof(struct sctp_pad_chunk);
227+
pad = sctp_make_pad(t->asoc, t->pl.probe_size - overhead);
228+
if (!pad)
229+
return SCTP_XMIT_DELAY;
230+
231+
list_add_tail(&pad->list, &pkt->chunk_list);
232+
pkt->size += SCTP_PAD4(ntohs(pad->chunk_hdr->length));
233+
chunk->transport = t;
234+
235+
return SCTP_XMIT_OK;
236+
}
237+
214238
/* Try to bundle an auth chunk into the packet. */
215239
static enum sctp_xmit sctp_packet_bundle_auth(struct sctp_packet *pkt,
216240
struct sctp_chunk *chunk)
@@ -382,6 +406,10 @@ enum sctp_xmit sctp_packet_append_chunk(struct sctp_packet *packet,
382406
goto finish;
383407

384408
retval = __sctp_packet_append_chunk(packet, chunk);
409+
if (retval != SCTP_XMIT_OK)
410+
goto finish;
411+
412+
retval = sctp_packet_bundle_pad(packet, chunk);
385413

386414
finish:
387415
return retval;
@@ -553,7 +581,7 @@ int sctp_packet_transmit(struct sctp_packet *packet, gfp_t gfp)
553581
sk = chunk->skb->sk;
554582

555583
/* check gso */
556-
if (packet->size > tp->pathmtu && !packet->ipfragok) {
584+
if (packet->size > tp->pathmtu && !packet->ipfragok && !chunk->pmtu_probe) {
557585
if (!sk_can_gso(sk)) {
558586
pr_err_once("Trying to GSO but underlying device doesn't support it.");
559587
goto out;

net/sctp/outqueue.c

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -769,7 +769,11 @@ static int sctp_packet_singleton(struct sctp_transport *transport,
769769

770770
sctp_packet_init(&singleton, transport, sport, dport);
771771
sctp_packet_config(&singleton, vtag, 0);
772-
sctp_packet_append_chunk(&singleton, chunk);
772+
if (sctp_packet_append_chunk(&singleton, chunk) != SCTP_XMIT_OK) {
773+
list_del_init(&chunk->list);
774+
sctp_chunk_free(chunk);
775+
return -ENOMEM;
776+
}
773777
return sctp_packet_transmit(&singleton, gfp);
774778
}
775779

@@ -929,8 +933,13 @@ static void sctp_outq_flush_ctrl(struct sctp_flush_ctx *ctx)
929933
one_packet = 1;
930934
fallthrough;
931935

932-
case SCTP_CID_SACK:
933936
case SCTP_CID_HEARTBEAT:
937+
if (chunk->pmtu_probe) {
938+
sctp_packet_singleton(ctx->transport, chunk, ctx->gfp);
939+
break;
940+
}
941+
fallthrough;
942+
case SCTP_CID_SACK:
934943
case SCTP_CID_SHUTDOWN:
935944
case SCTP_CID_ECN_ECNE:
936945
case SCTP_CID_ASCONF:

net/sctp/sm_make_chunk.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1160,7 +1160,8 @@ struct sctp_chunk *sctp_make_new_encap_port(const struct sctp_association *asoc,
11601160

11611161
/* Make a HEARTBEAT chunk. */
11621162
struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *asoc,
1163-
const struct sctp_transport *transport)
1163+
const struct sctp_transport *transport,
1164+
__u32 probe_size)
11641165
{
11651166
struct sctp_sender_hb_info hbinfo;
11661167
struct sctp_chunk *retval;
@@ -1176,13 +1177,15 @@ struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *asoc,
11761177
hbinfo.daddr = transport->ipaddr;
11771178
hbinfo.sent_at = jiffies;
11781179
hbinfo.hb_nonce = transport->hb_nonce;
1180+
hbinfo.probe_size = probe_size;
11791181

11801182
/* Cast away the 'const', as this is just telling the chunk
11811183
* what transport it belongs to.
11821184
*/
11831185
retval->transport = (struct sctp_transport *) transport;
11841186
retval->subh.hbs_hdr = sctp_addto_chunk(retval, sizeof(hbinfo),
11851187
&hbinfo);
1188+
retval->pmtu_probe = !!probe_size;
11861189

11871190
nodata:
11881191
return retval;

net/sctp/sm_statefuns.c

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1004,7 +1004,7 @@ static enum sctp_disposition sctp_sf_heartbeat(
10041004
struct sctp_chunk *reply;
10051005

10061006
/* Send a heartbeat to our peer. */
1007-
reply = sctp_make_heartbeat(asoc, transport);
1007+
reply = sctp_make_heartbeat(asoc, transport, 0);
10081008
if (!reply)
10091009
return SCTP_DISPOSITION_NOMEM;
10101010

@@ -1104,8 +1104,15 @@ enum sctp_disposition sctp_sf_send_probe(struct net *net,
11041104
struct sctp_cmd_seq *commands)
11051105
{
11061106
struct sctp_transport *transport = (struct sctp_transport *)arg;
1107+
struct sctp_chunk *reply;
1108+
1109+
if (!sctp_transport_pl_enabled(transport))
1110+
return SCTP_DISPOSITION_CONSUME;
11071111

1108-
/* The actual handling will be performed here in a later patch. */
1112+
reply = sctp_make_heartbeat(asoc, transport, transport->pl.probe_size);
1113+
if (!reply)
1114+
return SCTP_DISPOSITION_NOMEM;
1115+
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply));
11091116
sctp_add_cmd_sf(commands, SCTP_CMD_PROBE_TIMER_UPDATE,
11101117
SCTP_TRANSPORT(transport));
11111118

@@ -1260,6 +1267,15 @@ enum sctp_disposition sctp_sf_backbeat_8_3(struct net *net,
12601267
if (hbinfo->hb_nonce != link->hb_nonce)
12611268
return SCTP_DISPOSITION_DISCARD;
12621269

1270+
if (hbinfo->probe_size) {
1271+
if (hbinfo->probe_size != link->pl.probe_size ||
1272+
!sctp_transport_pl_enabled(link))
1273+
return SCTP_DISPOSITION_DISCARD;
1274+
1275+
/* The actual handling will be performed here in a later patch. */
1276+
return SCTP_DISPOSITION_CONSUME;
1277+
}
1278+
12631279
max_interval = link->hbinterval + link->rto;
12641280

12651281
/* Check if the timestamp looks valid. */

0 commit comments

Comments
 (0)