/* Initialize the 64-bit random nonce sent with heartbeat. */
get_random_bytes(&peer->hb_nonce, sizeof(peer->hb_nonce));
refcount_set(&peer->refcnt, 1);
return peer;
}
/* Allocate and initialize a new transport. */ struct sctp_transport *sctp_transport_new(struct net *net, constunion sctp_addr *addr,
gfp_t gfp)
{ struct sctp_transport *transport;
transport = kzalloc(sizeof(*transport), gfp); if (!transport) goto fail;
if (!sctp_transport_init(net, transport, addr, gfp)) goto fail_init;
SCTP_DBG_OBJCNT_INC(transport);
return transport;
fail_init:
kfree(transport);
fail: return NULL;
}
/* This transport is no longer needed. Free up if possible, or *delayuntilitlastreferencecount.
*/ void sctp_transport_free(struct sctp_transport *transport)
{
transport->dead = 1;
/* Try to delete the heartbeat timer. */ if (timer_delete(&transport->hb_timer))
sctp_transport_put(transport);
/* Delete the T3_rtx timer if it's active. *Thereisnopointinnotdoingthisnowandletting *structurehangaroundinmemorysinceweknow *thetransportisgoingaway.
*/ if (timer_delete(&transport->T3_rtx_timer))
sctp_transport_put(transport);
if (timer_delete(&transport->reconf_timer))
sctp_transport_put(transport);
if (timer_delete(&transport->probe_timer))
sctp_transport_put(transport);
/* Delete the ICMP proto unreachable timer if it's active. */ if (timer_delete(&transport->proto_unreach_timer))
sctp_transport_put(transport);
/* Destroy the transport data structure. *Assumestherearenomoreusersofthisstructure.
*/ staticvoid sctp_transport_destroy(struct sctp_transport *transport)
{ if (unlikely(refcount_read(&transport->refcnt))) {
WARN(1, "Attempt to destroy undead transport %p!\n", transport); return;
}
sctp_packet_free(&transport->packet);
if (transport->asoc)
sctp_association_put(transport->asoc);
/* When a data chunk is sent, reset the heartbeat interval. */
expires = jiffies + sctp_transport_timeout(transport); if (!mod_timer(&transport->hb_timer,
expires + get_random_u32_below(transport->rto)))
sctp_transport_hold(transport);
}
void sctp_transport_reset_reconf_timer(struct sctp_transport *transport)
{ if (!timer_pending(&transport->reconf_timer)) if (!mod_timer(&transport->reconf_timer,
jiffies + transport->rto))
sctp_transport_hold(transport);
}
/* This transport has been assigned to an association. *Initializefieldsfromtheassociationorfromthesockitself. *Registerthereferencecountintheassociation.
*/ void sctp_transport_set_owner(struct sctp_transport *transport, struct sctp_association *asoc)
{
transport->asoc = asoc;
sctp_association_hold(asoc);
}
/* Initialize the pmtu of a transport. */ void sctp_transport_pmtu(struct sctp_transport *transport, struct sock *sk)
{ /* If we don't have a fresh route, look one up */ if (!transport->dst || READ_ONCE(transport->dst->obsolete)) {
sctp_transport_dst_release(transport);
transport->af_specific->get_dst(transport, &transport->saddr,
&transport->fl, sk);
}
if (transport->param_flags & SPP_PMTUD_DISABLE) { struct sctp_association *asoc = transport->asoc;
if (!transport->pathmtu && asoc && asoc->pathmtu)
transport->pathmtu = asoc->pathmtu; if (transport->pathmtu) return;
}
if (transport->dst)
transport->pathmtu = sctp_dst_mtu(transport->dst); else
transport->pathmtu = SCTP_DEFAULT_MAXSEGMENT;
if (saddr)
memcpy(&transport->saddr, saddr, sizeof(union sctp_addr)); else
af->get_saddr(opt, transport, &transport->fl);
sctp_transport_pmtu(transport, sctp_opt2sk(opt));
/* Initialize sk->sk_rcv_saddr, if the transport is the *association'sactivepathforgetsockname().
*/ if (transport->dst && asoc &&
(!asoc->peer.primary_path || transport == asoc->peer.active_path))
opt->pf->to_sk_saddr(&transport->saddr, asoc->base.sk);
}
/* Hold a reference to a transport. */ int sctp_transport_hold(struct sctp_transport *transport)
{ return refcount_inc_not_zero(&transport->refcnt);
}
/* Release a reference to a transport and clean up *iftherearenomorereferences.
*/ void sctp_transport_put(struct sctp_transport *transport)
{ if (refcount_dec_and_test(&transport->refcnt))
sctp_transport_destroy(transport);
}
/* Update transport's RTO based on the newly calculated RTT. */ void sctp_transport_update_rto(struct sctp_transport *tp, __u32 rtt)
{ if (unlikely(!tp->rto_pending)) /* We should not be doing any RTO updates unless rto_pending is set. */
pr_debug("%s: rto_pending not set on transport %p!\n", __func__, tp);
if (tp->rttvar || tp->srtt) { struct net *net = tp->asoc->base.net; unsignedint rto_beta, rto_alpha; /* 6.3.1 C3) When a new RTT measurement R' is made, set *RTTVAR<-(1-RTO.Beta)*RTTVAR+RTO.Beta*|SRTT-R'| *SRTT<-(1-RTO.Alpha)*SRTT+RTO.Alpha*R'
*/
/* Note: The above algorithm has been rewritten to *expressrto_betaandrto_alphaasinversepowers *oftwo. *Forexample,assumingthedefaultvalueofRTO.Alphaof *1/8,rto_alphawouldbeexpressedas3.
*/
rto_beta = READ_ONCE(net->sctp.rto_beta); if (rto_beta < 32)
tp->rttvar = tp->rttvar - (tp->rttvar >> rto_beta)
+ (((__u32)abs((__s64)tp->srtt - (__s64)rtt)) >> rto_beta);
rto_alpha = READ_ONCE(net->sctp.rto_alpha); if (rto_alpha < 32)
tp->srtt = tp->srtt - (tp->srtt >> rto_alpha)
+ (rtt >> rto_alpha);
} else { /* 6.3.1 C2) When the first RTT measurement R is made, set *SRTT<-R,RTTVAR<-R/2.
*/
tp->srtt = rtt;
tp->rttvar = rtt >> 1;
}
/* 6.3.1 G1) Whenever RTTVAR is computed, if RTTVAR = 0, then *adjustRTTVAR<-G,whereGistheCLOCKGRANULARITY.
*/ if (tp->rttvar == 0)
tp->rttvar = SCTP_CLOCK_GRANULARITY;
/* 6.3.1 C6) Whenever RTO is computed, if it is less than RTO.Min *secondsthenitisroundeduptoRTO.Minseconds.
*/ if (tp->rto < tp->asoc->rto_min)
tp->rto = tp->asoc->rto_min;
/* 6.3.1 C7) A maximum value may be placed on RTO provided it is *atleastRTO.maxseconds.
*/ if (tp->rto > tp->asoc->rto_max)
tp->rto = tp->asoc->rto_max;
sctp_max_rto(tp->asoc, tp);
tp->rtt = rtt;
/* Reset rto_pending so that a new RTT measurement is started when a *newdatachunkissent.
*/
tp->rto_pending = 0;
/* The appropriate cwnd increase algorithm is performed *if,andonlyifthecongestionwindowisbeingfully *utilized.NotethatRFC4960Errata3.22removedthe *otherconditiononctsnmoving.
*/ if (flight_size < cwnd) return;
/* This routine is used to lower the transport's cwnd when congestion is *detected.
*/ void sctp_transport_lower_cwnd(struct sctp_transport *transport, enum sctp_lower_cwnd reason)
{ struct sctp_association *asoc = transport->asoc;
/* T3-rtx also clears fast recovery */
asoc->fast_recovery = 0; break;
case SCTP_LOWER_CWND_FAST_RTX: /* RFC 2960 7.2.4 Adjust the ssthresh and cwnd of the *destinationaddress(es)towhichthemissingDATAchunks *werelastsent,accordingtotheformuladescribedin *Section7.2.3. * *RFC29607.2.3,sctpimpguideUpondetectionofpacket *lossesfromSACK(seeSection7.2.4),Anendpoint *shoulddothefollowing: *ssthresh=max(cwnd/2,4*MTU) *cwnd=ssthresh *partial_bytes_acked=0
*/ if (asoc->fast_recovery) return;
/* Mark Fast recovery */
asoc->fast_recovery = 1;
asoc->fast_recovery_exit = asoc->next_tsn - 1;
/* Restore the old cwnd congestion window, after the burst had it's *desiredeffect.
*/ void sctp_transport_burst_reset(struct sctp_transport *t)
{ if (t->burst_limited) {
t->cwnd = t->burst_limited;
t->burst_limited = 0;
}
}
/* What is the next timeout value for this transport? */ unsignedlong sctp_transport_timeout(struct sctp_transport *trans)
{ /* RTO + timer slack +/- 50% of RTO */ unsignedlong timeout = trans->rto >> 1;
/* Reset these additional variables so that we have a clean slate. */
t->partial_bytes_acked = 0;
t->flight_size = 0;
t->error_count = 0;
t->rto_pending = 0;
t->hb_sent = 0;
/* Initialize the state information for SFR-CACC */
t->cacc.changeover_active = 0;
t->cacc.cycling_changeover = 0;
t->cacc.next_tsn_at_change = 0;
t->cacc.cacc_saw_newack = 0;
}
/* Schedule retransmission on the given transport */ void sctp_transport_immediate_rtx(struct sctp_transport *t)
{ /* Stop pending T3_rtx_timer */ if (timer_delete(&t->T3_rtx_timer))
sctp_transport_put(t);
sctp_retransmit(&t->asoc->outqueue, t, SCTP_RTXR_T3_RTX); if (!timer_pending(&t->T3_rtx_timer)) { if (!mod_timer(&t->T3_rtx_timer, jiffies + t->rto))
sctp_transport_hold(t);
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.