From patchwork Mon May 14 17:34: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: 913160 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="J7HHKPw0"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 40l7CL18kfz9s0W for ; Tue, 15 May 2018 03:35:58 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753330AbeENRfz (ORCPT ); Mon, 14 May 2018 13:35:55 -0400 Received: from mail-qt0-f194.google.com ([209.85.216.194]:44071 "EHLO mail-qt0-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752347AbeENRfB (ORCPT ); Mon, 14 May 2018 13:35:01 -0400 Received: by mail-qt0-f194.google.com with SMTP id d3-v6so17174886qtp.11; Mon, 14 May 2018 10:35:00 -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=J7HHKPw0fdmNDNW9sB5sBqJ9pP29yAgZwyhcIOGdYZDqptTEMomsJLX2A0hqGr4kSY tV+z2M//1+blbZZKS35sgLDdIPUnFNstTeMuA+P0q6XsOyiKAiLdSwQ0wiet//bP0Sj2 pbLb8yze8weu89sL38vubRrjiYAVDT+zd6E9BXcMrFCGBT/WlRP6e45FVye/jXGuujrA axFjyqRX3hxcEpc8GFtzkEql41PoLeCCS6CsX9Vv2DvVf5GET+M7MFqYMdeRS5u/Y8GM t1+4Eqg2n2MIi1xoy/4lvXXbOfEa8GQqQ9GAUKaCEO8Aj2XPxXraZKTYpRL4Yu9CRqHQ PWBw== 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=fsaSUZfV4JItnaoH1sslcxNn5jtAcTKmbvbPuFSFjtL4fx9f4iAsgrUVmsYRUMku/e +OwST6jhPn3NoNivL6SeHaimwtd5ghwPY7tvO/4e/3TsORToV82MZtMII9dtKm28A43S sSfPYagyX+CVVxqLxZlyzH1T/FLuqmPGxEBQ/oPNPYaDIP+lBeeBCyPBCe9jYaz1x/TZ QMhvEv5EC78Cr+dGtogbJIzzWhPjsJg6qKoMEt7ARCYBt/oZPQHGJhN3N8O9RTLyYsMd 94YrqHEZTkVrES946M+KFu6OclXNuOv3khptg5ctUbgqK+ztMJ79DbMn4k43GqgUiI4Q aVRw== X-Gm-Message-State: ALKqPwe0bt6FOAzhMPNdMLmh5JRuUGo4g7d0+UeBRDdDBeopVtKvBb7d kPOd904IeBnfoEkQmiKFiSc= X-Google-Smtp-Source: AB8JxZpGLkzBY0a/IQoVO8owAeFRwpQnl5rVCI6OQ278FatnL0lf7k4iinuVnoWs6sAjm31N+FnmlA== X-Received: by 2002:a0c:f88e:: with SMTP id u14-v6mr9815418qvn.61.1526319300282; Mon, 14 May 2018 10:35:00 -0700 (PDT) Received: from localhost.localdomain ([45.4.239.227]) by smtp.gmail.com with ESMTPSA id t184-v6sm7493212qkc.6.2018.05.14.10.34.56 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Mon, 14 May 2018 10:34:57 -0700 (PDT) Received: by localhost.localdomain (Postfix, from userid 1000) id 892071812C5; Mon, 14 May 2018 14:34:53 -0300 (-03) From: Marcelo Ricardo Leitner To: netdev@vger.kernel.org Cc: linux-sctp@vger.kernel.org, Neil Horman , Xin Long , Vlad Yasevich Subject: [PATCH net-next v3 2/8] sctp: factor out sctp_outq_select_transport Date: Mon, 14 May 2018 14:34:37 -0300 Message-Id: <85c608b7d56ccd73e218268a499e636ca16dbd35.1526318522.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",