From patchwork Fri May 11 23:28:37 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marcelo Ricardo Leitner X-Patchwork-Id: 912259 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="qip5B3La"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 40jR9y4r19z9s1b for ; Sat, 12 May 2018 09:28:54 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751596AbeEKX2s (ORCPT ); Fri, 11 May 2018 19:28:48 -0400 Received: from mail-qt0-f194.google.com ([209.85.216.194]:40359 "EHLO mail-qt0-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751345AbeEKX2q (ORCPT ); Fri, 11 May 2018 19:28:46 -0400 Received: by mail-qt0-f194.google.com with SMTP id h2-v6so9229864qtp.7; Fri, 11 May 2018 16:28:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=sFOD0cQFU2cnz5cZR1JwX9xAY4oRei+bCn2rR2n1I7U=; b=qip5B3La92U2jZcH+i4lp4t/JnElZmAI51Xgzbl6thmgINNXh+lqvbb+l9fXPv/o1l +uF8H1HR1ukEvXv7ctEXv50DrsUavln0xWjzMxeM5DMhjbGcCGzAHY00VnNDtJNhiI0V YfKcjMrYHvSoaCyc1KvERL1KO6zD5Joc1pm0XItaOclb4f0P7vIm+GrqjeSStt+XgAXP VnGLtfmc0yERh1ve7Re2S/PbLmt7O2ADdsm3+oa8cxDAO0CtlIPlBeRVmHiw4g2lXSX+ kBIskVE/gACXRzKQvQ9Q8YfuZ+dBMJNfPxswlAs815D2Ac2wCjWhZfhrZaVU0koh8aQ6 W8GQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=sFOD0cQFU2cnz5cZR1JwX9xAY4oRei+bCn2rR2n1I7U=; b=k4l8lOVOya0wHf7pP5GBtc1wFpcLGzqLL0E3dNCmlfmyxlxZYXNUmT1NVLN50czZvv /SIqsuMQLzgRk7pjj6OcdPHOk77b2dO00vYI9arC3iApu69KpZXhJyMu7CQEpnmw0RZW 3Glbueg7G2FgGygPZgoY+vYEfPzAGHvo649ctn/V60cDdYAv5bKBl49amb3bEz1byON2 WtLLLJLzsHJov7vuSuY41fw6/dAGna0bkSGlaP+I2CnSVnhbLtHe1+s4LJLMaHxWQLpr up8LxKvsgZqi/rvwbxf39sr7cMV/FcRTopmfLZo4WR+O1ExvrS015osKu8YnFEHlXRzz ASvw== X-Gm-Message-State: ALKqPweLP8vvjHENzFJDLiJqQUOWkxl21iXyjDTUdtUWJnURSQ2/woBz ilcYq8FPJ4ora24foMKIduo= X-Google-Smtp-Source: AB8JxZquHWQWDhA+wd4gvjH2a6KrgAcK4OvXIgktcVp+ZNft1S185RsACZPEfKNGonww5l7VvumNug== X-Received: by 2002:aed:21c5:: with SMTP id m5-v6mr51795qtc.211.1526081325633; Fri, 11 May 2018 16:28:45 -0700 (PDT) Received: from localhost.localdomain ([45.4.239.227]) by smtp.gmail.com with ESMTPSA id m8-v6sm2980998qth.24.2018.05.11.16.28.44 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Fri, 11 May 2018 16:28:45 -0700 (PDT) Received: by localhost.localdomain (Postfix, from userid 1000) id 2A129180C3B; Fri, 11 May 2018 20:28:43 -0300 (-03) From: Marcelo Ricardo Leitner To: netdev@vger.kernel.org Cc: linux-sctp@vger.kernel.org, Neil Horman , Vlad Yasevich , Xin Long Subject: [PATCH net-next 2/8] sctp: factor out sctp_outq_select_transport Date: Fri, 11 May 2018 20:28:37 -0300 Message-Id: <4b7935c08dea4610292965ad1c002843c9f98831.1526077476.git.marcelo.leitner@gmail.com> X-Mailer: git-send-email 2.14.3 In-Reply-To: References: Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org We had two spots doing such complex operation and they were very close to each other, a bit more tailored to here or there. This patch unifies these under the same function, sctp_outq_select_transport, which knows how to handle control chunks and original transmissions (but not retransmissions). Signed-off-by: Marcelo Ricardo Leitner --- net/sctp/outqueue.c | 187 +++++++++++++++++++++++++--------------------------- 1 file changed, 90 insertions(+), 97 deletions(-) diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index 300bd0dfc7c14c9df579dbe2f9e78dd8356ae1a3..bda50596d4bfebeac03966c5a161473df1c1986a 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c @@ -791,6 +791,90 @@ static int sctp_packet_singleton(struct sctp_transport *transport, return sctp_packet_transmit(&singleton, gfp); } +static bool sctp_outq_select_transport(struct sctp_chunk *chunk, + struct sctp_association *asoc, + struct sctp_transport **transport, + struct list_head *transport_list) +{ + struct sctp_transport *new_transport = chunk->transport; + struct sctp_transport *curr = *transport; + bool changed = false; + + if (!new_transport) { + if (!sctp_chunk_is_data(chunk)) { + /* + * If we have a prior transport pointer, see if + * the destination address of the chunk + * matches the destination address of the + * current transport. If not a match, then + * try to look up the transport with a given + * destination address. We do this because + * after processing ASCONFs, we may have new + * transports created. + */ + if (curr && sctp_cmp_addr_exact(&chunk->dest, + &curr->ipaddr)) + new_transport = curr; + else + new_transport = sctp_assoc_lookup_paddr(asoc, + &chunk->dest); + } + + /* if we still don't have a new transport, then + * use the current active path. + */ + if (!new_transport) + new_transport = asoc->peer.active_path; + } else { + __u8 type; + + switch (new_transport->state) { + case SCTP_INACTIVE: + case SCTP_UNCONFIRMED: + case SCTP_PF: + /* If the chunk is Heartbeat or Heartbeat Ack, + * send it to chunk->transport, even if it's + * inactive. + * + * 3.3.6 Heartbeat Acknowledgement: + * ... + * A HEARTBEAT ACK is always sent to the source IP + * address of the IP datagram containing the + * HEARTBEAT chunk to which this ack is responding. + * ... + * + * ASCONF_ACKs also must be sent to the source. + */ + type = chunk->chunk_hdr->type; + if (type != SCTP_CID_HEARTBEAT && + type != SCTP_CID_HEARTBEAT_ACK && + type != SCTP_CID_ASCONF_ACK) + new_transport = asoc->peer.active_path; + break; + default: + break; + } + } + + /* Are we switching transports? Take care of transport locks. */ + if (new_transport != curr) { + changed = true; + curr = new_transport; + *transport = curr; + if (list_empty(&curr->send_ready)) + list_add_tail(&curr->send_ready, transport_list); + + sctp_packet_config(&curr->packet, asoc->peer.i.init_tag, + asoc->peer.ecn_capable); + /* We've switched transports, so apply the + * Burst limit to the new transport. + */ + sctp_transport_burst_limited(curr); + } + + return changed; +} + /* * Try to flush an outqueue. * @@ -806,7 +890,6 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp) struct sctp_association *asoc = q->asoc; __u32 vtag = asoc->peer.i.init_tag; struct sctp_transport *transport = NULL; - struct sctp_transport *new_transport; struct sctp_chunk *chunk, *tmp; enum sctp_xmit status; int error = 0; @@ -843,68 +926,12 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp) list_del_init(&chunk->list); - /* Pick the right transport to use. */ - new_transport = chunk->transport; - - if (!new_transport) { - /* - * If we have a prior transport pointer, see if - * the destination address of the chunk - * matches the destination address of the - * current transport. If not a match, then - * try to look up the transport with a given - * destination address. We do this because - * after processing ASCONFs, we may have new - * transports created. - */ - if (transport && - sctp_cmp_addr_exact(&chunk->dest, - &transport->ipaddr)) - new_transport = transport; - else - new_transport = sctp_assoc_lookup_paddr(asoc, - &chunk->dest); - - /* if we still don't have a new transport, then - * use the current active path. - */ - if (!new_transport) - new_transport = asoc->peer.active_path; - } else if ((new_transport->state == SCTP_INACTIVE) || - (new_transport->state == SCTP_UNCONFIRMED) || - (new_transport->state == SCTP_PF)) { - /* If the chunk is Heartbeat or Heartbeat Ack, - * send it to chunk->transport, even if it's - * inactive. - * - * 3.3.6 Heartbeat Acknowledgement: - * ... - * A HEARTBEAT ACK is always sent to the source IP - * address of the IP datagram containing the - * HEARTBEAT chunk to which this ack is responding. - * ... - * - * ASCONF_ACKs also must be sent to the source. - */ - if (chunk->chunk_hdr->type != SCTP_CID_HEARTBEAT && - chunk->chunk_hdr->type != SCTP_CID_HEARTBEAT_ACK && - chunk->chunk_hdr->type != SCTP_CID_ASCONF_ACK) - new_transport = asoc->peer.active_path; - } - - /* Are we switching transports? - * Take care of transport locks. + /* Pick the right transport to use. Should always be true for + * the first chunk as we don't have a transport by then. */ - if (new_transport != transport) { - transport = new_transport; - if (list_empty(&transport->send_ready)) { - list_add_tail(&transport->send_ready, - &transport_list); - } + if (sctp_outq_select_transport(chunk, asoc, &transport, + &transport_list)) packet = &transport->packet; - sctp_packet_config(packet, vtag, - asoc->peer.ecn_capable); - } switch (chunk->chunk_hdr->type) { /* @@ -1072,43 +1099,9 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp) goto sctp_flush_out; } - /* If there is a specified transport, use it. - * Otherwise, we want to use the active path. - */ - new_transport = chunk->transport; - if (!new_transport || - ((new_transport->state == SCTP_INACTIVE) || - (new_transport->state == SCTP_UNCONFIRMED) || - (new_transport->state == SCTP_PF))) - new_transport = asoc->peer.active_path; - if (new_transport->state == SCTP_UNCONFIRMED) { - WARN_ONCE(1, "Attempt to send packet on unconfirmed path."); - sctp_sched_dequeue_done(q, chunk); - sctp_chunk_fail(chunk, 0); - sctp_chunk_free(chunk); - continue; - } - - /* Change packets if necessary. */ - if (new_transport != transport) { - transport = new_transport; - - /* Schedule to have this transport's - * packet flushed. - */ - if (list_empty(&transport->send_ready)) { - list_add_tail(&transport->send_ready, - &transport_list); - } - + if (sctp_outq_select_transport(chunk, asoc, &transport, + &transport_list)) packet = &transport->packet; - sctp_packet_config(packet, vtag, - asoc->peer.ecn_capable); - /* We've switched transports, so apply the - * Burst limit to the new transport. - */ - sctp_transport_burst_limited(transport); - } pr_debug("%s: outq:%p, chunk:%p[%s], tx-tsn:0x%x skb->head:%p " "skb->users:%d\n",