⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 outqueue.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
						      &transport_list);				}				packet = &transport->packet;				sctp_packet_config(packet, vtag,						   asoc->peer.ecn_capable);			}			SCTP_DEBUG_PRINTK("sctp_outq_flush(%p, %p[%s]), ",					  q, chunk,					  chunk && chunk->chunk_hdr ?					  sctp_cname(SCTP_ST_CHUNK(						  chunk->chunk_hdr->type))					  : "Illegal Chunk");			SCTP_DEBUG_PRINTK("TX TSN 0x%x skb->head "					"%p skb->users %d.\n",					ntohl(chunk->subh.data_hdr->tsn),					chunk->skb ?chunk->skb->head : NULL,					chunk->skb ?					atomic_read(&chunk->skb->users) : -1);			/* Add the chunk to the packet.  */			status = sctp_packet_transmit_chunk(packet, chunk);			switch (status) {			case SCTP_XMIT_PMTU_FULL:			case SCTP_XMIT_RWND_FULL:			case SCTP_XMIT_NAGLE_DELAY:				/* We could not append this chunk, so put				 * the chunk back on the output queue.				 */				SCTP_DEBUG_PRINTK("sctp_outq_flush: could "					"not transmit TSN: 0x%x, status: %d\n",					ntohl(chunk->subh.data_hdr->tsn),					status);				sctp_outq_head_data(q, chunk);				goto sctp_flush_out;				break;			case SCTP_XMIT_OK:				break;			default:				BUG();			}			/* BUG: We assume that the sctp_packet_transmit()			 * call below will succeed all the time and add the			 * chunk to the transmitted list and restart the			 * timers.			 * It is possible that the call can fail under OOM			 * conditions.			 *			 * Is this really a problem?  Won't this behave			 * like a lost TSN?			 */			list_add_tail(&chunk->transmitted_list,				      &transport->transmitted);			sctp_transport_reset_timers(transport);			q->empty = 0;			/* Only let one DATA chunk get bundled with a			 * COOKIE-ECHO chunk.			 */			if (packet->has_cookie_echo)				goto sctp_flush_out;		}		break;	default:		/* Do nothing.  */		break;	}sctp_flush_out:	/* Before returning, examine all the transports touched in	 * this call.  Right now, we bluntly force clear all the	 * transports.  Things might change after we implement Nagle.	 * But such an examination is still required.	 *	 * --xguo	 */	while ((ltransport = sctp_list_dequeue(&transport_list)) != NULL ) {		struct sctp_transport *t = list_entry(ltransport,						      struct sctp_transport,						      send_ready);		packet = &t->packet;		if (!sctp_packet_empty(packet))			error = sctp_packet_transmit(packet);	}	return error;}/* Update unack_data based on the incoming SACK chunk */static void sctp_sack_update_unack_data(struct sctp_association *assoc,					struct sctp_sackhdr *sack){	sctp_sack_variable_t *frags;	__u16 unack_data;	int i;	unack_data = assoc->next_tsn - assoc->ctsn_ack_point - 1;	frags = sack->variable;	for (i = 0; i < ntohs(sack->num_gap_ack_blocks); i++) {		unack_data -= ((ntohs(frags[i].gab.end) -				ntohs(frags[i].gab.start) + 1));	}	assoc->unack_data = unack_data;}/* Return the highest new tsn that is acknowledged by the given SACK chunk. */static __u32 sctp_highest_new_tsn(struct sctp_sackhdr *sack,				  struct sctp_association *asoc){	struct list_head *ltransport, *lchunk;	struct sctp_transport *transport;	struct sctp_chunk *chunk;	__u32 highest_new_tsn, tsn;	struct list_head *transport_list = &asoc->peer.transport_addr_list;	highest_new_tsn = ntohl(sack->cum_tsn_ack);	list_for_each(ltransport, transport_list) {		transport = list_entry(ltransport, struct sctp_transport,				       transports);		list_for_each(lchunk, &transport->transmitted) {			chunk = list_entry(lchunk, struct sctp_chunk,					   transmitted_list);			tsn = ntohl(chunk->subh.data_hdr->tsn);			if (!chunk->tsn_gap_acked &&			    TSN_lt(highest_new_tsn, tsn) &&			    sctp_acked(sack, tsn))				highest_new_tsn = tsn;		}	}	return highest_new_tsn;}/* This is where we REALLY process a SACK. * * Process the SACK against the outqueue.  Mostly, this just frees * things off the transmitted queue. */int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack){	struct sctp_association *asoc = q->asoc;	struct sctp_transport *transport;	struct sctp_chunk *tchunk = NULL;	struct list_head *lchunk, *transport_list, *pos, *temp;	sctp_sack_variable_t *frags = sack->variable;	__u32 sack_ctsn, ctsn, tsn;	__u32 highest_tsn, highest_new_tsn;	__u32 sack_a_rwnd;	unsigned outstanding;	struct sctp_transport *primary = asoc->peer.primary_path;	int count_of_newacks = 0;	/* Grab the association's destination address list. */	transport_list = &asoc->peer.transport_addr_list;	sack_ctsn = ntohl(sack->cum_tsn_ack);	/*	 * SFR-CACC algorithm:	 * On receipt of a SACK the sender SHOULD execute the	 * following statements.	 *	 * 1) If the cumulative ack in the SACK passes next tsn_at_change	 * on the current primary, the CHANGEOVER_ACTIVE flag SHOULD be	 * cleared. The CYCLING_CHANGEOVER flag SHOULD also be cleared for	 * all destinations.	 */	if (TSN_lte(primary->cacc.next_tsn_at_change, sack_ctsn)) {		primary->cacc.changeover_active = 0;		list_for_each(pos, transport_list) {			transport = list_entry(pos, struct sctp_transport,					transports);			transport->cacc.cycling_changeover = 0;		}	}	/*	 * SFR-CACC algorithm:	 * 2) If the SACK contains gap acks and the flag CHANGEOVER_ACTIVE	 * is set the receiver of the SACK MUST take the following actions:	 *	 * A) Initialize the cacc_saw_newack to 0 for all destination	 * addresses.	 */	if (sack->num_gap_ack_blocks &&	    primary->cacc.changeover_active) {		list_for_each(pos, transport_list) {			transport = list_entry(pos, struct sctp_transport,					transports);			transport->cacc.cacc_saw_newack = 0;		}	}	/* Get the highest TSN in the sack. */	highest_tsn = sack_ctsn;	if (sack->num_gap_ack_blocks)		highest_tsn +=		    ntohs(frags[ntohs(sack->num_gap_ack_blocks) - 1].gab.end);	if (TSN_lt(asoc->highest_sacked, highest_tsn)) {		highest_new_tsn = highest_tsn;		asoc->highest_sacked = highest_tsn;	} else {		highest_new_tsn = sctp_highest_new_tsn(sack, asoc);	}	/* Run through the retransmit queue.  Credit bytes received	 * and free those chunks that we can.	 */	sctp_check_transmitted(q, &q->retransmit, NULL, sack, highest_new_tsn);	sctp_mark_missing(q, &q->retransmit, NULL, highest_new_tsn, 0);	/* Run through the transmitted queue.	 * Credit bytes received and free those chunks which we can.	 *	 * This is a MASSIVE candidate for optimization.	 */	list_for_each(pos, transport_list) {		transport  = list_entry(pos, struct sctp_transport,					transports);		sctp_check_transmitted(q, &transport->transmitted,				       transport, sack, highest_new_tsn);		/*		 * SFR-CACC algorithm:		 * C) Let count_of_newacks be the number of		 * destinations for which cacc_saw_newack is set.		 */		if (transport->cacc.cacc_saw_newack)			count_of_newacks ++;	}	list_for_each(pos, transport_list) {		transport  = list_entry(pos, struct sctp_transport,					transports);		sctp_mark_missing(q, &transport->transmitted, transport,				  highest_new_tsn, count_of_newacks);	}	/* Move the Cumulative TSN Ack Point if appropriate.  */	if (TSN_lt(asoc->ctsn_ack_point, sack_ctsn))		asoc->ctsn_ack_point = sack_ctsn;	/* Update unack_data field in the assoc. */	sctp_sack_update_unack_data(asoc, sack);	ctsn = asoc->ctsn_ack_point;	/* Throw away stuff rotting on the sack queue.  */	list_for_each_safe(lchunk, temp, &q->sacked) {		tchunk = list_entry(lchunk, struct sctp_chunk,				    transmitted_list);		tsn = ntohl(tchunk->subh.data_hdr->tsn);		if (TSN_lte(tsn, ctsn))			sctp_chunk_free(tchunk);	}	/* ii) Set rwnd equal to the newly received a_rwnd minus the	 *     number of bytes still outstanding after processing the	 *     Cumulative TSN Ack and the Gap Ack Blocks.	 */	sack_a_rwnd = ntohl(sack->a_rwnd);	outstanding = q->outstanding_bytes;	if (outstanding < sack_a_rwnd)		sack_a_rwnd -= outstanding;	else		sack_a_rwnd = 0;	asoc->peer.rwnd = sack_a_rwnd;	sctp_generate_fwdtsn(q, sack_ctsn);	SCTP_DEBUG_PRINTK("%s: sack Cumulative TSN Ack is 0x%x.\n",			  __FUNCTION__, sack_ctsn);	SCTP_DEBUG_PRINTK("%s: Cumulative TSN Ack of association, "			  "%p is 0x%x. Adv peer ack point: 0x%x\n",			  __FUNCTION__, asoc, ctsn, asoc->adv_peer_ack_point);	/* See if all chunks are acked.	 * Make sure the empty queue handler will get run later.	 */	q->empty = (list_empty(&q->out_chunk_list) &&		    list_empty(&q->control_chunk_list) &&		    list_empty(&q->retransmit));	if (!q->empty)		goto finish;	list_for_each(pos, transport_list) {		transport  = list_entry(pos, struct sctp_transport,					transports);		q->empty = q->empty && list_empty(&transport->transmitted);		if (!q->empty)			goto finish;	}	SCTP_DEBUG_PRINTK("sack queue is empty.\n");finish:	return q->empty;}/* Is the outqueue empty?  */int sctp_outq_is_empty(const struct sctp_outq *q){	return q->empty;}/******************************************************************** * 2nd Level Abstractions ********************************************************************//* Go through a transport's transmitted list or the association's retransmit * list and move chunks that are acked by the Cumulative TSN Ack to q->sacked. * The retransmit list will not have an associated transport. * * I added coherent debug information output.	--xguo * * Instead of printing 'sacked' or 'kept' for each TSN on the * transmitted_queue, we print a range: SACKED: TSN1-TSN2, TSN3, TSN4-TSN5. * KEPT TSN6-TSN7, etc. */static void sctp_check_transmitted(struct sctp_outq *q,				   struct list_head *transmitted_queue,				   struct sctp_transport *transport,				   struct sctp_sackhdr *sack,				   __u32 highest_new_tsn_in_sack){	struct list_head *lchunk;	struct sctp_chunk *tchunk;	struct list_head tlist;	__u32 tsn;	__u32 sack_ctsn;	__u32 rtt;	__u8 restart_timer = 0;	int bytes_acked = 0;	/* These state variables are for coherent debug output. --xguo */#if SCTP_DEBUG	__u32 dbg_ack_tsn = 0;	/* An ACKed TSN range starts here... */	__u32 dbg_last_ack_tsn = 0;  /* ...and finishes here.	     */	__u32 dbg_kept_tsn = 0;	/* An un-ACKed range starts here...  */	__u32 dbg_last_kept_tsn = 0; /* ...and finishes here.	     */	/* 0 : The last TSN was ACKed.	 * 1 : The last TSN was NOT ACKed (i.e. KEPT).	 * -1: We need to initialize.	 */	int dbg_prt_state = -1;#endif /* SCTP_DEBUG */	sack_ctsn = ntohl(sack->cum_tsn_ack);	INIT_LIST_HEAD(&tlist);	/* The while loop will skip empty transmitted queues. */	while (NULL != (lchunk = sctp_list_dequeue(transmitted_queue))) {		tchunk = list_entry(lchunk, struct sctp_chunk,				    transmitted_list);		if (sctp_chunk_abandoned(tchunk)) {			/* Move the chunk to abandoned list. */			sctp_insert_list(&q->abandoned, lchunk);			/* If this chunk has not been acked, stop			 * considering it as 'outstanding'.			 */			if (!tchunk->tsn_gap_acked) {				tchunk->transport->flight_size -=						sctp_data_size(tchunk);				q->outstanding_bytes -= sctp_data_size(tchunk);			}			continue;		}		tsn = ntohl(tchunk->subh.data_hdr->tsn);		if (sctp_acked(sack, tsn)) {			/* If this queue is the retransmit queue, the			 * retransmit timer has already reclaimed			 * the outstanding bytes for this chunk, so only			 * count bytes associated with a transport.			 */			if (transport) {				/* If this chunk is being used for RTT				 * measurement, calculate the RTT and update				 * the RTO using this value.				 *				 * 6.3.1 C5) Karn's algorithm: RTT measurements				 * MUST NOT be made using packets that were				 * retransmitted (and thus for which it is				 * ambiguous whether the reply was for the				 * first instance of the packet or a later				 * instance).				 */				if (!tchunk->tsn_gap_acked &&				    !tchunk->resent &&				    tchunk->rtt_in_progress) {					tchunk->rtt_in_progress = 0;					rtt = jiffies - tchunk->sent_at;					sctp_transport_update_rto(transport,								  rtt);				}			}			if (TSN_lte(tsn, sack_ctsn)) {				/* RFC 2960  6.3.2 Retransmission Timer Rules				 *				 * R3) Whenever a SACK is received				 * that acknowledges the DATA chunk				 * with the earliest outstanding TSN				 * for that address, restart T3-rtx				 * timer for that address with its				 * current RTO.				 */				restart_timer = 1;				if (!tchunk->tsn_gap_acked) {					tchunk->tsn_gap_acked = 1;					bytes_acked += sctp_data_size(tchunk);					/*					 * SFR-CACC algorithm:					 * 2) If the SACK contains gap acks					 * and the flag CHANGEOVER_ACTIVE is					 * set the receiver of the SACK MUST					 * take the following action:					 *					 * B) For each TSN t being acked that					 * has not been acked in any SACK so					 * far, set cacc_saw_newack to 1 for					 * the destination that the TSN was					 * sent to.					 */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -