Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

sctp: add the probe timer in transport for PLPMTUD

There are 3 timers described in rfc8899#section-5.1.1:

PROBE_TIMER, PMTU_RAISE_TIMER, CONFIRMATION_TIMER

This patches adds a 'probe_timer' in transport, and it works as either
PROBE_TIMER or PMTU_RAISE_TIMER. At most time, it works as PROBE_TIMER
and expires every a 'probe_interval' time to send the HB probe packet.
When transport pl enters COMPLETE state, it works as PMTU_RAISE_TIMER
and expires in 'probe_interval * 30' time to go back to SEARCH state
and do searching again.

SCTP HB is an acknowledged packet, CONFIRMATION_TIMER is not needed.

The timer will start when transport pl enters BASE state and stop
when it enters DISABLED state.

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>

authored by

Xin Long and committed by
David S. Miller
92548ec2 d9e2e410

+109 -1
+1
include/net/sctp/command.h
··· 59 59 SCTP_CMD_HB_TIMERS_START, /* Start the heartbeat timers. */ 60 60 SCTP_CMD_HB_TIMER_UPDATE, /* Update a heartbeat timers. */ 61 61 SCTP_CMD_HB_TIMERS_STOP, /* Stop the heartbeat timers. */ 62 + SCTP_CMD_PROBE_TIMER_UPDATE, /* Update a probe timer. */ 62 63 SCTP_CMD_TRANSPORT_HB_SENT, /* Reset the status of a transport. */ 63 64 SCTP_CMD_TRANSPORT_IDLE, /* Do manipulations on idle transport */ 64 65 SCTP_CMD_TRANSPORT_ON, /* Mark the transport as active. */
+1
include/net/sctp/constants.h
··· 77 77 SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD, 78 78 SCTP_EVENT_TIMEOUT_HEARTBEAT, 79 79 SCTP_EVENT_TIMEOUT_RECONF, 80 + SCTP_EVENT_TIMEOUT_PROBE, 80 81 SCTP_EVENT_TIMEOUT_SACK, 81 82 SCTP_EVENT_TIMEOUT_AUTOCLOSE, 82 83 };
+8 -1
include/net/sctp/sctp.h
··· 635 635 t->pl.state = SCTP_PL_BASE; 636 636 t->pl.pmtu = SCTP_BASE_PLPMTU; 637 637 t->pl.probe_size = SCTP_BASE_PLPMTU; 638 + sctp_transport_reset_probe_timer(t); 638 639 } 639 640 } else { 640 - if (t->pl.state != SCTP_PL_DISABLED) 641 + if (t->pl.state != SCTP_PL_DISABLED) { 642 + if (del_timer(&t->probe_timer)) 643 + sctp_transport_put(t); 641 644 t->pl.state = SCTP_PL_DISABLED; 645 + } 642 646 } 643 647 } 644 648 ··· 650 646 { 651 647 if (t->pl.state == SCTP_PL_DISABLED) 652 648 return; 649 + 650 + if (del_timer(&t->probe_timer)) 651 + sctp_transport_put(t); 653 652 654 653 t->pl.state = SCTP_PL_BASE; 655 654 t->pl.pmtu = SCTP_BASE_PLPMTU;
+2
include/net/sctp/sm.h
··· 151 151 /* Prototypes for timeout event state functions. */ 152 152 sctp_state_fn_t sctp_sf_do_6_3_3_rtx; 153 153 sctp_state_fn_t sctp_sf_send_reconf; 154 + sctp_state_fn_t sctp_sf_send_probe; 154 155 sctp_state_fn_t sctp_sf_do_6_2_sack; 155 156 sctp_state_fn_t sctp_sf_autoclose_timer_expire; 156 157 ··· 312 311 void sctp_generate_t3_rtx_event(struct timer_list *t); 313 312 void sctp_generate_heartbeat_event(struct timer_list *t); 314 313 void sctp_generate_reconf_event(struct timer_list *t); 314 + void sctp_generate_probe_event(struct timer_list *t); 315 315 void sctp_generate_proto_unreach_event(struct timer_list *t); 316 316 317 317 void sctp_ootb_pkt_free(struct sctp_packet *packet);
+4
include/net/sctp/structs.h
··· 936 936 /* Timer to handler reconf chunk rtx */ 937 937 struct timer_list reconf_timer; 938 938 939 + /* Timer to send a probe HB packet for PLPMTUD */ 940 + struct timer_list probe_timer; 941 + 939 942 /* Since we're using per-destination retransmission timers 940 943 * (see above), we're also using per-destination "transmitted" 941 944 * queues. This probably ought to be a private struct ··· 1006 1003 void sctp_transport_reset_t3_rtx(struct sctp_transport *); 1007 1004 void sctp_transport_reset_hb_timer(struct sctp_transport *); 1008 1005 void sctp_transport_reset_reconf_timer(struct sctp_transport *transport); 1006 + void sctp_transport_reset_probe_timer(struct sctp_transport *transport); 1009 1007 int sctp_transport_hold(struct sctp_transport *); 1010 1008 void sctp_transport_put(struct sctp_transport *); 1011 1009 void sctp_transport_update_rto(struct sctp_transport *, __u32);
+1
net/sctp/debug.c
··· 154 154 "TIMEOUT_T5_SHUTDOWN_GUARD", 155 155 "TIMEOUT_HEARTBEAT", 156 156 "TIMEOUT_RECONF", 157 + "TIMEOUT_PROBE", 157 158 "TIMEOUT_SACK", 158 159 "TIMEOUT_AUTOCLOSE", 159 160 };
+37
net/sctp/sm_sideeffect.c
··· 471 471 sctp_transport_put(transport); 472 472 } 473 473 474 + /* Handle the timeout of the probe timer. */ 475 + void sctp_generate_probe_event(struct timer_list *t) 476 + { 477 + struct sctp_transport *transport = from_timer(transport, t, probe_timer); 478 + struct sctp_association *asoc = transport->asoc; 479 + struct sock *sk = asoc->base.sk; 480 + struct net *net = sock_net(sk); 481 + int error = 0; 482 + 483 + bh_lock_sock(sk); 484 + if (sock_owned_by_user(sk)) { 485 + pr_debug("%s: sock is busy\n", __func__); 486 + 487 + /* Try again later. */ 488 + if (!mod_timer(&transport->probe_timer, jiffies + (HZ / 20))) 489 + sctp_transport_hold(transport); 490 + goto out_unlock; 491 + } 492 + 493 + error = sctp_do_sm(net, SCTP_EVENT_T_TIMEOUT, 494 + SCTP_ST_TIMEOUT(SCTP_EVENT_TIMEOUT_PROBE), 495 + asoc->state, asoc->ep, asoc, 496 + transport, GFP_ATOMIC); 497 + 498 + if (error) 499 + sk->sk_err = -error; 500 + 501 + out_unlock: 502 + bh_unlock_sock(sk); 503 + sctp_transport_put(transport); 504 + } 505 + 474 506 /* Inject a SACK Timeout event into the state machine. */ 475 507 static void sctp_generate_sack_event(struct timer_list *t) 476 508 { ··· 1671 1639 1672 1640 case SCTP_CMD_HB_TIMERS_STOP: 1673 1641 sctp_cmd_hb_timers_stop(commands, asoc); 1642 + break; 1643 + 1644 + case SCTP_CMD_PROBE_TIMER_UPDATE: 1645 + t = cmd->obj.transport; 1646 + sctp_transport_reset_probe_timer(t); 1674 1647 break; 1675 1648 1676 1649 case SCTP_CMD_REPORT_ERROR:
+17
net/sctp/sm_statefuns.c
··· 1095 1095 return SCTP_DISPOSITION_CONSUME; 1096 1096 } 1097 1097 1098 + /* send hb chunk with padding for PLPMUTD. */ 1099 + enum sctp_disposition sctp_sf_send_probe(struct net *net, 1100 + const struct sctp_endpoint *ep, 1101 + const struct sctp_association *asoc, 1102 + const union sctp_subtype type, 1103 + void *arg, 1104 + struct sctp_cmd_seq *commands) 1105 + { 1106 + struct sctp_transport *transport = (struct sctp_transport *)arg; 1107 + 1108 + /* The actual handling will be performed here in a later patch. */ 1109 + sctp_add_cmd_sf(commands, SCTP_CMD_PROBE_TIMER_UPDATE, 1110 + SCTP_TRANSPORT(transport)); 1111 + 1112 + return SCTP_DISPOSITION_CONSUME; 1113 + } 1114 + 1098 1115 /* 1099 1116 * Process an heartbeat request. 1100 1117 *
+20
net/sctp/sm_statetable.c
··· 967 967 TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \ 968 968 } 969 969 970 + #define TYPE_SCTP_EVENT_TIMEOUT_PROBE { \ 971 + /* SCTP_STATE_CLOSED */ \ 972 + TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \ 973 + /* SCTP_STATE_COOKIE_WAIT */ \ 974 + TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \ 975 + /* SCTP_STATE_COOKIE_ECHOED */ \ 976 + TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \ 977 + /* SCTP_STATE_ESTABLISHED */ \ 978 + TYPE_SCTP_FUNC(sctp_sf_send_probe), \ 979 + /* SCTP_STATE_SHUTDOWN_PENDING */ \ 980 + TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \ 981 + /* SCTP_STATE_SHUTDOWN_SENT */ \ 982 + TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \ 983 + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ 984 + TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \ 985 + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ 986 + TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \ 987 + } 988 + 970 989 static const struct sctp_sm_table_entry 971 990 timeout_event_table[SCTP_NUM_TIMEOUT_TYPES][SCTP_STATE_NUM_STATES] = { 972 991 TYPE_SCTP_EVENT_TIMEOUT_NONE, ··· 997 978 TYPE_SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD, 998 979 TYPE_SCTP_EVENT_TIMEOUT_HEARTBEAT, 999 980 TYPE_SCTP_EVENT_TIMEOUT_RECONF, 981 + TYPE_SCTP_EVENT_TIMEOUT_PROBE, 1000 982 TYPE_SCTP_EVENT_TIMEOUT_SACK, 1001 983 TYPE_SCTP_EVENT_TIMEOUT_AUTOCLOSE, 1002 984 };
+18
net/sctp/transport.c
··· 75 75 timer_setup(&peer->T3_rtx_timer, sctp_generate_t3_rtx_event, 0); 76 76 timer_setup(&peer->hb_timer, sctp_generate_heartbeat_event, 0); 77 77 timer_setup(&peer->reconf_timer, sctp_generate_reconf_event, 0); 78 + timer_setup(&peer->probe_timer, sctp_generate_probe_event, 0); 78 79 timer_setup(&peer->proto_unreach_timer, 79 80 sctp_generate_proto_unreach_event, 0); 80 81 ··· 130 129 sctp_transport_put(transport); 131 130 132 131 if (del_timer(&transport->reconf_timer)) 132 + sctp_transport_put(transport); 133 + 134 + if (del_timer(&transport->probe_timer)) 133 135 sctp_transport_put(transport); 134 136 135 137 /* Delete the ICMP proto unreachable timer if it's active. */ ··· 209 205 if (!mod_timer(&transport->reconf_timer, 210 206 jiffies + transport->rto)) 211 207 sctp_transport_hold(transport); 208 + } 209 + 210 + void sctp_transport_reset_probe_timer(struct sctp_transport *transport) 211 + { 212 + int scale = 1; 213 + 214 + if (timer_pending(&transport->probe_timer)) 215 + return; 216 + if (transport->pl.state == SCTP_PL_COMPLETE && 217 + transport->pl.probe_count == 1) 218 + scale = 30; /* works as PMTU_RAISE_TIMER */ 219 + if (!mod_timer(&transport->probe_timer, 220 + jiffies + transport->probe_interval * scale)) 221 + sctp_transport_hold(transport); 212 222 } 213 223 214 224 /* This transport has been assigned to an association.