From patchwork Mon May 4 12:43:20 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1282587 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=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; 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.a=rsa-sha256 header.s=20161025 header.b=CaHyqs+2; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 49G2cZ6608z9sSd for ; Mon, 4 May 2020 22:44:46 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728885AbgEDMoV (ORCPT ); Mon, 4 May 2020 08:44:21 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35586 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1728869AbgEDMoT (ORCPT ); Mon, 4 May 2020 08:44:19 -0400 Received: from mail-wr1-x444.google.com (mail-wr1-x444.google.com [IPv6:2a00:1450:4864:20::444]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id ABF53C061A0E for ; Mon, 4 May 2020 05:44:17 -0700 (PDT) Received: by mail-wr1-x444.google.com with SMTP id e16so15631613wra.7 for ; Mon, 04 May 2020 05:44:17 -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=zgtWbKwoFPL+t361Q3v0HiQBH/Kcg/vdhd2CNMYKU30=; b=CaHyqs+27R6UXGBTwE5Gw22OESrv/Qc+J/WGXO/HycrIylHJfMOfKSL95tifC/rQ48 h0vPptbFORb5OcM+SErEKTc2+35X30m9ATw+GgSUL0Zisnwadp3jYXfoEmgwo7PB8NlU RqFoAGT9ELADV3M9LI6XczvFVlAPcmO/dGGgzYca0NaA/UGh+zp+WSouZjfigqyTxEaQ f5lNi//VGeDeX5qInRXrIbemq16iizUlEUAqB8g2+tE0tn2T9DWw2BW8K7AidlNFrfkf VO1L0do0AwMJ0Q27jd+e1CPsOUq7L32J6MaZcyNM9BtXD7GhYfgAxyAEnauJ7cetdJcs sekA== 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=zgtWbKwoFPL+t361Q3v0HiQBH/Kcg/vdhd2CNMYKU30=; b=PQ+ZYCwjDmY8/151nHnxndXysBtuOfeF1gkIXtw3vIDuKWfWxtL0SccX34HumscsUU BqRpxtytJbr5eNM9Ml2SYHs+wmpIZR5rH6tDHZG41iYwVQnyY0sLGDeL7bEzeoiuGY3k cfSKWGj309U4j6be7hCVAgRAasECB47Ar9WB7RP1PU6200R+Jcn2fo+xZ8p0B/A8GufO 8uTZwOB77uR1NpxkARU0hw0lMb6etOnufSBHX9BHa9SJdhLiflApE4FWfgZyYkuCUp+5 IHZsjxOaLbaTv/LO4pDXE7LBZL0vLMG6PuW5z6edObTZTqwm6hJ+6TaHcsuhRG5v0f/T f2TA== X-Gm-Message-State: AGi0PubNdycOV1FXMRjd84fbFPLf7W7BBJIZLNCgrxrKOLmVFGYbAbn2 xyopF1L46JK1FGGquDt0BuNCXqwiR/k= X-Google-Smtp-Source: APiQypLbqyg5VxT2ZHm9axNVEzwOl7DHOBcZl9ZgqjQgTZ1eYFc7nyLxRZJL0Gg7+/2SaxaLQKBxnQ== X-Received: by 2002:adf:e751:: with SMTP id c17mr1942991wrn.351.1588596256377; Mon, 04 May 2020 05:44:16 -0700 (PDT) Received: from localhost.localdomain ([86.121.118.29]) by smtp.gmail.com with ESMTPSA id 32sm17343670wrg.19.2020.05.04.05.44.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 04 May 2020 05:44:15 -0700 (PDT) From: Vladimir Oltean To: andrew@lunn.ch, f.fainelli@gmail.com, vivien.didelot@gmail.com Cc: davem@davemloft.net, jiri@resnulli.us, idosch@idosch.org, kuba@kernel.org, netdev@vger.kernel.org, nikolay@cumulusnetworks.com, roopa@cumulusnetworks.com, georg.waibel@sensor-technik.de, o.rempel@pengutronix.de, christian.herber@nxp.com Subject: [RFC 1/6] net: dsa: sja1105: add packing ops for the Retagging Table Date: Mon, 4 May 2020 15:43:20 +0300 Message-Id: <20200504124325.26758-2-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200504124325.26758-1-olteanv@gmail.com> References: <20200504124325.26758-1-olteanv@gmail.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Vladimir Oltean The Retagging Table is an optional feature that allows the switch to match frames against a {ingress port, egress port, vid} rule and change their VLAN ID. The retagged frames are by default clones of the original ones (since the hardware-foreseen use case was to mirror traffic for debugging purposes and to tag it with a special VLAN for this purpose), but we can force the original frames to be dropped by removing the pre-retagging VLAN from the port membership list of the egress port. Signed-off-by: Vladimir Oltean --- drivers/net/dsa/sja1105/sja1105.h | 2 + .../net/dsa/sja1105/sja1105_dynamic_config.c | 33 ++++++++++ .../net/dsa/sja1105/sja1105_static_config.c | 62 ++++++++++++++++++- .../net/dsa/sja1105/sja1105_static_config.h | 15 +++++ 4 files changed, 110 insertions(+), 2 deletions(-) diff --git a/drivers/net/dsa/sja1105/sja1105.h b/drivers/net/dsa/sja1105/sja1105.h index a12779c9fa19..f925f6a231e2 100644 --- a/drivers/net/dsa/sja1105/sja1105.h +++ b/drivers/net/dsa/sja1105/sja1105.h @@ -252,6 +252,8 @@ size_t sja1105et_l2_lookup_entry_packing(void *buf, void *entry_ptr, enum packing_op op); size_t sja1105_vlan_lookup_entry_packing(void *buf, void *entry_ptr, enum packing_op op); +size_t sja1105_retagging_entry_packing(void *buf, void *entry_ptr, + enum packing_op op); size_t sja1105pqrs_mac_config_entry_packing(void *buf, void *entry_ptr, enum packing_op op); size_t sja1105pqrs_avb_params_entry_packing(void *buf, void *entry_ptr, diff --git a/drivers/net/dsa/sja1105/sja1105_dynamic_config.c b/drivers/net/dsa/sja1105/sja1105_dynamic_config.c index bf9b36ff35bf..a1ade782beb1 100644 --- a/drivers/net/dsa/sja1105/sja1105_dynamic_config.c +++ b/drivers/net/dsa/sja1105/sja1105_dynamic_config.c @@ -127,6 +127,9 @@ #define SJA1105PQRS_SIZE_AVB_PARAMS_DYN_CMD \ (SJA1105_SIZE_DYN_CMD + SJA1105PQRS_SIZE_AVB_PARAMS_ENTRY) +#define SJA1105_SIZE_RETAGGING_DYN_CMD \ + (SJA1105_SIZE_DYN_CMD + SJA1105_SIZE_RETAGGING_ENTRY) + #define SJA1105_MAX_DYN_CMD_SIZE \ SJA1105PQRS_SIZE_MAC_CONFIG_DYN_CMD @@ -496,6 +499,20 @@ sja1105pqrs_avb_params_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd, sja1105_packing(p, &cmd->rdwrset, 29, 29, size, op); } +static void +sja1105_retagging_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd, + enum packing_op op) +{ + u8 *p = buf + SJA1105_SIZE_RETAGGING_ENTRY; + const int size = SJA1105_SIZE_DYN_CMD; + + sja1105_packing(p, &cmd->valid, 31, 31, size, op); + sja1105_packing(p, &cmd->errors, 30, 30, size, op); + sja1105_packing(p, &cmd->valident, 29, 29, size, op); + sja1105_packing(p, &cmd->rdwrset, 28, 28, size, op); + sja1105_packing(p, &cmd->index, 5, 0, size, op); +} + #define OP_READ BIT(0) #define OP_WRITE BIT(1) #define OP_DEL BIT(2) @@ -566,6 +583,14 @@ struct sja1105_dynamic_table_ops sja1105et_dyn_ops[BLK_IDX_MAX_DYN] = { .packed_size = SJA1105ET_SIZE_GENERAL_PARAMS_DYN_CMD, .addr = 0x34, }, + [BLK_IDX_RETAGGING] = { + .entry_packing = sja1105_retagging_entry_packing, + .cmd_packing = sja1105_retagging_cmd_packing, + .max_entry_count = SJA1105_MAX_RETAGGING_COUNT, + .access = (OP_WRITE | OP_DEL), + .packed_size = SJA1105_SIZE_RETAGGING_DYN_CMD, + .addr = 0x31, + }, [BLK_IDX_XMII_PARAMS] = {0}, }; @@ -641,6 +666,14 @@ struct sja1105_dynamic_table_ops sja1105pqrs_dyn_ops[BLK_IDX_MAX_DYN] = { .packed_size = SJA1105ET_SIZE_GENERAL_PARAMS_DYN_CMD, .addr = 0x34, }, + [BLK_IDX_RETAGGING] = { + .entry_packing = sja1105_retagging_entry_packing, + .cmd_packing = sja1105_retagging_cmd_packing, + .max_entry_count = SJA1105_MAX_RETAGGING_COUNT, + .access = (OP_READ | OP_WRITE | OP_DEL), + .packed_size = SJA1105_SIZE_RETAGGING_DYN_CMD, + .addr = 0x38, + }, [BLK_IDX_XMII_PARAMS] = {0}, }; diff --git a/drivers/net/dsa/sja1105/sja1105_static_config.c b/drivers/net/dsa/sja1105/sja1105_static_config.c index bbfe034910a0..09125f1c064d 100644 --- a/drivers/net/dsa/sja1105/sja1105_static_config.c +++ b/drivers/net/dsa/sja1105/sja1105_static_config.c @@ -463,6 +463,22 @@ static size_t sja1105_xmii_params_entry_packing(void *buf, void *entry_ptr, return size; } +size_t sja1105_retagging_entry_packing(void *buf, void *entry_ptr, + enum packing_op op) +{ + struct sja1105_retagging_entry *entry = entry_ptr; + const size_t size = SJA1105_SIZE_RETAGGING_ENTRY; + + sja1105_packing(buf, &entry->egr_port, 63, 59, size, op); + sja1105_packing(buf, &entry->ing_port, 58, 54, size, op); + sja1105_packing(buf, &entry->vlan_ing, 53, 42, size, op); + sja1105_packing(buf, &entry->vlan_egr, 41, 30, size, op); + sja1105_packing(buf, &entry->do_not_learn, 29, 29, size, op); + sja1105_packing(buf, &entry->use_dest_ports, 28, 28, size, op); + sja1105_packing(buf, &entry->destports, 27, 23, size, op); + return size; +} + size_t sja1105_table_header_packing(void *buf, void *entry_ptr, enum packing_op op) { @@ -521,6 +537,7 @@ static u64 blk_id_map[BLK_IDX_MAX] = { [BLK_IDX_L2_FORWARDING_PARAMS] = BLKID_L2_FORWARDING_PARAMS, [BLK_IDX_AVB_PARAMS] = BLKID_AVB_PARAMS, [BLK_IDX_GENERAL_PARAMS] = BLKID_GENERAL_PARAMS, + [BLK_IDX_RETAGGING] = BLKID_RETAGGING, [BLK_IDX_XMII_PARAMS] = BLKID_XMII_PARAMS, }; @@ -560,14 +577,19 @@ static sja1105_config_valid_t static_config_check_memory_size(const struct sja1105_table *tables) { const struct sja1105_l2_forwarding_params_entry *l2_fwd_params; - int i, mem = 0; + int i, max_mem, mem = 0; l2_fwd_params = tables[BLK_IDX_L2_FORWARDING_PARAMS].entries; for (i = 0; i < 8; i++) mem += l2_fwd_params->part_spc[i]; - if (mem > SJA1105_MAX_FRAME_MEMORY) + if (tables[BLK_IDX_RETAGGING].entry_count) + max_mem = SJA1105_MAX_FRAME_MEMORY_RETAGGING; + else + max_mem = SJA1105_MAX_FRAME_MEMORY; + + if (mem > max_mem) return SJA1105_OVERCOMMITTED_FRAME_MEMORY; return SJA1105_CONFIG_OK; @@ -759,6 +781,12 @@ struct sja1105_table_ops sja1105e_table_ops[BLK_IDX_MAX] = { .packed_entry_size = SJA1105ET_SIZE_GENERAL_PARAMS_ENTRY, .max_entry_count = SJA1105_MAX_GENERAL_PARAMS_COUNT, }, + [BLK_IDX_RETAGGING] = { + .packing = sja1105_retagging_entry_packing, + .unpacked_entry_size = sizeof(struct sja1105_retagging_entry), + .packed_entry_size = SJA1105_SIZE_RETAGGING_ENTRY, + .max_entry_count = SJA1105_MAX_RETAGGING_COUNT, + }, [BLK_IDX_XMII_PARAMS] = { .packing = sja1105_xmii_params_entry_packing, .unpacked_entry_size = sizeof(struct sja1105_xmii_params_entry), @@ -847,6 +875,12 @@ struct sja1105_table_ops sja1105t_table_ops[BLK_IDX_MAX] = { .packed_entry_size = SJA1105ET_SIZE_GENERAL_PARAMS_ENTRY, .max_entry_count = SJA1105_MAX_GENERAL_PARAMS_COUNT, }, + [BLK_IDX_RETAGGING] = { + .packing = sja1105_retagging_entry_packing, + .unpacked_entry_size = sizeof(struct sja1105_retagging_entry), + .packed_entry_size = SJA1105_SIZE_RETAGGING_ENTRY, + .max_entry_count = SJA1105_MAX_RETAGGING_COUNT, + }, [BLK_IDX_XMII_PARAMS] = { .packing = sja1105_xmii_params_entry_packing, .unpacked_entry_size = sizeof(struct sja1105_xmii_params_entry), @@ -915,6 +949,12 @@ struct sja1105_table_ops sja1105p_table_ops[BLK_IDX_MAX] = { .packed_entry_size = SJA1105PQRS_SIZE_GENERAL_PARAMS_ENTRY, .max_entry_count = SJA1105_MAX_GENERAL_PARAMS_COUNT, }, + [BLK_IDX_RETAGGING] = { + .packing = sja1105_retagging_entry_packing, + .unpacked_entry_size = sizeof(struct sja1105_retagging_entry), + .packed_entry_size = SJA1105_SIZE_RETAGGING_ENTRY, + .max_entry_count = SJA1105_MAX_RETAGGING_COUNT, + }, [BLK_IDX_XMII_PARAMS] = { .packing = sja1105_xmii_params_entry_packing, .unpacked_entry_size = sizeof(struct sja1105_xmii_params_entry), @@ -1003,6 +1043,12 @@ struct sja1105_table_ops sja1105q_table_ops[BLK_IDX_MAX] = { .packed_entry_size = SJA1105PQRS_SIZE_GENERAL_PARAMS_ENTRY, .max_entry_count = SJA1105_MAX_GENERAL_PARAMS_COUNT, }, + [BLK_IDX_RETAGGING] = { + .packing = sja1105_retagging_entry_packing, + .unpacked_entry_size = sizeof(struct sja1105_retagging_entry), + .packed_entry_size = SJA1105_SIZE_RETAGGING_ENTRY, + .max_entry_count = SJA1105_MAX_RETAGGING_COUNT, + }, [BLK_IDX_XMII_PARAMS] = { .packing = sja1105_xmii_params_entry_packing, .unpacked_entry_size = sizeof(struct sja1105_xmii_params_entry), @@ -1071,6 +1117,12 @@ struct sja1105_table_ops sja1105r_table_ops[BLK_IDX_MAX] = { .packed_entry_size = SJA1105PQRS_SIZE_GENERAL_PARAMS_ENTRY, .max_entry_count = SJA1105_MAX_GENERAL_PARAMS_COUNT, }, + [BLK_IDX_RETAGGING] = { + .packing = sja1105_retagging_entry_packing, + .unpacked_entry_size = sizeof(struct sja1105_retagging_entry), + .packed_entry_size = SJA1105_SIZE_RETAGGING_ENTRY, + .max_entry_count = SJA1105_MAX_RETAGGING_COUNT, + }, [BLK_IDX_XMII_PARAMS] = { .packing = sja1105_xmii_params_entry_packing, .unpacked_entry_size = sizeof(struct sja1105_xmii_params_entry), @@ -1159,6 +1211,12 @@ struct sja1105_table_ops sja1105s_table_ops[BLK_IDX_MAX] = { .packed_entry_size = SJA1105PQRS_SIZE_GENERAL_PARAMS_ENTRY, .max_entry_count = SJA1105_MAX_GENERAL_PARAMS_COUNT, }, + [BLK_IDX_RETAGGING] = { + .packing = sja1105_retagging_entry_packing, + .unpacked_entry_size = sizeof(struct sja1105_retagging_entry), + .packed_entry_size = SJA1105_SIZE_RETAGGING_ENTRY, + .max_entry_count = SJA1105_MAX_RETAGGING_COUNT, + }, [BLK_IDX_XMII_PARAMS] = { .packing = sja1105_xmii_params_entry_packing, .unpacked_entry_size = sizeof(struct sja1105_xmii_params_entry), diff --git a/drivers/net/dsa/sja1105/sja1105_static_config.h b/drivers/net/dsa/sja1105/sja1105_static_config.h index 8afafb6aef12..fa7bdd95cfd1 100644 --- a/drivers/net/dsa/sja1105/sja1105_static_config.h +++ b/drivers/net/dsa/sja1105/sja1105_static_config.h @@ -17,6 +17,7 @@ #define SJA1105_SIZE_VLAN_LOOKUP_ENTRY 8 #define SJA1105_SIZE_L2_FORWARDING_ENTRY 8 #define SJA1105_SIZE_L2_FORWARDING_PARAMS_ENTRY 12 +#define SJA1105_SIZE_RETAGGING_ENTRY 8 #define SJA1105_SIZE_XMII_PARAMS_ENTRY 4 #define SJA1105_SIZE_SCHEDULE_PARAMS_ENTRY 12 #define SJA1105_SIZE_SCHEDULE_ENTRY_POINTS_PARAMS_ENTRY 4 @@ -46,6 +47,7 @@ enum { BLKID_L2_FORWARDING_PARAMS = 0x0E, BLKID_AVB_PARAMS = 0x10, BLKID_GENERAL_PARAMS = 0x11, + BLKID_RETAGGING = 0x12, BLKID_XMII_PARAMS = 0x4E, }; @@ -63,6 +65,7 @@ enum sja1105_blk_idx { BLK_IDX_L2_FORWARDING_PARAMS, BLK_IDX_AVB_PARAMS, BLK_IDX_GENERAL_PARAMS, + BLK_IDX_RETAGGING, BLK_IDX_XMII_PARAMS, BLK_IDX_MAX, /* Fake block indices that are only valid for dynamic access */ @@ -83,10 +86,12 @@ enum sja1105_blk_idx { #define SJA1105_MAX_L2_LOOKUP_PARAMS_COUNT 1 #define SJA1105_MAX_L2_FORWARDING_PARAMS_COUNT 1 #define SJA1105_MAX_GENERAL_PARAMS_COUNT 1 +#define SJA1105_MAX_RETAGGING_COUNT 32 #define SJA1105_MAX_XMII_PARAMS_COUNT 1 #define SJA1105_MAX_AVB_PARAMS_COUNT 1 #define SJA1105_MAX_FRAME_MEMORY 929 +#define SJA1105_MAX_FRAME_MEMORY_RETAGGING 910 #define SJA1105E_DEVICE_ID 0x9C00000Cull #define SJA1105T_DEVICE_ID 0x9E00030Eull @@ -257,6 +262,16 @@ struct sja1105_mac_config_entry { u64 ingress; }; +struct sja1105_retagging_entry { + u64 egr_port; + u64 ing_port; + u64 vlan_ing; + u64 vlan_egr; + u64 do_not_learn; + u64 use_dest_ports; + u64 destports; +}; + struct sja1105_xmii_params_entry { u64 phy_mac[5]; u64 xmii_mode[5]; From patchwork Mon May 4 12:43:21 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1282583 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=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; 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.a=rsa-sha256 header.s=20161025 header.b=NSpNmB5i; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 49G2c81XGLz9sSc for ; Mon, 4 May 2020 22:44:24 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728901AbgEDMoX (ORCPT ); Mon, 4 May 2020 08:44:23 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35594 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1728878AbgEDMoV (ORCPT ); Mon, 4 May 2020 08:44:21 -0400 Received: from mail-wm1-x341.google.com (mail-wm1-x341.google.com [IPv6:2a00:1450:4864:20::341]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 238D5C061A10 for ; Mon, 4 May 2020 05:44:19 -0700 (PDT) Received: by mail-wm1-x341.google.com with SMTP id u16so8847473wmc.5 for ; Mon, 04 May 2020 05:44:19 -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=zamKz/OEXE5VTT9xTFrE5unYHuyrJjhAH/AzuTBuV2A=; b=NSpNmB5iLmMcBmmtS5QEUdaCa/0IchQWYgtwkj453bw/k5DUMz8Gm0bVMLd02B0q4o oRiWcvvZxYyrxzkrPD49NYicgbRvBOgGJl9x75EET8J1aki5cZ6+IUqVWYxCsvd6hvDk aMcE8uALBin7A6a2qcufvo5PzylueirH2FilFegk8d8dhV/p1KYW8Gcs2ACAJpzwcMBU FkuZOcpJ5R2jHlkRD7lZvuD0KrrQyFS6tyxd2gjK2hJuy/44iVLVyed46SynjpFf67sd pjHiRJ4dHlhPRW+j7zCBDOdGN3AU5Ba2Crj03Scs2uu73fj81jjBNu2X1FPgDhbBYcqK XM3Q== 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=zamKz/OEXE5VTT9xTFrE5unYHuyrJjhAH/AzuTBuV2A=; b=P81L0h53peWE+d12vxZIFpnauL1SJA2npJhYGOFOPW56+Tf0Dr3CfePm5VuJNWm7Ff 9SsgN66rTdmFNmjssmt9Ck2hEL810mCYLZMQsY0rexA0O2u6lC8laXOPbjUlLr6b3nyc xeYOIjTKKQUgvr/VE4HG+NAeNarqYFoqY+mumXk649hoAW+82xkPA1t1wFyen4Bz809X b7PHsIX4VISbOxfxM+ndWm4a9IihDg0noVf9yP4DnoD6+r7WkvD8bLC2aAkXeH6NAXQL r+mj3hsF7SWqqCZUTDhoFss0iixZfLwvnHdF2cTzdI+Gdo2OCxGyo4qRTZZ/zlrzKo6O J3Wg== X-Gm-Message-State: AGi0PuZi8rBdx2azShxV558AzcRO0whfFVzRP3uoVzSVgT8+Bt8WTQm4 iWTVWeqtNwjOT4C43uu1yuQ= X-Google-Smtp-Source: APiQypIWdj71G4pQOkNoM65wd+BwgY3sj8Jo//4KecdcSHiuCZR+6tKL/XdHgEIUSOpQxQg3KJZ34w== X-Received: by 2002:a7b:c181:: with SMTP id y1mr15474176wmi.83.1588596257723; Mon, 04 May 2020 05:44:17 -0700 (PDT) Received: from localhost.localdomain ([86.121.118.29]) by smtp.gmail.com with ESMTPSA id 32sm17343670wrg.19.2020.05.04.05.44.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 04 May 2020 05:44:17 -0700 (PDT) From: Vladimir Oltean To: andrew@lunn.ch, f.fainelli@gmail.com, vivien.didelot@gmail.com Cc: davem@davemloft.net, jiri@resnulli.us, idosch@idosch.org, kuba@kernel.org, netdev@vger.kernel.org, nikolay@cumulusnetworks.com, roopa@cumulusnetworks.com, georg.waibel@sensor-technik.de, o.rempel@pengutronix.de, christian.herber@nxp.com Subject: [RFC 2/6] net: dsa: sja1105: make HOSTPRIO a devlink param Date: Mon, 4 May 2020 15:43:21 +0300 Message-Id: <20200504124325.26758-3-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200504124325.26758-1-olteanv@gmail.com> References: <20200504124325.26758-1-olteanv@gmail.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Vladimir Oltean Unfortunately with this hardware, there is no way to transmit in-band QoS hints with management frames (i.e. VLAN PCP is ignored). The traffic class for these is fixed in the static config (which in turn requires a reset to change). The switch has 2 MAC filters for link-local management traffic. They are hardcoded them in the driver to 01-80-C2-xx-xx-xx and 01-1B-19-xx-xx-xx so that STP and PTP work by default. The switch checks the DMAC of frames against these masks very early in the packet processing pipeline, and if they match, they are trapped to the CPU. In fact, the match is so early that the analyzer module is bypassed and the frames do not get classified to a TC based on any QoS classification rules. The hardware designers recognized that this might be a problem, so they just invented a knob called HOSTPRIO, which all frames that are trapped to the CPU get assigned. On xmit, the MAC filters are active on the CPU port as well. So the switch wants to trap the link-local frames coming from the CPU and redirect them to the CPU, which it won't do because it's configured to avoid hairpinning. So it drops those frames when they come from the CPU port, due to lack of valid destinations. So the hardware designers invented another concept called "management routes" which are meant to bypass the MAC filters (which themselves bypass L2 forwarding). You pre-program a one-shot "management route" in the switch for a frame matching a certain DMAC, then you send it, then the switch figures out it matches this "management route" and properly sends it out the correct front-panel port. The point is that on xmit, the switch uses HOSTPRIO for the "management route" frames as well. With the new ability to add time gates for individual traffic classes, there is a real danger that the user might unknowingly turn off the traffic class for PTP, BPDUs, LLDP etc. Also, users might have certain use cases which require mapping link-local traffic to other TCs than 7. This will become even more obvious when we add offload for tc-cbs, where only 2 traffic classes per port support the SR class A and B timing requirements. So we need to manage this situation the best we can. There isn't any knob in Linux for this, so create a driver-specific devlink param which is a runtime u8. The default value is 7 (the highest priority traffic class). Patch is largely inspired by the mv88e6xxx ATU_hash devlink param implementation. Signed-off-by: Vladimir Oltean --- Please ignore this patch for now, it is not conceptually part of the series. I included it because it adds devlink plumbing to sja1105, and I didn't want to rebase the next patches. .../networking/devlink-params-sja1105.txt | 9 ++ Documentation/networking/dsa/sja1105.rst | 19 +++- MAINTAINERS | 1 + drivers/net/dsa/sja1105/sja1105.h | 1 + drivers/net/dsa/sja1105/sja1105_main.c | 94 +++++++++++++++++++ 5 files changed, 122 insertions(+), 2 deletions(-) create mode 100644 Documentation/networking/devlink-params-sja1105.txt diff --git a/Documentation/networking/devlink-params-sja1105.txt b/Documentation/networking/devlink-params-sja1105.txt new file mode 100644 index 000000000000..5096a4cf923c --- /dev/null +++ b/Documentation/networking/devlink-params-sja1105.txt @@ -0,0 +1,9 @@ +hostprio [DEVICE, DRIVER-SPECIFIC] + Configure the traffic class which will be used for + management (link-local) traffic injected and trapped + to/from the CPU. This includes STP, PTP, LLDP etc, as + well as hardware-specific meta frames with RX + timestamps. Higher is better as long as you care about + your PTP frames. + Configuration mode: runtime + Type: u8. 0-7 valid. diff --git a/Documentation/networking/dsa/sja1105.rst b/Documentation/networking/dsa/sja1105.rst index 64553d8d91cb..35d0643f1377 100644 --- a/Documentation/networking/dsa/sja1105.rst +++ b/Documentation/networking/dsa/sja1105.rst @@ -181,8 +181,23 @@ towards the switch, with the VLAN PCP bits set appropriately. Management traffic (having DMAC 01-80-C2-xx-xx-xx or 01-19-1B-xx-xx-xx) is the notable exception: the switch always treats it with a fixed priority and disregards any VLAN PCP bits even if present. The traffic class for management -traffic has a value of 7 (highest priority) at the moment, which is not -configurable in the driver. +traffic is configurable through a driver-specific devlink param called +``hostprio``, which by default has a value of 7 (highest priority):: + + devlink dev param show + spi/spi0.1: + name hostprio type driver-specific + values: + cmode runtime value 7 + + devlink dev param set spi/spi0.1 name hostprio value 5 cmode runtime + [ 389.903342] sja1105 spi0.1: Reset switch and programmed static config. Reason: Link-local traffic class + + devlink dev param show + spi/spi0.1: + name hostprio type driver-specific + values: + cmode runtime value 5 Below is an example of configuring a 500 us cyclic schedule on egress port ``swp5``. The traffic class gate for management traffic (7) is open for 100 us, diff --git a/MAINTAINERS b/MAINTAINERS index db7a6d462dff..c7c465a12935 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12137,6 +12137,7 @@ M: Vladimir Oltean L: linux-kernel@vger.kernel.org S: Maintained F: drivers/net/dsa/sja1105 +F: Documentation/networking/devlink-params-sja1105.txt NXP TDA998X DRM DRIVER M: Russell King diff --git a/drivers/net/dsa/sja1105/sja1105.h b/drivers/net/dsa/sja1105/sja1105.h index f925f6a231e2..2a21cab0888c 100644 --- a/drivers/net/dsa/sja1105/sja1105.h +++ b/drivers/net/dsa/sja1105/sja1105.h @@ -163,6 +163,7 @@ enum sja1105_reset_reason { SJA1105_AGEING_TIME, SJA1105_SCHEDULING, SJA1105_BEST_EFFORT_POLICING, + SJA1105_HOSTPRIO, }; int sja1105_static_config_reload(struct sja1105_private *priv, diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index f75ceabb4bf9..8a444e6949fd 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -1591,6 +1591,7 @@ static const char * const sja1105_reset_reasons[] = { [SJA1105_AGEING_TIME] = "Ageing time", [SJA1105_SCHEDULING] = "Time-aware scheduling", [SJA1105_BEST_EFFORT_POLICING] = "Best-effort policing", + [SJA1105_HOSTPRIO] = "Link-local traffic class", }; /* For situations where we need to change a setting at runtime that is only @@ -2020,6 +2021,92 @@ static int sja1105_vlan_del(struct dsa_switch *ds, int port, return 0; } +static int sja1105_hostprio_get(struct sja1105_private *priv, u8 *hostprio) +{ + struct sja1105_general_params_entry *general_params; + struct sja1105_table *table; + + table = &priv->static_config.tables[BLK_IDX_GENERAL_PARAMS]; + general_params = table->entries; + *hostprio = general_params->hostprio; + + return 0; +} + +static int sja1105_hostprio_set(struct sja1105_private *priv, u8 hostprio) +{ + struct sja1105_general_params_entry *general_params; + struct sja1105_table *table; + + if (hostprio >= SJA1105_NUM_TC) + return -ERANGE; + + table = &priv->static_config.tables[BLK_IDX_GENERAL_PARAMS]; + general_params = table->entries; + general_params->hostprio = hostprio; + + return sja1105_static_config_reload(priv, SJA1105_HOSTPRIO); +} + +enum sja1105_devlink_param_id { + SJA1105_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX, + SJA1105_DEVLINK_PARAM_ID_HOSTPRIO, +}; + +static int sja1105_devlink_param_get(struct dsa_switch *ds, u32 id, + struct devlink_param_gset_ctx *ctx) +{ + struct sja1105_private *priv = ds->priv; + int err; + + switch (id) { + case SJA1105_DEVLINK_PARAM_ID_HOSTPRIO: + err = sja1105_hostprio_get(priv, &ctx->val.vu8); + break; + default: + err = -EOPNOTSUPP; + break; + } + + return err; +} + +static int sja1105_devlink_param_set(struct dsa_switch *ds, u32 id, + struct devlink_param_gset_ctx *ctx) +{ + struct sja1105_private *priv = ds->priv; + int err; + + switch (id) { + case SJA1105_DEVLINK_PARAM_ID_HOSTPRIO: + err = sja1105_hostprio_set(priv, ctx->val.vu8); + break; + default: + err = -EOPNOTSUPP; + break; + } + + return err; +} + +static const struct devlink_param sja1105_devlink_params[] = { + DSA_DEVLINK_PARAM_DRIVER(SJA1105_DEVLINK_PARAM_ID_HOSTPRIO, + "hostprio", DEVLINK_PARAM_TYPE_U8, + BIT(DEVLINK_PARAM_CMODE_RUNTIME)), +}; + +static int sja1105_setup_devlink_params(struct dsa_switch *ds) +{ + return dsa_devlink_params_register(ds, sja1105_devlink_params, + ARRAY_SIZE(sja1105_devlink_params)); +} + +static void sja1105_teardown_devlink_params(struct dsa_switch *ds) +{ + dsa_devlink_params_unregister(ds, sja1105_devlink_params, + ARRAY_SIZE(sja1105_devlink_params)); +} + /* The programming model for the SJA1105 switch is "all-at-once" via static * configuration tables. Some of these can be dynamically modified at runtime, * but not the xMII mode parameters table. @@ -2085,6 +2172,10 @@ static int sja1105_setup(struct dsa_switch *ds) ds->mtu_enforcement_ingress = true; + rc = sja1105_setup_devlink_params(ds); + if (rc < 0) + return rc; + /* The DSA/switchdev model brings up switch ports in standalone mode by * default, and that means vlan_filtering is 0 since they're not under * a bridge, so it's safe to set up switch tagging at this time. @@ -2107,6 +2198,7 @@ static void sja1105_teardown(struct dsa_switch *ds) kthread_destroy_worker(sp->xmit_worker); } + sja1105_teardown_devlink_params(ds); sja1105_flower_teardown(ds); sja1105_tas_teardown(ds); sja1105_ptp_clock_unregister(ds); @@ -2445,6 +2537,8 @@ static const struct dsa_switch_ops sja1105_switch_ops = { .port_policer_del = sja1105_port_policer_del, .cls_flower_add = sja1105_cls_flower_add, .cls_flower_del = sja1105_cls_flower_del, + .devlink_param_get = sja1105_devlink_param_get, + .devlink_param_set = sja1105_devlink_param_set, .crosschip_bridge_join = sja1105_crosschip_bridge_join, .crosschip_bridge_leave = sja1105_crosschip_bridge_leave, }; From patchwork Mon May 4 12:43:22 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1282582 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=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; 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.a=rsa-sha256 header.s=20161025 header.b=kjOWA6Db; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 49G2c65k1Jz9sSc for ; Mon, 4 May 2020 22:44:22 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728894AbgEDMoW (ORCPT ); Mon, 4 May 2020 08:44:22 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35602 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1728876AbgEDMoU (ORCPT ); Mon, 4 May 2020 08:44:20 -0400 Received: from mail-wm1-x344.google.com (mail-wm1-x344.google.com [IPv6:2a00:1450:4864:20::344]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 52098C061A41 for ; Mon, 4 May 2020 05:44:20 -0700 (PDT) Received: by mail-wm1-x344.google.com with SMTP id u127so8865795wmg.1 for ; Mon, 04 May 2020 05:44:20 -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=D1kbuXB6vTsPB0I0gwKSR9cCQxqxWxU9Yl8zRddbnmE=; b=kjOWA6Dbvso4hi2U+wUWzvtRlLn4MhQ8LbMJQJPoV3g8yeby9Uj8qP6jpbbClQYiqb 7R2bnSRzsvX89K9zBgnA+u5wOT0WOjW8nr5oLBr9jwogqe7mnwCj7luZi+/j8IGO5ziD EqeXTzZ1iPqfuMkbiZP9n8nhsRjhhtRnUKbN7na6c5Mxmbc/HQri+0WzDqTyIjSn7qi0 K1+AlyM8t/Ps2fh1Pg9hxUA4tvw4Z+dvpfJVr56XBz5hIv6Ej16O4h/p8aWLyd45jzSQ a5dIinFVf4IZFEAG5u/mx5v5B2S57KdFjfY9GuYav61QjCR6VkOuZE1LmGnkjdL3jTPj QbrA== 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=D1kbuXB6vTsPB0I0gwKSR9cCQxqxWxU9Yl8zRddbnmE=; b=N8tiO5Cu0CLx6Y1IZhRlGbjBzNMYyJ0J26aAM0FvwbEG0jMMtvGGbMLSZN5u1lu68T u6oUuJe4seKf4/yaCCw0S3jTfJJjtnQdVTN1zjAOgJkAy26Fy9vveztiyT6OEPoVd7I9 0cS3dmed1yq46DFAynzE3gYE7J6pKq2atzKedCsO4gi1gTt2W8wKHrGnOB+zTrfI8Mbk dtFjzBYwfjVFHedxXjwhZCHh/8thmMoPQZ0c1FbxZs5iweywKJTBEIpTGOag348XPbvo YX+kOWa+McAkG4GYoUZ8zl/pZQiOWXyhHhpAQall3p04ZNcueeEcYydG88Ps8Ij0pUln Hkng== X-Gm-Message-State: AGi0PuaEG8VHGLqJGTL57gsv/poZ7zbgiDjYolKPInAXU25Rme2Fpnz+ hm/LI6wdYkfnXGkARSUandg= X-Google-Smtp-Source: APiQypKJxcNLApDkAoxEE72cBWcKD8vGwSe6sazehyrTVg9djUkdG5E8SX15f/RjSWcd8G6rIBTeuQ== X-Received: by 2002:a05:600c:2196:: with SMTP id e22mr14077781wme.105.1588596258909; Mon, 04 May 2020 05:44:18 -0700 (PDT) Received: from localhost.localdomain ([86.121.118.29]) by smtp.gmail.com with ESMTPSA id 32sm17343670wrg.19.2020.05.04.05.44.17 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 04 May 2020 05:44:18 -0700 (PDT) From: Vladimir Oltean To: andrew@lunn.ch, f.fainelli@gmail.com, vivien.didelot@gmail.com Cc: davem@davemloft.net, jiri@resnulli.us, idosch@idosch.org, kuba@kernel.org, netdev@vger.kernel.org, nikolay@cumulusnetworks.com, roopa@cumulusnetworks.com, georg.waibel@sensor-technik.de, o.rempel@pengutronix.de, christian.herber@nxp.com Subject: [RFC 3/6] net: dsa: tag_8021q: allow DSA tags and VLAN filtering simultaneously Date: Mon, 4 May 2020 15:43:22 +0300 Message-Id: <20200504124325.26758-4-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200504124325.26758-1-olteanv@gmail.com> References: <20200504124325.26758-1-olteanv@gmail.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Vladimir Oltean There are very good reasons to want this, but there are also very good reasons for not enabling it by default. So a devlink param named best_effort_vlan_filtering, currently driver-specific and exported only by sja1105, is used to configure this. In practice, this is perhaps the way that most users are going to use the switch in. Best-effort untagged traffic can be bridged with any net device in the system or terminated locally, and VLAN-tagged streams are forwarded autonomously in a time-sensitive manner according to their PCP (they need not transit the CPU). For those cases where the CPU needs to terminate some VLAN-tagged traffic, the next patch will also address that, via dsa_8021q sub-VLANs. Signed-off-by: Vladimir Oltean --- Documentation/networking/dsa/sja1105.rst | 21 +++--- drivers/net/dsa/sja1105/sja1105.h | 1 + drivers/net/dsa/sja1105/sja1105_main.c | 81 ++++++++++++++++++++++-- include/linux/dsa/8021q.h | 7 ++ include/linux/dsa/sja1105.h | 2 + net/dsa/tag_8021q.c | 62 ++++++++++++++++++ net/dsa/tag_sja1105.c | 16 ++--- 7 files changed, 167 insertions(+), 23 deletions(-) diff --git a/Documentation/networking/dsa/sja1105.rst b/Documentation/networking/dsa/sja1105.rst index 35d0643f1377..4a8639cba1f3 100644 --- a/Documentation/networking/dsa/sja1105.rst +++ b/Documentation/networking/dsa/sja1105.rst @@ -85,15 +85,18 @@ functionality. The following traffic modes are supported over the switch netdevices: -+--------------------+------------+------------------+------------------+ -| | Standalone | Bridged with | Bridged with | -| | ports | vlan_filtering 0 | vlan_filtering 1 | -+====================+============+==================+==================+ -| Regular traffic | Yes | Yes | No (use master) | -+--------------------+------------+------------------+------------------+ -| Management traffic | Yes | Yes | Yes | -| (BPDU, PTP) | | | | -+--------------------+------------+------------------+------------------+ ++-------------+------------+----------------+----------------+----------------------------+ +| | Standalone | Bridged with | Bridged with | Bridged with | +| | ports | vlan_filtering | vlan_filtering | best_effort_vlan_filtering | +| | | 0 | 1 | 1 | ++=============+============+================+================+============================+ +| Regular | Yes | Yes | No | Partial (untagged), | +| traffic | | | (use master) | use master for tagged | ++-------------+------------+----------------+----------------+----------------------------+ +| Management | Yes | Yes | Yes | Yes | +| traffic | | | | | +| (BPDU, PTP) | | | | | ++-------------+------------+----------------+----------------+----------------------------+ Switching features ================== diff --git a/drivers/net/dsa/sja1105/sja1105.h b/drivers/net/dsa/sja1105/sja1105.h index 2a21cab0888c..8fedcaa99f3b 100644 --- a/drivers/net/dsa/sja1105/sja1105.h +++ b/drivers/net/dsa/sja1105/sja1105.h @@ -132,6 +132,7 @@ struct sja1105_private { struct sja1105_static_config static_config; bool rgmii_rx_delay[SJA1105_NUM_PORTS]; bool rgmii_tx_delay[SJA1105_NUM_PORTS]; + bool best_effort_vlan_filtering; const struct sja1105_info *info; struct gpio_desc *reset_gpio; struct spi_device *spidev; diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index 8a444e6949fd..edbe5dd4af37 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -1901,10 +1901,27 @@ sja1105_get_tag_protocol(struct dsa_switch *ds, int port, return DSA_TAG_PROTO_SJA1105; } -/* This callback needs to be present */ static int sja1105_vlan_prepare(struct dsa_switch *ds, int port, const struct switchdev_obj_port_vlan *vlan) { + struct sja1105_private *priv = ds->priv; + u16 vid; + int rc; + + if (!dsa_port_is_vlan_filtering(dsa_to_port(ds, port)) || + !priv->best_effort_vlan_filtering) + return 0; + + /* If the user wants best-effort VLAN filtering (aka vlan_filtering + * bridge plus tagging), be sure to at least deny alterations to the + * configuration done by dsa_8021q. + */ + for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) { + rc = dsa_8021q_vid_validate(ds, port, vid, vlan->flags); + if (rc < 0) + return rc; + } + return 0; } @@ -1918,6 +1935,7 @@ static int sja1105_vlan_filtering(struct dsa_switch *ds, int port, bool enabled) struct sja1105_general_params_entry *general_params; struct sja1105_private *priv = ds->priv; struct sja1105_table *table; + bool want_tagging; u16 tpid, tpid2; int rc; @@ -1943,8 +1961,10 @@ static int sja1105_vlan_filtering(struct dsa_switch *ds, int port, bool enabled) general_params->incl_srcpt1 = enabled; general_params->incl_srcpt0 = enabled; + want_tagging = priv->best_effort_vlan_filtering || !enabled; + /* VLAN filtering => independent VLAN learning. - * No VLAN filtering => shared VLAN learning. + * No VLAN filtering (or best effort) => shared VLAN learning. * * In shared VLAN learning mode, untagged traffic still gets * pvid-tagged, and the FDB table gets populated with entries @@ -1963,7 +1983,7 @@ static int sja1105_vlan_filtering(struct dsa_switch *ds, int port, bool enabled) */ table = &priv->static_config.tables[BLK_IDX_L2_LOOKUP_PARAMS]; l2_lookup_params = table->entries; - l2_lookup_params->shared_learn = !enabled; + l2_lookup_params->shared_learn = want_tagging; rc = sja1105_static_config_reload(priv, SJA1105_VLAN_FILTERING); if (rc) @@ -1971,11 +1991,24 @@ static int sja1105_vlan_filtering(struct dsa_switch *ds, int port, bool enabled) /* Switch port identification based on 802.1Q is only passable * if we are not under a vlan_filtering bridge. So make sure - * the two configurations are mutually exclusive. + * the two configurations are mutually exclusive (of course, the + * user may know better, i.e. best_effort_vlan_filtering). */ - return sja1105_setup_8021q_tagging(ds, !enabled); + return sja1105_setup_8021q_tagging(ds, want_tagging); } +bool sja1105_can_use_vlan_as_tags(struct dsa_port *dp) +{ + struct dsa_switch *ds = dp->ds; + struct sja1105_private *priv = ds->priv; + + if (dsa_port_is_vlan_filtering(dp) && !priv->best_effort_vlan_filtering) + return false; + + return true; +} +EXPORT_SYMBOL_GPL(sja1105_can_use_vlan_as_tags); + static void sja1105_vlan_add(struct dsa_switch *ds, int port, const struct switchdev_obj_port_vlan *vlan) { @@ -2048,9 +2081,35 @@ static int sja1105_hostprio_set(struct sja1105_private *priv, u8 hostprio) return sja1105_static_config_reload(priv, SJA1105_HOSTPRIO); } +static int sja1105_best_effort_vlan_filtering_get(struct sja1105_private *priv, + bool *be_vlan) +{ + *be_vlan = priv->best_effort_vlan_filtering; + + return 0; +} + +static int sja1105_best_effort_vlan_filtering_set(struct sja1105_private *priv, + bool be_vlan) +{ + struct dsa_switch *ds = priv->ds; + bool vlan_filtering; + int rc; + + vlan_filtering = dsa_port_is_vlan_filtering(dsa_to_port(ds, 0)); + priv->best_effort_vlan_filtering = be_vlan; + + rtnl_lock(); + rc = sja1105_vlan_filtering(ds, 0, vlan_filtering); + rtnl_unlock(); + + return rc; +} + enum sja1105_devlink_param_id { SJA1105_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX, SJA1105_DEVLINK_PARAM_ID_HOSTPRIO, + SJA1105_DEVLINK_PARAM_ID_BEST_EFFORT_VLAN_FILTERING, }; static int sja1105_devlink_param_get(struct dsa_switch *ds, u32 id, @@ -2063,6 +2122,10 @@ static int sja1105_devlink_param_get(struct dsa_switch *ds, u32 id, case SJA1105_DEVLINK_PARAM_ID_HOSTPRIO: err = sja1105_hostprio_get(priv, &ctx->val.vu8); break; + case SJA1105_DEVLINK_PARAM_ID_BEST_EFFORT_VLAN_FILTERING: + err = sja1105_best_effort_vlan_filtering_get(priv, + &ctx->val.vbool); + break; default: err = -EOPNOTSUPP; break; @@ -2081,6 +2144,10 @@ static int sja1105_devlink_param_set(struct dsa_switch *ds, u32 id, case SJA1105_DEVLINK_PARAM_ID_HOSTPRIO: err = sja1105_hostprio_set(priv, ctx->val.vu8); break; + case SJA1105_DEVLINK_PARAM_ID_BEST_EFFORT_VLAN_FILTERING: + err = sja1105_best_effort_vlan_filtering_set(priv, + ctx->val.vbool); + break; default: err = -EOPNOTSUPP; break; @@ -2093,6 +2160,10 @@ static const struct devlink_param sja1105_devlink_params[] = { DSA_DEVLINK_PARAM_DRIVER(SJA1105_DEVLINK_PARAM_ID_HOSTPRIO, "hostprio", DEVLINK_PARAM_TYPE_U8, BIT(DEVLINK_PARAM_CMODE_RUNTIME)), + DSA_DEVLINK_PARAM_DRIVER(SJA1105_DEVLINK_PARAM_ID_BEST_EFFORT_VLAN_FILTERING, + "best_effort_vlan_filtering", + DEVLINK_PARAM_TYPE_BOOL, + BIT(DEVLINK_PARAM_CMODE_RUNTIME)), }; static int sja1105_setup_devlink_params(struct dsa_switch *ds) diff --git a/include/linux/dsa/8021q.h b/include/linux/dsa/8021q.h index b8daaec0896e..dfbd5b62f67a 100644 --- a/include/linux/dsa/8021q.h +++ b/include/linux/dsa/8021q.h @@ -25,6 +25,8 @@ struct dsa_8021q_crosschip_link { int dsa_port_setup_8021q_tagging(struct dsa_switch *ds, int index, bool enabled); +int dsa_8021q_vid_validate(struct dsa_switch *ds, int port, u16 vid, u16 flags); + int dsa_8021q_crosschip_link_apply(struct dsa_switch *ds, int port, struct dsa_switch *other_ds, int other_port, bool enabled); @@ -58,6 +60,11 @@ int dsa_port_setup_8021q_tagging(struct dsa_switch *ds, int index, return 0; } +int dsa_8021q_vid_validate(struct dsa_switch *ds, int port, u16 vid, u16 flags) +{ + return 0; +} + int dsa_8021q_crosschip_link_apply(struct dsa_switch *ds, int port, struct dsa_switch *other_ds, int other_port, bool enabled) diff --git a/include/linux/dsa/sja1105.h b/include/linux/dsa/sja1105.h index fa5735c353cd..a609fdbe1355 100644 --- a/include/linux/dsa/sja1105.h +++ b/include/linux/dsa/sja1105.h @@ -61,4 +61,6 @@ struct sja1105_port { bool hwts_tx_en; }; +bool sja1105_can_use_vlan_as_tags(struct dsa_port *dp); + #endif /* _NET_DSA_SJA1105_H */ diff --git a/net/dsa/tag_8021q.c b/net/dsa/tag_8021q.c index ff9c5bf64bda..158584153e15 100644 --- a/net/dsa/tag_8021q.c +++ b/net/dsa/tag_8021q.c @@ -289,6 +289,68 @@ int dsa_port_setup_8021q_tagging(struct dsa_switch *ds, int port, bool enabled) } EXPORT_SYMBOL_GPL(dsa_port_setup_8021q_tagging); +int dsa_8021q_vid_validate(struct dsa_switch *ds, int port, u16 vid, u16 flags) +{ + int upstream = dsa_upstream_port(ds, port); + int rx_vid_of = ds->num_ports; + int tx_vid_of = ds->num_ports; + int other_port; + + /* @vid wants to be a pvid of @port, but is not equal to its rx_vid */ + if ((flags & BRIDGE_VLAN_INFO_PVID) && + vid != dsa_8021q_rx_vid(ds, port)) + return -EPERM; + + for (other_port = 0; other_port < ds->num_ports; other_port++) { + if (vid == dsa_8021q_rx_vid(ds, other_port)) { + rx_vid_of = other_port; + break; + } + if (vid == dsa_8021q_tx_vid(ds, other_port)) { + tx_vid_of = other_port; + break; + } + } + + /* @vid is a TX VLAN of the @tx_vid_of port */ + if (tx_vid_of != ds->num_ports) { + if (tx_vid_of == port) { + if (flags != BRIDGE_VLAN_INFO_UNTAGGED) + return -EPERM; + /* Fall through on proper flags */ + } else if (port == upstream) { + if (flags != 0) + return -EPERM; + /* Fall through on proper flags */ + } else { + /* Trying to configure on other port */ + return -EPERM; + } + } + + /* @vid is an RX VLAN of the @rx_vid_of port */ + if (rx_vid_of != ds->num_ports) { + if (rx_vid_of == port) { + if (flags != (BRIDGE_VLAN_INFO_UNTAGGED | + BRIDGE_VLAN_INFO_PVID)) + return -EPERM; + /* Fall through on proper flags */ + } else if (port == upstream) { + if (flags != 0) + return -EPERM; + /* Fall through on proper flags */ + } else if (flags != BRIDGE_VLAN_INFO_UNTAGGED) { + /* Trying to configure on other port, but with + * invalid flags. + */ + return -EPERM; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(dsa_8021q_vid_validate); + int dsa_8021q_crosschip_link_apply(struct dsa_switch *ds, int port, struct dsa_switch *other_ds, int other_port, bool enabled) diff --git a/net/dsa/tag_sja1105.c b/net/dsa/tag_sja1105.c index d553bf36bd41..72d76743c272 100644 --- a/net/dsa/tag_sja1105.c +++ b/net/dsa/tag_sja1105.c @@ -74,7 +74,7 @@ static inline bool sja1105_is_meta_frame(const struct sk_buff *skb) */ static bool sja1105_filter(const struct sk_buff *skb, struct net_device *dev) { - if (!dsa_port_is_vlan_filtering(dev->dsa_ptr)) + if (sja1105_can_use_vlan_as_tags(skb->dev->dsa_ptr)) return true; if (sja1105_is_link_local(skb)) return true; @@ -103,6 +103,7 @@ static struct sk_buff *sja1105_xmit(struct sk_buff *skb, u16 tx_vid = dsa_8021q_tx_vid(dp->ds, dp->index); u16 queue_mapping = skb_get_queue_mapping(skb); u8 pcp = netdev_txq_to_tc(netdev, queue_mapping); + u16 tpid; /* Transmitting management traffic does not rely upon switch tagging, * but instead SPI-installed management routes. Part 2 of this @@ -111,15 +112,12 @@ static struct sk_buff *sja1105_xmit(struct sk_buff *skb, if (unlikely(sja1105_is_link_local(skb))) return sja1105_defer_xmit(dp->priv, skb); - /* If we are under a vlan_filtering bridge, IP termination on - * switch ports based on 802.1Q tags is simply too brittle to - * be passable. So just defer to the dsa_slave_notag_xmit - * implementation. - */ if (dsa_port_is_vlan_filtering(dp)) - return skb; + tpid = ETH_P_8021Q; + else + tpid = ETH_P_SJA1105; - return dsa_8021q_xmit(skb, netdev, ETH_P_SJA1105, + return dsa_8021q_xmit(skb, netdev, tpid, ((pcp << VLAN_PRIO_SHIFT) | tx_vid)); } @@ -258,7 +256,7 @@ static struct sk_buff *sja1105_rcv(struct sk_buff *skb, hdr = eth_hdr(skb); tpid = ntohs(hdr->h_proto); - is_tagged = (tpid == ETH_P_SJA1105); + is_tagged = (tpid == ETH_P_SJA1105 || tpid == ETH_P_8021Q); is_link_local = sja1105_is_link_local(skb); is_meta = sja1105_is_meta_frame(skb); From patchwork Mon May 4 12:43:23 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1282586 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=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; 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.a=rsa-sha256 header.s=20161025 header.b=ozvX5ZbX; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 49G2cQ1BYwz9sSd for ; Mon, 4 May 2020 22:44:38 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728921AbgEDMof (ORCPT ); Mon, 4 May 2020 08:44:35 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35604 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1728079AbgEDMoV (ORCPT ); Mon, 4 May 2020 08:44:21 -0400 Received: from mail-wr1-x441.google.com (mail-wr1-x441.google.com [IPv6:2a00:1450:4864:20::441]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6EA79C061A0E for ; Mon, 4 May 2020 05:44:21 -0700 (PDT) Received: by mail-wr1-x441.google.com with SMTP id i10so20721570wrv.10 for ; Mon, 04 May 2020 05:44:21 -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=aMUeZPhAHahhEsEZ8yqPryuY729nsIpF6ZIBOZrog/E=; b=ozvX5ZbXg4DZPJm7JylT5zofJyeJoDfrI+Z4w2TqAW0DergchiK84yfy3rF+gKKbGI y+RDe2b2hiNLTc4cSW6NfdTuo9577enO0Z+o12VnvFs0uZNBzJIxJ+AFKd+8j+D5A/Mi 1UtbB5yYOxFMUafrD1xlRLxtViEUwu5SDLhmP0DKuOXUW06EknxMceuWMFMmeRvwMDex wMgYnra6zMHOqZYBgzhehMXpc32BZn+6O1i9QyRVZ7jha20cFTJIuCEKTEjUknE4b85A F3MP6W8lc5Y6IYU828NQy5IfWZrzHpnH4R9PDtn8AVQYGByvryQWvjRUpdJdjzD8hnpC TDEg== 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=aMUeZPhAHahhEsEZ8yqPryuY729nsIpF6ZIBOZrog/E=; b=nnvUMYtQnhfUu0D6lbfxEKo6eCgD5mHbnbWA+k4JTrTmRNvxfXWfzJd8IH/wVwG7tM GItbrtwcqR79Pvm2aRP4TP9sWXOuWCyScKRItN/iIYaV6r8A1KjWt+5lVyRbtosDvEf+ LfUFGU+V2dsdW8c21ewaUNmOlSg5wfN+J1wR4GebKoJ+WaUHmlV1r2q1b49aOhSY4EkN aA3KkARq5kk6SZW7vibnJx4tbq4Jp6i4p8dLTGJ9kal/+XnQto5B+o5fp4MOl2I//jCM euP9giWiWCAwu+jFRA1S6Q+IRGIqdKSj0RYITn5FLO5pvjU66lR9s6Xi8opexWGmfdm8 GZog== X-Gm-Message-State: AGi0PuZfFdBle4HPdk6qMkYlbE33Kl21tRfxISnSyoJuc84Tm0PYBL62 Psu+hsl4PpAdlHwDrwsp8zI= X-Google-Smtp-Source: APiQypIuC/TbMrUmkyUT8ix9qZsNg7fPuf12hG3aVdWvW5Pi1PKtg7gZ+wOzpWWZc95eIBStRimTig== X-Received: by 2002:adf:fe01:: with SMTP id n1mr7176445wrr.268.1588596260195; Mon, 04 May 2020 05:44:20 -0700 (PDT) Received: from localhost.localdomain ([86.121.118.29]) by smtp.gmail.com with ESMTPSA id 32sm17343670wrg.19.2020.05.04.05.44.18 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 04 May 2020 05:44:19 -0700 (PDT) From: Vladimir Oltean To: andrew@lunn.ch, f.fainelli@gmail.com, vivien.didelot@gmail.com Cc: davem@davemloft.net, jiri@resnulli.us, idosch@idosch.org, kuba@kernel.org, netdev@vger.kernel.org, nikolay@cumulusnetworks.com, roopa@cumulusnetworks.com, georg.waibel@sensor-technik.de, o.rempel@pengutronix.de, christian.herber@nxp.com Subject: [RFC 4/6] net: dsa: tag_8021q: skip disabled ports Date: Mon, 4 May 2020 15:43:23 +0300 Message-Id: <20200504124325.26758-5-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200504124325.26758-1-olteanv@gmail.com> References: <20200504124325.26758-1-olteanv@gmail.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Vladimir Oltean Not only is it not needed to program dsa_8021q VLANs into ports that are not used, but it also makes validation impossible, given the fact that port == dsa_upstream_port(ds, port) for a port that is disabled. So when a user port wants to install its rx_vid into us (we the disabled port), think that we are in fact the CPU port, so we want the flags to be egress-tagged (which they aren't). So instead of trying to make dsa_upstream_port return something more sensible for disabled ports, skip this nonsense altogether. Because we didn't have VID validation until now, there's no reason to treat this patch as a bugfix. Signed-off-by: Vladimir Oltean --- net/dsa/tag_8021q.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/dsa/tag_8021q.c b/net/dsa/tag_8021q.c index 158584153e15..3958f426d60e 100644 --- a/net/dsa/tag_8021q.c +++ b/net/dsa/tag_8021q.c @@ -239,7 +239,7 @@ int dsa_port_setup_8021q_tagging(struct dsa_switch *ds, int port, bool enabled) for (i = 0; i < ds->num_ports; i++) { u16 flags; - if (i == upstream) + if (!dsa_is_user_port(ds, i)) continue; else if (i == port) /* The RX VID is pvid on this port */ @@ -302,6 +302,8 @@ int dsa_8021q_vid_validate(struct dsa_switch *ds, int port, u16 vid, u16 flags) return -EPERM; for (other_port = 0; other_port < ds->num_ports; other_port++) { + if (!dsa_is_user_port(ds, other_port)) + continue; if (vid == dsa_8021q_rx_vid(ds, other_port)) { rx_vid_of = other_port; break; From patchwork Mon May 4 12:43:24 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1282584 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=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; 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.a=rsa-sha256 header.s=20161025 header.b=rw3MrNKN; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 49G2cD6YrNz9sSc for ; Mon, 4 May 2020 22:44:28 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728904AbgEDMo1 (ORCPT ); Mon, 4 May 2020 08:44:27 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35610 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1728125AbgEDMoX (ORCPT ); Mon, 4 May 2020 08:44:23 -0400 Received: from mail-wr1-x444.google.com (mail-wr1-x444.google.com [IPv6:2a00:1450:4864:20::444]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0F93DC061A0E for ; Mon, 4 May 2020 05:44:23 -0700 (PDT) Received: by mail-wr1-x444.google.com with SMTP id i10so20721687wrv.10 for ; Mon, 04 May 2020 05:44:22 -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=k9wnPAkGNLB0wQOlYn6wdF/PnMiFe9GBaa49zGf0rRY=; b=rw3MrNKNK4UYS2LTZNsVF4tMZGTIT+kXwGNegImFKt0cwPYTY2AObpUJJtL9CR7E4i RR5q0Gcga0zdr4vAUriWkh+6pacmg1xf39SjyAEMbxmWWiwsVWoNlUSDDbjskkqTTiNe Dn8F2PW+dNaVyTGlCZyx28mMkjWynNgYh2SIYqedOcdYBlbw+OR4hibeNPKReDOOScEV DtEV3sNq/4avZ1y9v3Hwo3yny9eG2Syh+cSGZy7h/YHKnyX1Y6C6wKiEX3khTrzdIB+A jT+TpkqgpGJQchQSGuJ1VxsIgT15o4guvvweAWUQhWW99mRR7E32RWtmzr4Rtp+vD2z3 Tj0w== 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=k9wnPAkGNLB0wQOlYn6wdF/PnMiFe9GBaa49zGf0rRY=; b=r4nsDbxqXhM3cyX0t6u7nCFaPAJpwcURxfmE2fh4lB6gv6B0IWppkcLd4DSCOiAI+I jzBhSOWzRwf1i02e1RC0wM/ET2QNECwuFAkhk8PU4EJndOtEgkBnk/WMCfsobkJZ778/ Gz8WwGyEYmCOGk4byQGUNb8fYNSYVUz0WlJ4VYLY77VGbvnF2mqNcH+000aPJjM0ZOcA 6AwBJ7Yv+EeQo6xDn5TLDDwUMIeLbCkdxx2yWeUTHcqY7kE7sEuoFGQs95wfFBM9BoSv bNyopDGWDwt0Q4+7lP4f1+O6lyUSNAng7NNZAPHSltIqtOg7JHglELpl32ImQbHSmdra yp5w== X-Gm-Message-State: AGi0PuZsIXwtRkwEITw0+pqV9EjBczxgIPgh8Sko/Mktdf23LRgfywSO l5xNHjeYXDkdHJy/JFDcm5k= X-Google-Smtp-Source: APiQypIUYrmRG8C1j4X7GDXO+7ouzB5jlUG/1xc9y8U/nyQ8jGl08x8fjWepBidnLdBRaLzw0usGPg== X-Received: by 2002:adf:e751:: with SMTP id c17mr1943491wrn.351.1588596261459; Mon, 04 May 2020 05:44:21 -0700 (PDT) Received: from localhost.localdomain ([86.121.118.29]) by smtp.gmail.com with ESMTPSA id 32sm17343670wrg.19.2020.05.04.05.44.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 04 May 2020 05:44:21 -0700 (PDT) From: Vladimir Oltean To: andrew@lunn.ch, f.fainelli@gmail.com, vivien.didelot@gmail.com Cc: davem@davemloft.net, jiri@resnulli.us, idosch@idosch.org, kuba@kernel.org, netdev@vger.kernel.org, nikolay@cumulusnetworks.com, roopa@cumulusnetworks.com, georg.waibel@sensor-technik.de, o.rempel@pengutronix.de, christian.herber@nxp.com Subject: [RFC 5/6] net: dsa: sja1105: support up to 7 VLANs per port using retagging Date: Mon, 4 May 2020 15:43:24 +0300 Message-Id: <20200504124325.26758-6-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200504124325.26758-1-olteanv@gmail.com> References: <20200504124325.26758-1-olteanv@gmail.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Vladimir Oltean For switches that support VLAN retagging, such as sja1105, we extend dsa_8021q by encoding a "sub-VLAN" into the remaining 3 free bits in the dsa_8021q tag. A sub-VLAN is nothing more than a number in the range 0-7, which serves as an index into a per-port driver lookup table. The sub-VLAN value of zero means that traffic is untagged (this is also backwards-compatible with dsa_8021q without retagging). The switch is configured to retag VLAN-tagged traffic that gets transmitted towards the CPU port (and towards the CPU only). Example: bridge vlan add dev sw1p0 vid 100 The switch retags frames received on port 0, going to the CPU, and having VID 100, to the VID of 1104 0x0450. In dsa_8021q language, 0x0450 means: | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | +-----------+-----+-----------------+-----------+-----------------------+ | DIR | SVL | SWITCH_ID | SUBVLAN | PORT | +-----------+-----+-----------------+-----------+-----------------------+ aka: - DIR = 0b01: this is an RX VLAN - SUBVLAN = 0b001: this is subvlan #1 - SWITCH_ID = 0b001: this is switch 1 (see the name "sw1p0") - PORT = 0b0000: this is port 0 (see the name "sw1p0") The driver also remembers the "1 -> 100" mapping. In the hotpath, if the sub-VLAN from the tag encodes a non-untagged frame, this mapping is used to create a VLAN hwaccel tag, with the value of 100. There are some performance-related concerns, since all VLAN-retagged traffic cannot exceed 1Gbps due to the way it is implemented in hardware. This should not be an issue, because: - We only support retagging towards the CPU port, which is limited at 1Gbps anyway. - VLAN-tagged traffic between ports on the same chip works without retagging. - Untagged traffic, autonomously forwarded as well as terminated locally, works without retagging. On xmit from Linux, transmitting VLAN-tagged traffic is possible by adding a second VLAN tag with the tx_vid (which encode the destination port). But this tag needs to be transmitted using a different TPID than the plain ETH_P_8021Q, because otherwise, the switch thinks we're trying to do VLAN hopping, it freaks out and drops our frame. By using a TPID of ETH_P_8021AD, it looks at the S-tag only, which is what we want. Signed-off-by: Vladimir Oltean --- drivers/net/dsa/sja1105/sja1105_main.c | 244 ++++++++++++++++++++++++- include/linux/dsa/8021q.h | 31 ++++ include/linux/dsa/sja1105.h | 2 + net/dsa/tag_8021q.c | 80 ++++++-- net/dsa/tag_sja1105.c | 21 ++- 5 files changed, 357 insertions(+), 21 deletions(-) diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index edbe5dd4af37..106182103b19 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -387,7 +387,8 @@ static int sja1105_init_l2_forwarding_params(struct sja1105_private *priv) /* Disallow dynamic reconfiguration of vlan_pmap */ .max_dynp = 0, /* Use a single memory partition for all ingress queues */ - .part_spc = { SJA1105_MAX_FRAME_MEMORY, 0, 0, 0, 0, 0, 0, 0 }, + .part_spc = { SJA1105_MAX_FRAME_MEMORY_RETAGGING, + 0, 0, 0, 0, 0, 0, 0 }, }; struct sja1105_table *table; @@ -1733,6 +1734,31 @@ static int sja1105_is_vlan_configured(struct sja1105_private *priv, u16 vid) return -1; } +/* The Retagging Table generates packet *clones* with the new VLAN. This is a + * very odd hardware quirk which we need to suppress by dropping the original + * packet. We do that by removing the pre-retagging VID from the port + * membership of the egress port. For this strategy to be effective, we need a + * blacklist to ensure that nobody can add that VID back on the destination + * port, otherwise we'll see duplicates (with the old and the new VID). + */ +static bool sja1105_vlan_is_blacklisted(struct sja1105_private *priv, int port, + u16 vid) +{ + struct sja1105_retagging_entry *retagging; + struct sja1105_table *table; + int i; + + table = &priv->static_config.tables[BLK_IDX_RETAGGING]; + retagging = table->entries; + + for (i = 0; i < table->entry_count; i++) + if ((retagging[i].egr_port & BIT(port)) && + (retagging[i].vlan_ing == vid)) + return true; + + return false; +} + static int sja1105_vlan_apply(struct sja1105_private *priv, int port, u16 vid, bool enabled, bool untagged) { @@ -1741,6 +1767,9 @@ static int sja1105_vlan_apply(struct sja1105_private *priv, int port, u16 vid, bool keep = true; int match, rc; + if (enabled && sja1105_vlan_is_blacklisted(priv, port, vid)) + return 0; + table = &priv->static_config.tables[BLK_IDX_VLAN_LOOKUP]; match = sja1105_is_vlan_configured(priv, vid); @@ -1793,6 +1822,194 @@ static int sja1105_vlan_apply(struct sja1105_private *priv, int port, u16 vid, return 0; } +static int sja1105_find_retagging_entry(struct sja1105_private *priv, + int from_port, u16 from_vid, + int to_port, u16 to_vid) +{ + struct sja1105_retagging_entry *retagging; + struct sja1105_table *table; + int i; + + table = &priv->static_config.tables[BLK_IDX_RETAGGING]; + retagging = table->entries; + + for (i = 0; i < table->entry_count; i++) + if (retagging[i].ing_port & BIT(from_port) && + retagging[i].egr_port & BIT(to_port) && + retagging[i].vlan_ing == from_vid && + retagging[i].vlan_egr == to_vid) + return i; + + return -1; +} + +static int sja1105_setup_retagging_vid(struct sja1105_private *priv, + int from_port, u16 from_vid, int to_port, + u16 to_vid, bool keep, bool untagged) +{ + int rc; + + rc = sja1105_vlan_apply(priv, from_port, to_vid, keep, true); + if (rc) + return rc; + + rc = sja1105_vlan_apply(priv, to_port, to_vid, keep, untagged); + if (rc) + return rc; + + return sja1105_vlan_apply(priv, to_port, from_vid, false, false); +} + +static int sja1105_retagging_apply(struct sja1105_private *priv, int from_port, + u16 from_vid, int to_port, u16 to_vid, + bool keep, bool untagged) +{ + struct sja1105_retagging_entry *retagging; + struct sja1105_table *table; + int rc, match; + + rc = sja1105_setup_retagging_vid(priv, from_port, from_vid, to_port, + to_vid, keep, untagged); + if (rc) + return rc; + + table = &priv->static_config.tables[BLK_IDX_RETAGGING]; + + match = sja1105_find_retagging_entry(priv, from_port, from_vid, + to_port, to_vid); + if (match < 0) { + /* Can't delete a missing entry. */ + if (!keep) { + dev_err(priv->ds->dev, "can't delete a missing entry\n"); + return 0; + } + + /* No match => new entry */ + rc = sja1105_table_resize(table, table->entry_count + 1); + if (rc) { + dev_err(priv->ds->dev, "failed to resize retagging table: %d\n", rc); + return rc; + } + + match = table->entry_count - 1; + } + + /* Assign pointer after the resize (it may be new memory) */ + retagging = table->entries; + + if (keep) { + retagging[match].egr_port = BIT(to_port); + retagging[match].ing_port = BIT(from_port); + retagging[match].vlan_ing = from_vid; + retagging[match].vlan_egr = to_vid; + retagging[match].do_not_learn = false; + retagging[match].use_dest_ports = true; + retagging[match].destports = BIT(to_port); + + dev_err(priv->ds->dev, + "%s: entry %d egr_port 0x%llx ing_port 0x%llx vlan_ing %lld vlan_egr %lld do_not_learn %lld use_dest_ports %lld destports %lld\n", + __func__, match, retagging[match].egr_port, retagging[match].ing_port, retagging[match].vlan_ing, retagging[match].vlan_egr, + retagging[match].do_not_learn, retagging[match].use_dest_ports, retagging[match].destports); + return sja1105_dynamic_config_write(priv, BLK_IDX_RETAGGING, + match, &retagging[match], + true); + } + + /* To remove, the strategy is to overwrite the element with + * the last one, and then reduce the array size by 1 + */ + retagging[match] = retagging[table->entry_count - 1]; + + rc = sja1105_dynamic_config_write(priv, BLK_IDX_RETAGGING, + table->entry_count - 1, + &retagging[table->entry_count - 1], + false); + if (rc) + return rc; + + rc = sja1105_dynamic_config_write(priv, BLK_IDX_RETAGGING, match, + &retagging[match], true); + if (rc) + return rc; + + return sja1105_table_resize(table, table->entry_count - 1); +} + +static int sja1105_find_free_subvlan(struct sja1105_private *priv, int port) +{ + struct sja1105_port *sp = &priv->ports[port]; + int subvlan; + + for (subvlan = 1; subvlan < DSA_8021Q_N_SUBVLAN; subvlan++) + if (sp->subvlan_map[subvlan] == VLAN_N_VID) + return subvlan; + + return -1; +} + +static int sja1105_find_subvlan(struct sja1105_private *priv, int port, u16 vid) +{ + struct sja1105_port *sp = &priv->ports[port]; + int subvlan; + + for (subvlan = 1; subvlan < DSA_8021Q_N_SUBVLAN; subvlan++) + if (sp->subvlan_map[subvlan] == vid) + return subvlan; + + return -1; +} + +static int sja1105_subvlan_apply(struct sja1105_private *priv, int port, + u16 vid, bool pvid, bool keep) +{ + struct sja1105_port *sp = &priv->ports[port]; + int cpu = dsa_upstream_port(priv->ds, port); + int rc, subvlan; + u16 rx_vid; + + /* There are several situations when we don't want to add a subvlan */ + if (!priv->best_effort_vlan_filtering) + return 0; + if (vid_is_dsa_8021q(vid)) + return 0; + if (!dsa_is_user_port(priv->ds, port)) + return 0; + + if (keep) { + subvlan = sja1105_find_free_subvlan(priv, port); + if (subvlan < 0) { + dev_err(priv->ds->dev, "No more free subvlans\n"); + return -ENOSPC; + } + } else { + subvlan = sja1105_find_subvlan(priv, port, vid); + if (subvlan < 0) + /* A subvlan may not be found because either we ran out + * (and that's ok, after all, we only support up to 7 + * per port), or because the VID was added prior to + * best_effort_vlan_filtering getting toggled. So it's + * perfectly fine, don't do anything. + */ + return 0; + } + + if (pvid) + rx_vid = dsa_8021q_rx_vid(priv->ds, port); + else + rx_vid = dsa_8021q_rx_vid_subvlan(priv->ds, port, subvlan); + + rc = sja1105_retagging_apply(priv, port, vid, cpu, rx_vid, keep, false); + if (rc) + return rc; + + if (keep) + sp->subvlan_map[subvlan] = vid; + else + sp->subvlan_map[subvlan] = VLAN_N_VID; + + return 0; +} + static int sja1105_crosschip_bridge_join(struct dsa_switch *ds, int tree_index, int sw_index, int other_port, struct net_device *br) @@ -1918,8 +2135,13 @@ static int sja1105_vlan_prepare(struct dsa_switch *ds, int port, */ for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) { rc = dsa_8021q_vid_validate(ds, port, vid, vlan->flags); - if (rc < 0) - return rc; + /* Suppress the "wrong pvid" error. We can (and will) retag the + * pvid requested by the bridge to the dsa_8021q pvid. Untagged + * traffic is still tagged with the dsa_8021q pvid directly and + * does not require retagging. + */ + if (rc < 0 && rc != DSA_8021Q_WRONG_PVID) + return -EPERM; } return 0; @@ -2017,6 +2239,8 @@ static void sja1105_vlan_add(struct dsa_switch *ds, int port, int rc; for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) { + bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID; + rc = sja1105_vlan_apply(priv, port, vid, true, vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED); if (rc < 0) { @@ -2024,7 +2248,7 @@ static void sja1105_vlan_add(struct dsa_switch *ds, int port, vid, port, rc); return; } - if (vlan->flags & BRIDGE_VLAN_INFO_PVID) { + if (pvid) { rc = sja1105_pvid_apply(ds->priv, port, vid); if (rc < 0) { dev_err(ds->dev, "Failed to set pvid %d on port %d: %d\n", @@ -2032,6 +2256,9 @@ static void sja1105_vlan_add(struct dsa_switch *ds, int port, return; } } + rc = sja1105_subvlan_apply(priv, port, vid, pvid, true); + if (rc) + return; } } @@ -2043,6 +2270,8 @@ static int sja1105_vlan_del(struct dsa_switch *ds, int port, int rc; for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) { + bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID; + rc = sja1105_vlan_apply(priv, port, vid, false, vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED); if (rc < 0) { @@ -2050,6 +2279,9 @@ static int sja1105_vlan_del(struct dsa_switch *ds, int port, vid, port, rc); return rc; } + rc = sja1105_subvlan_apply(priv, port, vid, pvid, false); + if (rc) + return rc; } return 0; } @@ -2728,6 +2960,7 @@ static int sja1105_probe(struct spi_device *spi) struct sja1105_port *sp = &priv->ports[port]; struct dsa_port *dp = dsa_to_port(ds, port); struct net_device *slave; + int subvlan; if (!dsa_is_user_port(ds, port)) continue; @@ -2747,6 +2980,9 @@ static int sja1105_probe(struct spi_device *spi) goto out; } skb_queue_head_init(&sp->xmit_queue); + + for (subvlan = 0; subvlan < DSA_8021Q_N_SUBVLAN; subvlan++) + sp->subvlan_map[subvlan] = VLAN_N_VID; } return 0; diff --git a/include/linux/dsa/8021q.h b/include/linux/dsa/8021q.h index dfbd5b62f67a..40d85d3cdf15 100644 --- a/include/linux/dsa/8021q.h +++ b/include/linux/dsa/8021q.h @@ -20,6 +20,16 @@ struct dsa_8021q_crosschip_link { refcount_t refcount; }; +enum dsa_8021q_vid_error { + DSA_8021Q_VID_OK = 0, + DSA_8021Q_WRONG_PVID = -1, + DSA_8021Q_TX_VLAN_WRONG_FLAGS = -2, + DSA_8021Q_TX_VLAN_WRONG_PORT = -3, + DSA_8021Q_RX_VLAN_WRONG_FLAGS = -4, +}; + +#define DSA_8021Q_N_SUBVLAN 8 + #if IS_ENABLED(CONFIG_NET_DSA_TAG_8021Q) int dsa_port_setup_8021q_tagging(struct dsa_switch *ds, int index, @@ -48,10 +58,16 @@ u16 dsa_8021q_tx_vid(struct dsa_switch *ds, int port); u16 dsa_8021q_rx_vid(struct dsa_switch *ds, int port); +u16 dsa_8021q_rx_vid_subvlan(struct dsa_switch *ds, int port, u16 subvlan); + int dsa_8021q_rx_switch_id(u16 vid); int dsa_8021q_rx_source_port(u16 vid); +u16 dsa_8021q_rx_subvlan(u16 vid); + +bool vid_is_dsa_8021q(u16 vid); + #else int dsa_port_setup_8021q_tagging(struct dsa_switch *ds, int index, @@ -104,6 +120,11 @@ u16 dsa_8021q_rx_vid(struct dsa_switch *ds, int port) return 0; } +u16 dsa_8021q_rx_vid_subvlan(struct dsa_switch *ds, int port, u16 subvlan) +{ + return 0; +} + int dsa_8021q_rx_switch_id(u16 vid) { return 0; @@ -114,6 +135,16 @@ int dsa_8021q_rx_source_port(u16 vid) return 0; } +u16 dsa_8021q_rx_subvlan(u16 vid) +{ + return 0; +} + +bool vid_is_dsa_8021q(u16 vid) +{ + return false; +} + #endif /* IS_ENABLED(CONFIG_NET_DSA_TAG_8021Q) */ #endif /* _NET_DSA_8021Q_H */ diff --git a/include/linux/dsa/sja1105.h b/include/linux/dsa/sja1105.h index a609fdbe1355..ef04625087ef 100644 --- a/include/linux/dsa/sja1105.h +++ b/include/linux/dsa/sja1105.h @@ -9,6 +9,7 @@ #include #include +#include #include #define ETH_P_SJA1105 ETH_P_DSA_8021Q @@ -53,6 +54,7 @@ struct sja1105_skb_cb { ((struct sja1105_skb_cb *)DSA_SKB_CB_PRIV(skb)) struct sja1105_port { + u16 subvlan_map[DSA_8021Q_N_SUBVLAN]; struct kthread_worker *xmit_worker; struct kthread_work xmit_work; struct sk_buff_head xmit_queue; diff --git a/net/dsa/tag_8021q.c b/net/dsa/tag_8021q.c index 3958f426d60e..48d4cb42763f 100644 --- a/net/dsa/tag_8021q.c +++ b/net/dsa/tag_8021q.c @@ -17,7 +17,7 @@ * * | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | * +-----------+-----+-----------------+-----------+-----------------------+ - * | DIR | RSV | SWITCH_ID | RSV | PORT | + * | DIR | SVL | SWITCH_ID | SUBVLAN | PORT | * +-----------+-----+-----------------+-----------+-----------------------+ * * DIR - VID[11:10]: @@ -27,17 +27,24 @@ * These values make the special VIDs of 0, 1 and 4095 to be left * unused by this coding scheme. * - * RSV - VID[9]: - * To be used for further expansion of SWITCH_ID or for other purposes. - * Must be transmitted as zero and ignored on receive. + * SVL/SUBVLAN - { VID[9], VID[5:4] }: + * Sub-VLAN encoding. Valid only when DIR indicates an RX VLAN. + * * 0 (0b000): Field does not encode a sub-VLAN, either because + * received traffic is untagged, PVID-tagged or because a second + * VLAN tag is present after this tag and not inside of it. + * * 1 (0b001): Received traffic is tagged with a VID value private + * to the host. This field encodes the index in the host's lookup + * table through which the value of the ingress VLAN ID can be + * recovered. + * * 2 (0b010): Field encodes a sub-VLAN. + * ... + * * 7 (0b111): Field encodes a sub-VLAN. + * When DIR indicates a TX VLAN, SUBVLAN must be transmitted as zero + * (by the host) and ignored on receive (by the switch). * * SWITCH_ID - VID[8:6]: * Index of switch within DSA tree. Must be between 0 and 7. * - * RSV - VID[5:4]: - * To be used for further expansion of PORT or for other purposes. - * Must be transmitted as zero and ignored on receive. - * * PORT - VID[3:0]: * Index of switch port. Must be between 0 and 15. */ @@ -54,6 +61,18 @@ #define DSA_8021Q_SWITCH_ID(x) (((x) << DSA_8021Q_SWITCH_ID_SHIFT) & \ DSA_8021Q_SWITCH_ID_MASK) +#define DSA_8021Q_SUBVLAN_HI_SHIFT 9 +#define DSA_8021Q_SUBVLAN_HI_MASK GENMASK(9, 9) +#define DSA_8021Q_SUBVLAN_LO_SHIFT 4 +#define DSA_8021Q_SUBVLAN_LO_MASK GENMASK(4, 3) +#define DSA_8021Q_SUBVLAN_HI(x) (((x) & GENMASK(2, 2)) >> 2) +#define DSA_8021Q_SUBVLAN_LO(x) ((x) & GENMASK(1, 0)) +#define DSA_8021Q_SUBVLAN(x) \ + (((DSA_8021Q_SUBVLAN_LO(x) << DSA_8021Q_SUBVLAN_LO_SHIFT) & \ + DSA_8021Q_SUBVLAN_LO_MASK) | \ + ((DSA_8021Q_SUBVLAN_HI(x) << DSA_8021Q_SUBVLAN_HI_SHIFT) & \ + DSA_8021Q_SUBVLAN_HI_MASK)) + #define DSA_8021Q_PORT_SHIFT 0 #define DSA_8021Q_PORT_MASK GENMASK(3, 0) #define DSA_8021Q_PORT(x) (((x) << DSA_8021Q_PORT_SHIFT) & \ @@ -79,6 +98,13 @@ u16 dsa_8021q_rx_vid(struct dsa_switch *ds, int port) } EXPORT_SYMBOL_GPL(dsa_8021q_rx_vid); +u16 dsa_8021q_rx_vid_subvlan(struct dsa_switch *ds, int port, u16 subvlan) +{ + return DSA_8021Q_DIR_RX | DSA_8021Q_SWITCH_ID(ds->index) | + DSA_8021Q_PORT(port) | DSA_8021Q_SUBVLAN(subvlan); +} +EXPORT_SYMBOL_GPL(dsa_8021q_rx_vid_subvlan); + /* Returns the decoded switch ID from the RX VID. */ int dsa_8021q_rx_switch_id(u16 vid) { @@ -93,6 +119,27 @@ int dsa_8021q_rx_source_port(u16 vid) } EXPORT_SYMBOL_GPL(dsa_8021q_rx_source_port); +/* Returns the decoded subvlan from the RX VID. */ +u16 dsa_8021q_rx_subvlan(u16 vid) +{ + u16 svl_hi, svl_lo; + + svl_hi = (vid & DSA_8021Q_SUBVLAN_HI_MASK) >> + DSA_8021Q_SUBVLAN_HI_SHIFT; + svl_lo = (vid & DSA_8021Q_SUBVLAN_LO_MASK) >> + DSA_8021Q_SUBVLAN_LO_SHIFT; + + return (svl_hi << 2) | svl_lo; +} +EXPORT_SYMBOL_GPL(dsa_8021q_rx_subvlan); + +bool vid_is_dsa_8021q(u16 vid) +{ + return ((vid & DSA_8021Q_DIR_MASK) == DSA_8021Q_DIR_RX || + (vid & DSA_8021Q_DIR_MASK) == DSA_8021Q_DIR_TX); +} +EXPORT_SYMBOL_GPL(vid_is_dsa_8021q); + static int dsa_8021q_restore_pvid(struct dsa_switch *ds, int port) { struct bridge_vlan_info vinfo; @@ -289,7 +336,8 @@ int dsa_port_setup_8021q_tagging(struct dsa_switch *ds, int port, bool enabled) } EXPORT_SYMBOL_GPL(dsa_port_setup_8021q_tagging); -int dsa_8021q_vid_validate(struct dsa_switch *ds, int port, u16 vid, u16 flags) +enum dsa_8021q_vid_error dsa_8021q_vid_validate(struct dsa_switch *ds, int port, + u16 vid, u16 flags) { int upstream = dsa_upstream_port(ds, port); int rx_vid_of = ds->num_ports; @@ -299,7 +347,7 @@ int dsa_8021q_vid_validate(struct dsa_switch *ds, int port, u16 vid, u16 flags) /* @vid wants to be a pvid of @port, but is not equal to its rx_vid */ if ((flags & BRIDGE_VLAN_INFO_PVID) && vid != dsa_8021q_rx_vid(ds, port)) - return -EPERM; + return DSA_8021Q_WRONG_PVID; for (other_port = 0; other_port < ds->num_ports; other_port++) { if (!dsa_is_user_port(ds, other_port)) @@ -318,15 +366,15 @@ int dsa_8021q_vid_validate(struct dsa_switch *ds, int port, u16 vid, u16 flags) if (tx_vid_of != ds->num_ports) { if (tx_vid_of == port) { if (flags != BRIDGE_VLAN_INFO_UNTAGGED) - return -EPERM; + return DSA_8021Q_TX_VLAN_WRONG_FLAGS; /* Fall through on proper flags */ } else if (port == upstream) { if (flags != 0) - return -EPERM; + return DSA_8021Q_TX_VLAN_WRONG_FLAGS; /* Fall through on proper flags */ } else { /* Trying to configure on other port */ - return -EPERM; + return DSA_8021Q_TX_VLAN_WRONG_PORT; } } @@ -335,17 +383,17 @@ int dsa_8021q_vid_validate(struct dsa_switch *ds, int port, u16 vid, u16 flags) if (rx_vid_of == port) { if (flags != (BRIDGE_VLAN_INFO_UNTAGGED | BRIDGE_VLAN_INFO_PVID)) - return -EPERM; + return DSA_8021Q_RX_VLAN_WRONG_FLAGS; /* Fall through on proper flags */ } else if (port == upstream) { if (flags != 0) - return -EPERM; + return DSA_8021Q_RX_VLAN_WRONG_FLAGS; /* Fall through on proper flags */ } else if (flags != BRIDGE_VLAN_INFO_UNTAGGED) { /* Trying to configure on other port, but with * invalid flags. */ - return -EPERM; + return DSA_8021Q_RX_VLAN_WRONG_FLAGS; } } diff --git a/net/dsa/tag_sja1105.c b/net/dsa/tag_sja1105.c index 72d76743c272..b47c38cd5fcc 100644 --- a/net/dsa/tag_sja1105.c +++ b/net/dsa/tag_sja1105.c @@ -113,7 +113,7 @@ static struct sk_buff *sja1105_xmit(struct sk_buff *skb, return sja1105_defer_xmit(dp->priv, skb); if (dsa_port_is_vlan_filtering(dp)) - tpid = ETH_P_8021Q; + tpid = ETH_P_8021AD; else tpid = ETH_P_SJA1105; @@ -242,6 +242,20 @@ static struct sk_buff return skb; } +static void sja1105_decode_subvlan(struct sk_buff *skb, u16 subvlan) +{ + struct dsa_port *dp = dsa_slave_to_port(skb->dev); + struct sja1105_port *sp = dp->priv; + u16 vid = sp->subvlan_map[subvlan]; + u16 vlan_tci; + + if (vid == VLAN_N_VID) + return; + + vlan_tci = (skb->priority << VLAN_PRIO_SHIFT) | vid; + __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan_tci); +} + static struct sk_buff *sja1105_rcv(struct sk_buff *skb, struct net_device *netdev, struct packet_type *pt) @@ -251,6 +265,7 @@ static struct sk_buff *sja1105_rcv(struct sk_buff *skb, struct ethhdr *hdr; u16 tpid, vid, tci; bool is_link_local; + u16 subvlan = 0; bool is_tagged; bool is_meta; @@ -274,6 +289,7 @@ static struct sk_buff *sja1105_rcv(struct sk_buff *skb, source_port = dsa_8021q_rx_source_port(vid); switch_id = dsa_8021q_rx_switch_id(vid); skb->priority = (tci & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT; + subvlan = dsa_8021q_rx_subvlan(vid); } else if (is_link_local) { /* Management traffic path. Switch embeds the switch ID and * port ID into bytes of the destination MAC, courtesy of @@ -298,6 +314,9 @@ static struct sk_buff *sja1105_rcv(struct sk_buff *skb, return NULL; } + if (subvlan) + sja1105_decode_subvlan(skb, subvlan); + return sja1105_rcv_meta_state_machine(skb, &meta, is_link_local, is_meta); } From patchwork Mon May 4 12:43:25 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1282585 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=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; 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.a=rsa-sha256 header.s=20161025 header.b=Q8NsrY1x; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 49G2cH36r9z9sSc for ; Mon, 4 May 2020 22:44:31 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728908AbgEDMoa (ORCPT ); Mon, 4 May 2020 08:44:30 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35618 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1728475AbgEDMoY (ORCPT ); Mon, 4 May 2020 08:44:24 -0400 Received: from mail-wm1-x342.google.com (mail-wm1-x342.google.com [IPv6:2a00:1450:4864:20::342]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 33AB1C061A0E for ; Mon, 4 May 2020 05:44:24 -0700 (PDT) Received: by mail-wm1-x342.google.com with SMTP id k12so8231787wmj.3 for ; Mon, 04 May 2020 05:44:24 -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=/VFrQTqtmw8M3JqCJ35gBTW/wMAKmrJTc9j9D0crIWw=; b=Q8NsrY1xrrpfulD18ddLN24jVD8dCg8/t0rOV+s6zY1zG0x53P+UQmWm/PE/ecvWhv 0SpAqocl3w7GolFsj+P21qZPNbRnsddBARwaQZODMYFuQVS4MH3BB8fgYjfU8DIOgISR a2HWxEjaFdJsctA6GTgVZpG3KScwZOH2QlhabvIwvnCKK8huMWaTdk6D0j6+ilK+3+7+ kn8ybMfVDWHPnJQAqlNrFytFfpLNQjTsG2s8c3M/U5SBztimxKNGrW2707pn9fvMIw6M eHPoGbaQY2L7m5S0IKWoJfGqweCJAocOIPI+SpYNQYCrZyMNiIsfJJzigWIkBKJ5wQCl VlYg== 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=/VFrQTqtmw8M3JqCJ35gBTW/wMAKmrJTc9j9D0crIWw=; b=MzMS718Sq8iDUbOeJ6/CPWBEU5YIiHsYbEFuUNlwlJHlAz6mbWZueGivFQ6iR4HB4p GMWdff9V8FRuTiDr+uE5aAWgB5vPuzqzJuvvuBGa9VBrYSmyMm6Mdjuvdh2lRjx6NAVm dERId89DtYW2wU0EjhsmPfgOw59cBsyLl3uyEzNq2OHe+OtVPvSZBlNwtB3b5mwMu3Cq pRKLwIMZ+le6c2e/9hVlMDKZbbXvyelIywsSN25nwBE/51eaOunR604HYoXu9Rl1rvhT 6sS8zaegK8ya5ofqOUvkHa+PUCS85jV63EVeIqxMva0lvXi5o58oohiEmaIMs0wmQQBb e64g== X-Gm-Message-State: AGi0PubwXXXIvMBoEHysH+T65PeCmLZPKles/kazyeHy9tncvmoXo2Jd WR5GBg1w0xSAuLrmpl7OhZI= X-Google-Smtp-Source: APiQypIXEWUe3xMzWEKDgvz7Hr4DbHJxlfpwZyJ56aIjOwl6kfXIcg6wQjBCTfMZpakW2v0FJ2ya/g== X-Received: by 2002:a1c:7715:: with SMTP id t21mr13727190wmi.182.1588596262875; Mon, 04 May 2020 05:44:22 -0700 (PDT) Received: from localhost.localdomain ([86.121.118.29]) by smtp.gmail.com with ESMTPSA id 32sm17343670wrg.19.2020.05.04.05.44.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 04 May 2020 05:44:22 -0700 (PDT) From: Vladimir Oltean To: andrew@lunn.ch, f.fainelli@gmail.com, vivien.didelot@gmail.com Cc: davem@davemloft.net, jiri@resnulli.us, idosch@idosch.org, kuba@kernel.org, netdev@vger.kernel.org, nikolay@cumulusnetworks.com, roopa@cumulusnetworks.com, georg.waibel@sensor-technik.de, o.rempel@pengutronix.de, christian.herber@nxp.com Subject: [RFC 6/6] docs: net: dsa: sja1105: document the best_effort_vlan_filtering option Date: Mon, 4 May 2020 15:43:25 +0300 Message-Id: <20200504124325.26758-7-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200504124325.26758-1-olteanv@gmail.com> References: <20200504124325.26758-1-olteanv@gmail.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Vladimir Oltean Signed-off-by: Vladimir Oltean --- .../networking/devlink-params-sja1105.txt | 24 ++++++++++ Documentation/networking/dsa/sja1105.rst | 46 +++++++++++++++++++ 2 files changed, 70 insertions(+) diff --git a/Documentation/networking/devlink-params-sja1105.txt b/Documentation/networking/devlink-params-sja1105.txt index 5096a4cf923c..576dcc6e2d96 100644 --- a/Documentation/networking/devlink-params-sja1105.txt +++ b/Documentation/networking/devlink-params-sja1105.txt @@ -7,3 +7,27 @@ hostprio [DEVICE, DRIVER-SPECIFIC] your PTP frames. Configuration mode: runtime Type: u8. 0-7 valid. + +best_effort_vlan_filtering + [DEVICE, DRIVER-SPECIFIC] + Allow plain ETH_P_8021Q headers to be used as DSA tags. + Benefits: + - Can terminate untagged traffic over switch net + devices even when enslaved to a bridge with + vlan_filtering=1. + - Can terminate VLAN-tagged traffic over switch net + devices even when enslaved to a bridge with + vlan_filtering=1, with some constraints (no more than + 7 VLANs per user port). + - Can do QoS based on VLAN PCP and VLAN membership + admission control for autonomously forwarded frames + (regardless of whether they can be terminated on the + CPU or not). + Drawbacks: + - User cannot use VLANs in range 1024-3071. If the + switch receives frames with such VIDs, it will + misinterpret them as DSA tags. + - Switch uses Shared VLAN Learning (FDB lookup uses + only DMAC as key). + Configuration mode: runtime + Type: bool. diff --git a/Documentation/networking/dsa/sja1105.rst b/Documentation/networking/dsa/sja1105.rst index 4a8639cba1f3..d963ff2ac1c9 100644 --- a/Documentation/networking/dsa/sja1105.rst +++ b/Documentation/networking/dsa/sja1105.rst @@ -77,6 +77,52 @@ change. The TPID is restored when ``vlan_filtering`` is requested by the user through the bridge layer, and general IP termination becomes no longer possible through the switch netdevices in this mode. +There exists a third configuration option, via ``best_effort_vlan_filtering``. +This permits termination of some traffic on switch net devices, at the expense +of losing some VLAN filtering abilities: reduced range of usable VIDs and +shared VLAN learning. +The frames which can be terminated on the CPU in this mode are: +- All untagged frames +- VLAN-tagged frames, up to 7 different VLANs per user port +This operating mode is slightly insane to be collated with the default +``vlan_filtering``, so it is an opt-in that needs to be enabled using a devlink +parameter. To enable it:: + + ip link set dev br0 type bridge vlan_filtering 1 + [ 61.204770] sja1105 spi0.1: Reset switch and programmed static config. Reason: VLAN filtering + [ 61.239944] sja1105 spi0.1: Disabled switch tagging + devlink dev param set spi/spi0.1 name best_effort_vlan_filtering value true cmode runtime + [ 64.682927] sja1105 spi0.1: Reset switch and programmed static config. Reason: VLAN filtering + [ 64.711925] sja1105 spi0.1: Enabled switch tagging + bridge vlan add dev swp2 vid 1025 untagged pvid + RTNETLINK answers: Operation not permitted + bridge vlan add dev swp2 vid 100 + bridge vlan add dev swp2 vid 101 untagged + bridge vlan + port vlan ids + swp5 1 PVID Egress Untagged + + swp2 1 PVID Egress Untagged + 100 + 101 Egress Untagged + + swp3 1 PVID Egress Untagged + + swp4 1 PVID Egress Untagged + + br0 1 PVID Egress Untagged + bridge vlan add dev swp2 vid 102 + bridge vlan add dev swp2 vid 103 + bridge vlan add dev swp2 vid 104 + bridge vlan add dev swp2 vid 105 + bridge vlan add dev swp2 vid 106 + bridge vlan add dev swp2 vid 107 + [ 3885.216832] sja1105 spi0.1: No more free subvlans + +The "No more free subvlans" warning message means that once the capacity is +exceeded, frames tagged with newly added VLANs (in this case 107) are not able +to be terminated on the CPU. They are still accepted and forwarded +autonomously. The switches have two programmable filters for link-local destination MACs. These are used to trap BPDUs and PTP traffic to the master netdevice, and are