ipq806x: nss patches for k6.x

SqTER-PL <r.napierala@asta-net.pl>
This commit is contained in:
Lucas Asvio
2025-02-22 13:36:18 +01:00
parent 3e772c843c
commit 290156f351
60 changed files with 9202 additions and 0 deletions

View File

@@ -0,0 +1,283 @@
--- a/arch/arm/boot/dts/qcom/qcom-ipq8064-v2.0.dtsi
+++ b/arch/arm/boot/dts/qcom/qcom-ipq8064-v2.0.dtsi
@@ -22,6 +22,15 @@
reg = <0x41200000 0x300000>;
no-map;
};
+
+ ramoops@42100000 {
+ compatible = "ramoops";
+ reg = <0x42100000 0x40000>;
+ record-size = <0x4000>;
+ console-size = <0x4000>;
+ ftrace-size = <0x4000>;
+ pmsg-size = <0x4000>;
+ };
};
};
--- a/arch/arm/boot/dts/qcom/qcom-ipq8064.dtsi
+++ b/arch/arm/boot/dts/qcom/qcom-ipq8064.dtsi
@@ -670,6 +670,20 @@
};
};
+ nss-common {
+ compatible = "qcom,nss-common";
+ reg = <0x03000000 0x00001000>;
+ reg-names = "nss_fpb_base";
+ clocks = <&gcc NSS_CORE_CLK>, <&gcc NSSTCM_CLK>,
+ <&rpmcc RPM_NSS_FABRIC_0_CLK>, <&rpmcc RPM_NSS_FABRIC_1_CLK>;
+ clock-names = "nss_core_clk", "nss_tcm_clk",
+ "nss-fab0-clk", "nss-fab1-clk";
+ nss_core-supply = <&smb208_s1b>;
+ nss_core_vdd_nominal = <1100000>;
+ nss_core_vdd_high = <1150000>;
+ nss_core_threshold_freq = <733000000>;
+ };
+
sfpb_mutex: hwlock@1200600 {
compatible = "qcom,sfpb-mutex";
reg = <0x01200600 0x100>;
@@ -856,6 +870,132 @@
status = "disabled";
};
+ nss0: nss@40000000 {
+ compatible = "qcom,nss";
+ qcom,low-frequency = <733000000>; /* orig value 110000000 */
+ qcom,mid-frequency = <733000000>; /* orig value 550000000 */
+ qcom,max-frequency = <733000000>;
+
+ interrupts = <GIC_SPI 213 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 232 IRQ_TYPE_LEVEL_HIGH>;
+ reg = <0x36000000 0x1000 0x39000000 0x10000>;
+ reg-names = "nphys", "vphys";
+ clocks = <&gcc NSS_CORE_CLK>, <&gcc NSSTCM_CLK_SRC>,
+ <&gcc NSSTCM_CLK>, <&rpmcc RPM_NSS_FABRIC_0_CLK>,
+ <&rpmcc RPM_NSS_FABRIC_1_CLK>;
+ clock-names = "nss-core-clk", "nss-tcm-src",
+ "nss-tcm-clk", "nss-fab0-clk",
+ "nss-fab1-clk";
+ resets = <&gcc UBI32_CORE1_CLKRST_CLAMP_RESET>,
+ <&gcc UBI32_CORE1_CLAMP_RESET>,
+ <&gcc UBI32_CORE1_AHB_RESET>,
+ <&gcc UBI32_CORE1_AXI_RESET>;
+ reset-names = "clkrst-clamp", "clamp", "ahb", "axi";
+
+ qcom,id = <0>;
+ qcom,num-irq = <2>;
+ qcom,num-queue = <2>;
+ qcom,load-addr = <0x40000000>;
+ qcom,turbo-frequency;
+
+ qcom,bridge-enabled;
+ qcom,gre-enabled;
+ qcom,gre-redir-enabled;
+ qcom,gre_tunnel_enabled;
+ qcom,ipv4-enabled;
+ qcom,ipv4-reasm-enabled;
+ qcom,ipv6-enabled;
+ qcom,ipv6-reasm-enabled;
+ qcom,l2tpv2-enabled;
+ qcom,map-t-enabled;
+ qcom,pppoe-enabled;
+ qcom,pptp-enabled;
+ qcom,portid-enabled;
+ qcom,shaping-enabled;
+ qcom,tun6rd-enabled;
+ qcom,tunipip6-enabled;
+ qcom,vlan-enabled;
+ qcom,wlan-dataplane-offload-enabled;
+ qcom,wlanredirect-enabled;
+ qcom,pxvlan-enabled;
+ qcom,vxlan-enabled;
+ qcom,match-enabled;
+ qcom,mirror-enabled;
+ qcom,rmnet-enabled;
+ qcom,clmap-enabled;
+ };
+
+ nss1: nss@40800000 {
+ compatible = "qcom,nss";
+ qcom,low-frequency = <733000000>; /* orig value 110000000 */
+ qcom,mid-frequency = <733000000>; /* orig value 550000000 */
+ qcom,max-frequency = <733000000>;
+
+ interrupts = <GIC_SPI 214 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 233 IRQ_TYPE_LEVEL_HIGH>;
+ reg = <0x36400000 0x1000 0x39010000 0x10000>;
+ reg-names = "nphys", "vphys";
+ resets = <&gcc UBI32_CORE2_CLKRST_CLAMP_RESET>,
+ <&gcc UBI32_CORE2_CLAMP_RESET>,
+ <&gcc UBI32_CORE2_AHB_RESET>,
+ <&gcc UBI32_CORE2_AXI_RESET>;
+ reset-names = "clkrst-clamp", "clamp", "ahb", "axi";
+
+ qcom,id = <1>;
+ qcom,num-irq = <2>;
+ qcom,load-addr = <0x40800000>;
+ qcom,num-queue = <2>;
+ qcom,turbo-frequency;
+
+ qcom,capwap-enabled;
+ qcom,crypto-enabled;
+ qcom,dtls-enabled;
+ qcom,ipsec-enabled;
+ };
+
+ crypto1: crypto@38000000 {
+ compatible = "qcom,nss-crypto";
+ reg = <0x38000000 0x20000>, <0x38004000 0x22000>;
+ reg-names = "crypto_pbase", "bam_base";
+ clocks = <&gcc CE5_CORE_CLK>, <&gcc CE5_A_CLK>, <&gcc CE5_H_CLK>;
+ clock-names = "ce5_core", "ce5_aclk", "ce5_hclk";
+ resets = <&gcc CRYPTO_ENG1_RESET>, <&gcc CRYPTO_AHB_RESET>;
+ reset-names = "rst_eng", "rst_ahb";
+ qcom,id = <0>;
+ qcom,ee = <0>;
+ };
+
+ crypto2: crypto@38400000 {
+ compatible = "qcom,nss-crypto";
+ reg = <0x38400000 0x20000>, <0x38404000 0x22000>;
+ reg-names = "crypto_pbase", "bam_base";
+ resets = <&gcc CRYPTO_ENG2_RESET>;
+ reset-names = "rst_eng";
+ qcom,id = <1>;
+ qcom,ee = <0>;
+ };
+
+ crypto3: crypto@38800000 {
+ compatible = "qcom,nss-crypto";
+ reg = <0x38800000 0x20000>, <0x38804000 0x22000>;
+ reg-names = "crypto_pbase", "bam_base";
+ resets = <&gcc CRYPTO_ENG3_RESET>;
+ reset-names = "rst_eng";
+ qcom,id = <2>;
+ qcom,ee = <0>;
+ };
+
+ crypto4: crypto@38c00000 {
+ compatible = "qcom,nss-crypto";
+ reg = <0x38c00000 0x20000>, <0x38c04000 0x22000>;
+ reg-names = "crypto_pbase", "bam_base";
+ resets = <&gcc CRYPTO_ENG4_RESET>;
+ reset-names = "rst_eng";
+ qcom,id = <3>;
+ qcom,ee = <0>;
+ };
+
+
sdcc3bam: dma-controller@12182000 {
compatible = "qcom,bam-v1.3.0";
reg = <0x12182000 0x8000>;
@@ -1462,6 +1602,12 @@
status = "disabled";
};
+ nss-gmac-common {
+ compatible = "qcom,nss-gmac-common";
+ reg = <0x03000000 0x0000FFFF 0x1bb00000 0x0000FFFF 0x00900000 0x00004000>;
+ reg-names = "nss_reg_base", "qsgmii_reg_base", "clk_ctl_base";
+ };
+
gmac0: ethernet@37000000 {
device_type = "network";
compatible = "qcom,ipq806x-gmac", "snps,dwmac";
@@ -1559,3 +1705,27 @@
};
};
};
+
+ &gmac1 {
+ compatible = "qcom,nss-gmac";
+ qcom,id = <0>;
+ qcom,pcs-chanid = <0>;
+ qcom,phy_mii_type = <0>;
+ qcom,emulation = <0>;
+ qcom,forced-speed = <1000>;
+ qcom,forced-duplex = <1>;
+ qcom,socver = <0>;
+ mdiobus = <&mdio0>;
+ };
+
+ &gmac2 {
+ compatible = "qcom,nss-gmac";
+ qcom,id = <1>;
+ qcom,pcs-chanid = <1>;
+ qcom,phy_mii_type = <1>;
+ qcom,emulation = <0>;
+ qcom,forced-speed = <1000>;
+ qcom,forced-duplex = <1>;
+ qcom,socver = <0>;
+ mdiobus = <&mdio0>;
+ };
--- a/arch/arm/boot/dts/qcom/qcom-ipq8065-nighthawk.dtsi
+++ b/arch/arm/boot/dts/qcom/qcom-ipq8065-nighthawk.dtsi
@@ -360,13 +360,23 @@
&gmac1 {
status = "okay";
+ compatible = "qcom,nss-gmac";
+ reg = <0x37200000 0x200000>;
+ interrupts = <GIC_SPI 223 IRQ_TYPE_LEVEL_HIGH>;
phy-mode = "rgmii";
qcom,id = <1>;
+ qcom,pcs-chanid = <0>;
qcom,phy_mdio_addr = <4>;
qcom,poll_required = <0>;
qcom,rgmii_delay = <1>;
+ qcom,phy-mdio-addr = <4>;
+ qcom,poll-required = <0>;
+ qcom,rgmii-delay = <1>;
qcom,phy_mii_type = <0>;
qcom,emulation = <0>;
+ qcom,forced-speed = <1000>;
+ qcom,forced-duplex = <1>;
+ qcom,socver = <0>;
qcom,irq = <255>;
mdiobus = <&mdio0>;
@@ -385,13 +395,23 @@
&gmac2 {
status = "okay";
+ compatible = "qcom,nss-gmac";
+ reg = <0x37400000 0x200000>;
+ interrupts = <GIC_SPI 226 IRQ_TYPE_LEVEL_HIGH>;
phy-mode = "sgmii";
qcom,id = <2>;
+ qcom,pcs-chanid = <1>;
qcom,phy_mdio_addr = <0>; /* none */
qcom,poll_required = <0>; /* no polling */
qcom,rgmii_delay = <0>;
+ qcom,phy-mdio-addr = <0>;
+ qcom,poll-required = <0>;
+ qcom,rgmii-delay = <0>;
qcom,phy_mii_type = <1>;
qcom,emulation = <0>;
+ qcom,forced-speed = <1000>;
+ qcom,forced-duplex = <1>;
+ qcom,socver = <0>;
qcom,irq = <258>;
mdiobus = <&mdio0>;
--- a/arch/arm/boot/dts/qcom/qcom-ipq8065.dtsi
+++ b/arch/arm/boot/dts/qcom/qcom-ipq8065.dtsi
@@ -95,3 +95,15 @@
opp-level = <2>;
};
};
+
+ &nss0 {
+ qcom,low-frequency = <110000000>;
+ qcom,mid-frequency = <600000000>;
+ qcom,max-frequency = <800000000>;
+ };
+
+ &nss1 {
+ qcom,low-frequency = <110000000>;
+ qcom,mid-frequency = <600000000>;
+ qcom,max-frequency = <800000000>;
+ };

View File

@@ -0,0 +1,643 @@
--- /dev/null
+++ b/include/net/netfilter/nf_conntrack_dscpremark_ext.h
@@ -0,0 +1,98 @@
+/*
+ **************************************************************************
+ * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved.
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all copies.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ **************************************************************************
+ */
+
+/* DSCP remark conntrack extension APIs. */
+
+#ifndef _NF_CONNTRACK_DSCPREMARK_H
+#define _NF_CONNTRACK_DSCPREMARK_H
+#include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_extend.h>
+
+/* Rule flags */
+#define NF_CT_DSCPREMARK_EXT_DSCP_RULE_VALID 0x1
+
+/* Rule validity */
+#define NF_CT_DSCPREMARK_EXT_RULE_VALID 0x1
+#define NF_CT_DSCPREMARK_EXT_RULE_NOT_VALID 0x0
+
+/* Which QoS features are set flags */
+#define NF_CT_DSCPREMARK_EXT_PRIO 0x1
+#define NF_CT_DSCPREMARK_EXT_DSCP 0x2
+#define NF_CT_DSCPREMARK_EXT_IGS_QOS 0x4
+#define NF_CT_DSCPREMARK_EXT_MARK 0x8
+#define NF_CT_DSCPREMARK_EXT_SAWF 0x10
+
+/*
+ * DSCP remark conntrack extension structure.
+ */
+struct nf_ct_dscpremark_ext {
+ __u32 flow_priority; /* Original direction packet priority */
+ __u32 reply_priority; /* Reply direction packet priority */
+ __u32 flow_mark; /* Original direction packet mark */
+ __u32 reply_mark; /* Reply direction packet mark */
+ __u32 flow_sawf_meta; /* Original direction SAWF meta info */
+ __u32 return_sawf_meta; /* Reply direction SAWF meta info */
+ __u16 igs_flow_qos_tag; /* Original direction ingress packet priority */
+ __u16 igs_reply_qos_tag; /* Reply direction ingress packet priority */
+ __u8 flow_dscp; /* IP DSCP value for original direction */
+ __u8 reply_dscp; /* IP DSCP value for reply direction */
+ __u16 rule_flags; /* Rule Validity flags */
+ __u16 flow_set_flags; /* Original direction set flags */
+ __u16 return_set_flags; /* Reply direction set flags */
+};
+
+/*
+ * nf_ct_dscpremark_ext_find()
+ * Finds the extension data of the conntrack entry if it exists.
+ */
+static inline struct nf_ct_dscpremark_ext *
+nf_ct_dscpremark_ext_find(const struct nf_conn *ct)
+{
+#ifdef CONFIG_NF_CONNTRACK_DSCPREMARK_EXT
+ return nf_ct_ext_find(ct, NF_CT_EXT_DSCPREMARK);
+#else
+ return NULL;
+#endif
+}
+
+/*
+ * nf_ct_dscpremark_ext_add()
+ * Adds the extension data to the conntrack entry.
+ */
+static inline
+struct nf_ct_dscpremark_ext *nf_ct_dscpremark_ext_add(struct nf_conn *ct,
+ gfp_t gfp)
+{
+#ifdef CONFIG_NF_CONNTRACK_DSCPREMARK_EXT
+ struct nf_ct_dscpremark_ext *ncde;
+
+ ncde = nf_ct_ext_add(ct, NF_CT_EXT_DSCPREMARK, gfp);
+ if (!ncde)
+ return NULL;
+
+ return ncde;
+#else
+ return NULL;
+#endif
+};
+
+#ifdef CONFIG_NF_CONNTRACK_DSCPREMARK_EXT
+extern int nf_conntrack_dscpremark_ext_set_dscp_rule_valid(struct nf_conn *ct);
+extern int nf_conntrack_dscpremark_ext_get_dscp_rule_validity(struct nf_conn *ct);
+#endif /* CONFIG_NF_CONNTRACK_DSCPREMARK_EXT */
+
+#endif /* _NF_CONNTRACK_DSCPREMARK_H */
--- /dev/null
+++ b/net/netfilter/nf_conntrack_dscpremark_ext.c
@@ -0,0 +1,62 @@
+/*
+ **************************************************************************
+ * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved.
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all copies.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ **************************************************************************
+ */
+
+/* DSCP remark handling conntrack extension registration. */
+
+#include <linux/netfilter.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/moduleparam.h>
+#include <linux/export.h>
+
+#include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_extend.h>
+#include <net/netfilter/nf_conntrack_dscpremark_ext.h>
+
+/* nf_conntrack_dscpremark_ext_set_dscp_rule_valid()
+ * Set DSCP rule validity flag in the extension
+ */
+int nf_conntrack_dscpremark_ext_set_dscp_rule_valid(struct nf_conn *ct)
+{
+ struct nf_ct_dscpremark_ext *ncde;
+
+ ncde = nf_ct_dscpremark_ext_find(ct);
+ if (!ncde)
+ return -1;
+
+ ncde->rule_flags = NF_CT_DSCPREMARK_EXT_DSCP_RULE_VALID;
+ return 0;
+}
+EXPORT_SYMBOL(nf_conntrack_dscpremark_ext_set_dscp_rule_valid);
+
+/* nf_conntrack_dscpremark_ext_get_dscp_rule_validity()
+ * Check if the DSCP rule flag is valid from the extension
+ */
+int nf_conntrack_dscpremark_ext_get_dscp_rule_validity(struct nf_conn *ct)
+{
+ struct nf_ct_dscpremark_ext *ncde;
+
+ ncde = nf_ct_dscpremark_ext_find(ct);
+ if (!ncde)
+ return NF_CT_DSCPREMARK_EXT_RULE_NOT_VALID;
+
+ if (ncde->rule_flags & NF_CT_DSCPREMARK_EXT_DSCP_RULE_VALID)
+ return NF_CT_DSCPREMARK_EXT_RULE_VALID;
+
+ return NF_CT_DSCPREMARK_EXT_RULE_NOT_VALID;
+}
+EXPORT_SYMBOL(nf_conntrack_dscpremark_ext_get_dscp_rule_validity);
--- /dev/null
+++ b/include/soc/qcom/socinfo.h
@@ -0,0 +1,435 @@
+/* Copyright (c) 2009-2014, 2016, 2020, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _ARCH_ARM_MACH_MSM_SOCINFO_H_
+#define _ARCH_ARM_MACH_MSM_SOCINFO_H_
+
+#include <linux/of.h>
+
+#define CPU_IPQ4018 272
+#define CPU_IPQ4019 273
+#define CPU_IPQ4028 287
+#define CPU_IPQ4029 288
+
+#define CPU_IPQ8062 201
+#define CPU_IPQ8064 202
+#define CPU_IPQ8066 203
+#define CPU_IPQ8065 280
+#define CPU_IPQ8068 204
+#define CPU_IPQ8069 281
+
+#define CPU_IPQ8074 323
+#define CPU_IPQ8072 342
+#define CPU_IPQ8076 343
+#define CPU_IPQ8078 344
+#define CPU_IPQ8070 375
+#define CPU_IPQ8071 376
+
+#define CPU_IPQ8072A 389
+#define CPU_IPQ8074A 390
+#define CPU_IPQ8076A 391
+#define CPU_IPQ8078A 392
+#define CPU_IPQ8070A 395
+#define CPU_IPQ8071A 396
+
+#define CPU_IPQ8172 397
+#define CPU_IPQ8173 398
+#define CPU_IPQ8174 399
+
+#define CPU_IPQ6018 402
+#define CPU_IPQ6028 403
+#define CPU_IPQ6000 421
+#define CPU_IPQ6010 422
+#define CPU_IPQ6005 453
+
+/* TBD the CHIP IDs */
+#define CPU_IPQ5000 425
+#define CPU_IPQ5010 426
+#define CPU_IPQ5018 427
+
+static inline const int* read_ipq_soc_version_major(void)
+{
+ const int *prop;
+ prop = of_get_property(of_find_node_by_path("/"), "soc_version_major",
+ NULL);
+
+ return prop;
+}
+
+static inline int read_ipq_cpu_type(void)
+{
+ const int *prop;
+ prop = of_get_property(of_find_node_by_path("/"), "cpu_type", NULL);
+ /*
+ * Return Default CPU type if "cpu_type" property is not found in DTSI
+ */
+ if (!prop)
+ return CPU_IPQ8064;
+ return *prop;
+}
+
+static inline int cpu_is_ipq4018(void)
+{
+#ifdef CONFIG_ARCH_QCOM
+ return read_ipq_cpu_type() == CPU_IPQ4018;
+#else
+ return 0;
+#endif
+}
+
+static inline int cpu_is_ipq4019(void)
+{
+#ifdef CONFIG_ARCH_QCOM
+ return read_ipq_cpu_type() == CPU_IPQ4019;
+#else
+ return 0;
+#endif
+}
+
+static inline int cpu_is_ipq4028(void)
+{
+#ifdef CONFIG_ARCH_QCOM
+ return read_ipq_cpu_type() == CPU_IPQ4028;
+#else
+ return 0;
+#endif
+}
+
+static inline int cpu_is_ipq4029(void)
+{
+#ifdef CONFIG_ARCH_QCOM
+ return read_ipq_cpu_type() == CPU_IPQ4029;
+#else
+ return 0;
+#endif
+}
+
+static inline int cpu_is_ipq40xx(void)
+{
+#ifdef CONFIG_ARCH_QCOM
+ return cpu_is_ipq4018() || cpu_is_ipq4019() ||
+ cpu_is_ipq4028() || cpu_is_ipq4029();
+#else
+ return 0;
+#endif
+}
+
+static inline int cpu_is_ipq8062(void)
+{
+#ifdef CONFIG_ARCH_QCOM
+ return read_ipq_cpu_type() == CPU_IPQ8062;
+#else
+ return 0;
+#endif
+}
+
+static inline int cpu_is_ipq8064(void)
+{
+#ifdef CONFIG_ARCH_QCOM
+ return read_ipq_cpu_type() == CPU_IPQ8064;
+#else
+ return 0;
+#endif
+}
+
+static inline int cpu_is_ipq8066(void)
+{
+#ifdef CONFIG_ARCH_QCOM
+ return read_ipq_cpu_type() == CPU_IPQ8066;
+#else
+ return 0;
+#endif
+}
+
+static inline int cpu_is_ipq8068(void)
+{
+#ifdef CONFIG_ARCH_QCOM
+ return read_ipq_cpu_type() == CPU_IPQ8068;
+#else
+ return 0;
+#endif
+}
+
+static inline int cpu_is_ipq8065(void)
+{
+#ifdef CONFIG_ARCH_QCOM
+ return read_ipq_cpu_type() == CPU_IPQ8065;
+#else
+ return 0;
+#endif
+}
+
+static inline int cpu_is_ipq8069(void)
+{
+#ifdef CONFIG_ARCH_QCOM
+ return read_ipq_cpu_type() == CPU_IPQ8069;
+#else
+ return 0;
+#endif
+}
+static inline int cpu_is_ipq806x(void)
+{
+#ifdef CONFIG_ARCH_QCOM
+ return cpu_is_ipq8062() || cpu_is_ipq8064() ||
+ cpu_is_ipq8066() || cpu_is_ipq8068() ||
+ cpu_is_ipq8065() || cpu_is_ipq8069();
+#else
+ return 0;
+#endif
+}
+
+static inline int cpu_is_ipq8070(void)
+{
+#ifdef CONFIG_ARCH_QCOM
+ return read_ipq_cpu_type() == CPU_IPQ8070;
+#else
+ return 0;
+#endif
+}
+
+static inline int cpu_is_ipq8071(void)
+{
+#ifdef CONFIG_ARCH_QCOM
+ return read_ipq_cpu_type() == CPU_IPQ8071;
+#else
+ return 0;
+#endif
+}
+
+static inline int cpu_is_ipq8072(void)
+{
+#ifdef CONFIG_ARCH_QCOM
+ return read_ipq_cpu_type() == CPU_IPQ8072;
+#else
+ return 0;
+#endif
+}
+
+static inline int cpu_is_ipq8074(void)
+{
+#ifdef CONFIG_ARCH_QCOM
+ return read_ipq_cpu_type() == CPU_IPQ8074;
+#else
+ return 0;
+#endif
+}
+
+static inline int cpu_is_ipq8076(void)
+{
+#ifdef CONFIG_ARCH_QCOM
+ return read_ipq_cpu_type() == CPU_IPQ8076;
+#else
+ return 0;
+#endif
+}
+
+static inline int cpu_is_ipq8078(void)
+{
+#ifdef CONFIG_ARCH_QCOM
+ return read_ipq_cpu_type() == CPU_IPQ8078;
+#else
+ return 0;
+#endif
+}
+
+static inline int cpu_is_ipq8072a(void)
+{
+#ifdef CONFIG_ARCH_QCOM
+ return read_ipq_cpu_type() == CPU_IPQ8072A;
+#else
+ return 0;
+#endif
+}
+
+static inline int cpu_is_ipq8074a(void)
+{
+#ifdef CONFIG_ARCH_QCOM
+ return read_ipq_cpu_type() == CPU_IPQ8074A;
+#else
+ return 0;
+#endif
+}
+
+static inline int cpu_is_ipq8076a(void)
+{
+#ifdef CONFIG_ARCH_QCOM
+ return read_ipq_cpu_type() == CPU_IPQ8076A;
+#else
+ return 0;
+#endif
+}
+
+static inline int cpu_is_ipq8078a(void)
+{
+#ifdef CONFIG_ARCH_QCOM
+ return read_ipq_cpu_type() == CPU_IPQ8078A;
+#else
+ return 0;
+#endif
+}
+
+static inline int cpu_is_ipq8070a(void)
+{
+#ifdef CONFIG_ARCH_QCOM
+ return read_ipq_cpu_type() == CPU_IPQ8070A;
+#else
+ return 0;
+#endif
+}
+
+static inline int cpu_is_ipq8071a(void)
+{
+#ifdef CONFIG_ARCH_QCOM
+ return read_ipq_cpu_type() == CPU_IPQ8071A;
+#else
+ return 0;
+#endif
+}
+
+static inline int cpu_is_ipq8172(void)
+{
+#ifdef CONFIG_ARCH_QCOM
+ return read_ipq_cpu_type() == CPU_IPQ8172;
+#else
+ return 0;
+#endif
+}
+
+static inline int cpu_is_ipq8173(void)
+{
+#ifdef CONFIG_ARCH_QCOM
+ return read_ipq_cpu_type() == CPU_IPQ8173;
+#else
+ return 0;
+#endif
+}
+
+static inline int cpu_is_ipq8174(void)
+{
+#ifdef CONFIG_ARCH_QCOM
+ return read_ipq_cpu_type() == CPU_IPQ8174;
+#else
+ return 0;
+#endif
+}
+
+static inline int cpu_is_ipq6018(void)
+{
+#ifdef CONFIG_ARCH_QCOM
+ return read_ipq_cpu_type() == CPU_IPQ6018;
+#else
+ return 0;
+#endif
+}
+
+static inline int cpu_is_ipq6028(void)
+{
+#ifdef CONFIG_ARCH_QCOM
+ return read_ipq_cpu_type() == CPU_IPQ6028;
+#else
+ return 0;
+#endif
+}
+
+static inline int cpu_is_ipq6000(void)
+{
+#ifdef CONFIG_ARCH_QCOM
+ return read_ipq_cpu_type() == CPU_IPQ6000;
+#else
+ return 0;
+#endif
+}
+
+static inline int cpu_is_ipq6010(void)
+{
+#ifdef CONFIG_ARCH_QCOM
+ return read_ipq_cpu_type() == CPU_IPQ6010;
+#else
+ return 0;
+#endif
+}
+
+static inline int cpu_is_ipq6005(void)
+{
+#ifdef CONFIG_ARCH_QCOM
+ return read_ipq_cpu_type() == CPU_IPQ6005;
+#else
+ return 0;
+#endif
+}
+
+static inline int cpu_is_ipq5000(void)
+{
+#ifdef CONFIG_ARCH_QCOM
+ return read_ipq_cpu_type() == CPU_IPQ5000;
+#else
+ return 0;
+#endif
+}
+
+static inline int cpu_is_ipq5010(void)
+{
+#ifdef CONFIG_ARCH_QCOM
+ return read_ipq_cpu_type() == CPU_IPQ5010;
+#else
+ return 0;
+#endif
+}
+
+static inline int cpu_is_ipq5018(void)
+{
+#ifdef CONFIG_ARCH_QCOM
+ return read_ipq_cpu_type() == CPU_IPQ5018;
+#else
+ return 0;
+#endif
+}
+
+static inline int cpu_is_ipq807x(void)
+{
+#ifdef CONFIG_ARCH_QCOM
+ return cpu_is_ipq8072() || cpu_is_ipq8074() ||
+ cpu_is_ipq8076() || cpu_is_ipq8078() ||
+ cpu_is_ipq8070() || cpu_is_ipq8071() ||
+ cpu_is_ipq8072a() || cpu_is_ipq8074a() ||
+ cpu_is_ipq8076a() || cpu_is_ipq8078a() ||
+ cpu_is_ipq8070a() || cpu_is_ipq8071a() ||
+ cpu_is_ipq8172() || cpu_is_ipq8173() ||
+ cpu_is_ipq8174();
+#else
+ return 0;
+#endif
+}
+
+static inline int cpu_is_ipq60xx(void)
+{
+#ifdef CONFIG_ARCH_QCOM
+ return cpu_is_ipq6018() || cpu_is_ipq6028() ||
+ cpu_is_ipq6000() || cpu_is_ipq6010() ||
+ cpu_is_ipq6005();
+#else
+ return 0;
+#endif
+}
+
+static inline int cpu_is_ipq50xx(void)
+{
+#ifdef CONFIG_ARCH_QCOM
+ return cpu_is_ipq5000() || cpu_is_ipq5010() ||
+ cpu_is_ipq5018();
+#else
+ return 0;
+#endif
+}
+
+#endif /* _ARCH_ARM_MACH_MSM_SOCINFO_H_ */
--- /dev/null
+++ b/include/uapi/linux/tc_act/tc_nss_mirred.h
@@ -0,0 +1,36 @@
+#ifndef __LINUX_TC_NSS_MIRRED_H
+#define __LINUX_TC_NSS_MIRRED_H
+
+#include <linux/pkt_cls.h>
+
+/*
+ * Type of nss mirred action.
+ */
+#define TCA_ACT_MIRRED_NSS 17
+
+/*
+ * Types of parameters for nss mirred action.
+ */
+enum {
+ TC_NSS_MIRRED_UNSPEC,
+ TC_NSS_MIRRED_TM,
+ TC_NSS_MIRRED_PARMS,
+ __TC_NSS_MIRRED_MAX
+};
+#define TC_NSS_MIRRED_MAX (__TC_NSS_MIRRED_MAX - 1)
+
+/*
+ * tc_nss_mirred
+ * tc command structure for nss mirred action.
+ */
+struct tc_nss_mirred {
+ tc_gen; /* General tc structure. */
+ __u32 from_ifindex; /* ifindex of the port from which traffic
+ * will be redirected.
+ */
+ __u32 to_ifindex; /* ifindex of the port to which traffic
+ * will be redirected.
+ */
+};
+
+#endif /* __LINUX_TC_NSS_MIRRED_H */

View File

@@ -0,0 +1,30 @@
--- a/arch/arm/boot/dts/qcom/qcom-ipq8064.dtsi
+++ b/arch/arm/boot/dts/qcom/qcom-ipq8064.dtsi
@@ -1706,6 +1706,27 @@
};
};
+ &rpm {
+ smb208_regulators: regulators {
+ compatible = "qcom,rpm-smb208-regulators";
+
+ smb208_s1a: s1a {
+ regulator-min-microvolt = <1050000>;
+ regulator-max-microvolt = <1150000>;
+
+ qcom,switch-mode-frequency = <1200000>;
+ };
+
+ smb208_s1b: s1b {
+ regulator-min-microvolt = <1050000>;
+ regulator-max-microvolt = <1150000>;
+
+ qcom,switch-mode-frequency = <1200000>;
+ };
+
+ };
+ };
+
&gmac1 {
compatible = "qcom,nss-gmac";
qcom,id = <0>;

View File

@@ -0,0 +1,210 @@
From c70758d96b22e4421a6afd824cb59e350c6a8040 Mon Sep 17 00:00:00 2001
From: Robert Marko <robert.marko@sartura.hr>
Date: Tue, 2 Jun 2020 22:09:15 +0200
Subject: [PATCH] Regulator: Add NSS VOLT
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
---
drivers/regulator/Kconfig | 7 +++++++
drivers/regulator/Makefile | 1 +
2 files changed, 8 insertions(+)
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -1663,4 +1663,11 @@ config REGULATOR_QCOM_LABIBB
boost regulator and IBB can be used as a negative boost regulator
for LCD display panel.
+config REGULATOR_NSS_VOLT
+ bool "Qualcomm IPQ806X NSS Voltage regulator"
+ depends on ARCH_QCOM || COMPILE_TEST
+ help
+ This driver provides support for the Qualcomm IPQ806X NSS Voltage
+ regulator.
+
endif
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -195,5 +195,6 @@ obj-$(CONFIG_REGULATOR_WM831X) += wm831x
obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o
obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o
obj-$(CONFIG_REGULATOR_WM8994) += wm8994-regulator.o
+obj-$(CONFIG_REGULATOR_NSS_VOLT) += nss-volt-ipq806x.o
ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG
--- /dev/null
+++ b/drivers/regulator/nss-volt-ipq806x.c
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/regulator/nss-volt-ipq806x.h>
+
+struct nss_data {
+ struct regulator *nss_reg;
+ u32 nss_core_vdd_nominal;
+ u32 nss_core_vdd_high;
+ u32 nss_core_threshold_freq;
+};
+
+static struct nss_data *data;
+
+int nss_ramp_voltage(unsigned long rate, bool ramp_up)
+{
+ int ret;
+ int curr_uV, uV;
+ struct regulator *reg;
+
+ if (!data) {
+ pr_err("NSS core regulator not init.\n");
+ return -ENODEV;
+ }
+
+ reg = data->nss_reg;
+
+ if (!reg) {
+ pr_err("NSS core regulator not found.\n");
+ return -EINVAL;
+ }
+
+ if (rate >= data->nss_core_threshold_freq)
+ uV = data->nss_core_vdd_high;
+ else
+ uV = data->nss_core_vdd_nominal;
+
+ curr_uV = regulator_get_voltage(reg);
+
+ if (ramp_up) {
+ if (uV <= curr_uV)
+ return 0;
+ } else {
+ if (uV >= curr_uV)
+ return 0;
+ }
+
+ ret = regulator_set_voltage(reg, uV, data->nss_core_vdd_high);
+ if (ret)
+ pr_err("NSS volt scaling failed (%d)\n", uV);
+
+ return ret;
+}
+
+static const struct of_device_id nss_ipq806x_match_table[] = {
+ { .compatible = "qcom,nss-common" },
+ {}
+};
+
+static int nss_volt_ipq806x_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ int ret;
+
+ if (!np)
+ return -ENODEV;
+
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->nss_reg = devm_regulator_get(&pdev->dev, "nss_core");
+ ret = PTR_ERR_OR_ZERO(data->nss_reg);
+ if (ret) {
+ if (ret == -EPROBE_DEFER)
+ dev_dbg(&pdev->dev,
+ "nss_core regulator not ready, retry\n");
+ else
+ dev_err(&pdev->dev, "no regulator for nss_core: %d\n",
+ ret);
+
+ return ret;
+ }
+
+ if (of_property_read_u32(np, "nss_core_vdd_nominal",
+ &data->nss_core_vdd_nominal)) {
+ pr_warn("NSS core vdd nominal not found. Using defaults...\n");
+ data->nss_core_vdd_nominal = 1100000;
+ }
+
+ if (of_property_read_u32(np, "nss_core_vdd_high",
+ &data->nss_core_vdd_high)) {
+ pr_warn("NSS core vdd high not found. Using defaults...\n");
+ data->nss_core_vdd_high = 1150000;
+ }
+
+ if (of_property_read_u32(np, "nss_core_threshold_freq",
+ &data->nss_core_threshold_freq)) {
+ pr_warn("NSS core thres freq not found. Using defaults...\n");
+ data->nss_core_threshold_freq = 733000000;
+ }
+
+ platform_set_drvdata(pdev, data);
+
+ return 0;
+}
+
+static struct platform_driver nss_ipq806x_driver = {
+ .probe = nss_volt_ipq806x_probe,
+ .driver = {
+ .name = "nss-volt-ipq806x",
+ .owner = THIS_MODULE,
+ .of_match_table = nss_ipq806x_match_table,
+ },
+};
+
+static int __init nss_ipq806x_init(void)
+{
+ return platform_driver_register(&nss_ipq806x_driver);
+}
+late_initcall(nss_ipq806x_init);
+
+static void __exit nss_ipq806x_exit(void)
+{
+ platform_driver_unregister(&nss_ipq806x_driver);
+}
+module_exit(nss_ipq806x_exit);
--- /dev/null
+++ b/include/linux/regulator/nss-volt-ipq806x.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __QCOM_NSS_VOL_SCALING_H
+#define __QCOM_NSS_VOL_SCALING_H
+
+#include <linux/regulator/consumer.h>
+
+int nss_ramp_voltage(unsigned long rate, bool ramp_up);
+
+#endif

View File

@@ -0,0 +1,237 @@
refs: linux-msm
db30db7d342f
42924e528bb6
--- a/include/dt-bindings/clock/qcom,gcc-ipq806x.h
+++ b/include/dt-bindings/clock/qcom,gcc-ipq806x.h
@@ -283,6 +283,7 @@
#define EBI2_AON_CLK 281
#define NSSTCM_CLK_SRC 282
#define NSSTCM_CLK 283
+#define NSS_CORE_CLK 284 /* Virtual */
#define CE5_A_CLK_SRC 285
#define CE5_H_CLK_SRC 286
#define CE5_CORE_CLK_SRC 287
--- a/drivers/clk/qcom/gcc-ipq806x.c
+++ b/drivers/clk/qcom/gcc-ipq806x.c
@@ -24,6 +24,10 @@
#include "clk-branch.h"
#include "clk-hfpll.h"
#include "reset.h"
+#include <linux/regulator/nss-volt-ipq806x.h>
+
+/* NSS safe parent index which will be used during NSS PLL rate change */
+static int gcc_ipq806x_nss_safe_parent;
static const struct clk_parent_data gcc_pxo[] = {
{ .fw_name = "pxo", .name = "pxo" },
@@ -2825,7 +2829,8 @@ static struct clk_dyn_rcg ubi32_core1_sr
.parent_data = gcc_pxo_pll8_pll14_pll18_pll0,
.num_parents = ARRAY_SIZE(gcc_pxo_pll8_pll14_pll18_pll0),
.ops = &clk_dyn_rcg_ops,
- .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE,
+ .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE |
+ CLK_IGNORE_UNUSED,
},
},
};
@@ -2878,7 +2883,8 @@ static struct clk_dyn_rcg ubi32_core2_sr
.parent_data = gcc_pxo_pll8_pll14_pll18_pll0,
.num_parents = ARRAY_SIZE(gcc_pxo_pll8_pll14_pll18_pll0),
.ops = &clk_dyn_rcg_ops,
- .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE,
+ .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE |
+ CLK_IGNORE_UNUSED,
},
},
};
@@ -3063,6 +3069,145 @@ static struct clk_branch ce5_h_clk = {
},
};
+static int nss_core_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ int ret;
+
+ /*
+ * When ramping up voltage, it needs to be done first. This ensures that
+ * the volt required will be available when you step up the frequency.
+ */
+ ret = nss_ramp_voltage(rate, true);
+ if (ret)
+ return ret;
+
+ ret = clk_dyn_rcg_ops.set_rate(&ubi32_core1_src_clk.clkr.hw, rate,
+ parent_rate);
+ if (ret)
+ return ret;
+
+ ret = clk_dyn_rcg_ops.set_rate(&ubi32_core2_src_clk.clkr.hw, rate,
+ parent_rate);
+
+ if (ret)
+ return ret;
+
+ /*
+ * When ramping down voltage, it needs to be set first. This ensures
+ * that the volt required will be available until you step down the
+ * frequency.
+ */
+ ret = nss_ramp_voltage(rate, false);
+
+ return ret;
+}
+
+static int
+nss_core_clk_set_rate_and_parent(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate, u8 index)
+{
+ int ret;
+
+ /*
+ * When ramping up voltage needs to be done first. This ensures that
+ * the voltage required will be available when you step up the
+ * frequency.
+ */
+ ret = nss_ramp_voltage(rate, true);
+ if (ret)
+ return ret;
+
+ ret = clk_dyn_rcg_ops.set_rate_and_parent(
+ &ubi32_core1_src_clk.clkr.hw, rate, parent_rate, index);
+ if (ret)
+ return ret;
+
+ ret = clk_dyn_rcg_ops.set_rate_and_parent(
+ &ubi32_core2_src_clk.clkr.hw, rate, parent_rate, index);
+
+ if (ret)
+ return ret;
+
+ /*
+ * When ramping down voltage needs to be done last. This ensures that
+ * the voltage required will be available when you step down the
+ * frequency.
+ */
+ ret = nss_ramp_voltage(rate, false);
+
+ return ret;
+}
+
+static int nss_core_clk_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+ return clk_dyn_rcg_ops.determine_rate(&ubi32_core1_src_clk.clkr.hw,
+ req);
+}
+
+static unsigned long
+nss_core_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+ return clk_dyn_rcg_ops.recalc_rate(&ubi32_core1_src_clk.clkr.hw,
+ parent_rate);
+}
+
+static u8 nss_core_clk_get_parent(struct clk_hw *hw)
+{
+ return clk_dyn_rcg_ops.get_parent(&ubi32_core1_src_clk.clkr.hw);
+}
+
+static int nss_core_clk_set_parent(struct clk_hw *hw, u8 i)
+{
+ int ret;
+ struct clk_dyn_rcg *rcg;
+ struct freq_tbl f = { 200000000, P_PLL0, 2, 1, 2 };
+
+ /* P_PLL0 is 800 Mhz which needs to be divided for 200 Mhz */
+ if (i == gcc_ipq806x_nss_safe_parent) {
+ rcg = to_clk_dyn_rcg(&ubi32_core1_src_clk.clkr.hw);
+ clk_dyn_configure_bank(rcg, &f);
+
+ rcg = to_clk_dyn_rcg(&ubi32_core2_src_clk.clkr.hw);
+ clk_dyn_configure_bank(rcg, &f);
+
+ return 0;
+ }
+
+ ret = clk_dyn_rcg_ops.set_parent(&ubi32_core1_src_clk.clkr.hw, i);
+ if (ret)
+ return ret;
+
+ return clk_dyn_rcg_ops.set_parent(&ubi32_core2_src_clk.clkr.hw, i);
+}
+
+static struct clk_hw *nss_core_clk_get_safe_parent(struct clk_hw *hw)
+{
+ return clk_hw_get_parent_by_index(hw, gcc_ipq806x_nss_safe_parent);
+}
+
+static const struct clk_ops clk_ops_nss_core = {
+ .set_rate = nss_core_clk_set_rate,
+ .set_rate_and_parent = nss_core_clk_set_rate_and_parent,
+ .determine_rate = nss_core_clk_determine_rate,
+ .recalc_rate = nss_core_clk_recalc_rate,
+ .get_parent = nss_core_clk_get_parent,
+ .set_parent = nss_core_clk_set_parent,
+ .get_safe_parent = nss_core_clk_get_safe_parent,
+};
+
+/* Virtual clock for nss core clocks */
+static struct clk_regmap nss_core_clk = {
+ .hw.init = &(struct clk_init_data){
+ .name = "nss_core_clk",
+ .ops = &clk_ops_nss_core,
+ .parent_data = gcc_pxo_pll8_pll14_pll18_pll0,
+ .num_parents = 5,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
static struct clk_regmap *gcc_ipq806x_clks[] = {
[PLL0] = &pll0.clkr,
[PLL0_VOTE] = &pll0_vote,
@@ -3182,6 +3327,7 @@ static struct clk_regmap *gcc_ipq806x_cl
[UBI32_CORE2_CLK_SRC] = &ubi32_core2_src_clk.clkr,
[NSSTCM_CLK_SRC] = &nss_tcm_src.clkr,
[NSSTCM_CLK] = &nss_tcm_clk.clkr,
+ [NSS_CORE_CLK] = &nss_core_clk,
[PLL9] = &hfpll0.clkr,
[PLL10] = &hfpll1.clkr,
[PLL12] = &hfpll_l2.clkr,
@@ -3402,6 +3548,12 @@ static int gcc_ipq806x_probe(struct plat
if (!regmap)
return -ENODEV;
+ gcc_ipq806x_nss_safe_parent = qcom_find_src_index(&nss_core_clk.hw,
+ gcc_pxo_pll8_pll14_pll18_pll0_map,
+ P_PLL0);
+ if (gcc_ipq806x_nss_safe_parent < 0)
+ return gcc_ipq806x_nss_safe_parent;
+
/* Setup PLL18 static bits */
regmap_update_bits(regmap, 0x31a4, 0xffffffc0, 0x40000400);
regmap_write(regmap, 0x31b0, 0x3080);
--- a/drivers/clk/qcom/clk-rcg.c
+++ b/drivers/clk/qcom/clk-rcg.c
@@ -818,6 +818,11 @@ static int clk_dyn_rcg_set_rate_and_pare
return __clk_dyn_rcg_set_rate(hw, rate);
}
+void clk_dyn_configure_bank(struct clk_dyn_rcg *rcg, const struct freq_tbl *f)
+{
+ configure_bank(rcg, f);
+}
+
const struct clk_ops clk_rcg_ops = {
.enable = clk_enable_regmap,
.disable = clk_disable_regmap,
--- a/drivers/clk/qcom/clk-rcg.h
+++ b/drivers/clk/qcom/clk-rcg.h
@@ -191,4 +191,7 @@ struct clk_rcg_dfs_data {
extern int qcom_cc_register_rcg_dfs(struct regmap *regmap,
const struct clk_rcg_dfs_data *rcgs,
size_t len);
+
+extern void clk_dyn_configure_bank(struct clk_dyn_rcg *rcg,
+ const struct freq_tbl *f);
#endif

View File

@@ -0,0 +1,149 @@
From a4851511e1d8e61a14c6f2345354c059cb964e6a Mon Sep 17 00:00:00 2001
From: regae <37059068+regae@users.noreply.github.com>
Date: Sat, 15 Jun 2024 19:16:36 +0700
Subject: [PATCH 10/13] OpenWrt: 136-clk-Add-safe-switch-hook.patch
Sometimes clocks can't accept their parent source turning off
while the source is reprogrammed to a different rate. Most
notably CPU clocks require a way to switch away from the current
PLL they're running on, reprogram that PLL to a new rate, and
then switch back to the PLL with the new rate once they're done.
Add a hook that drivers can implement allowing them to return a
'safe parent' that they can switch their parent to while the
upstream source is reprogrammed to support this.
---
drivers/clk/clk.c | 61 +++++++++++++++++++++++++++++++-----
include/linux/clk-provider.h | 1 +
2 files changed, 54 insertions(+), 8 deletions(-)
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -69,9 +69,12 @@ struct clk_core {
struct clk_parent_map *parents;
u8 num_parents;
u8 new_parent_index;
+ u8 safe_parent_index;
unsigned long rate;
unsigned long req_rate;
+ unsigned long old_rate;
unsigned long new_rate;
+ struct clk_core *safe_parent;
struct clk_core *new_parent;
struct clk_core *new_child;
unsigned long flags;
@@ -2240,7 +2243,8 @@ out:
static void clk_calc_subtree(struct clk_core *core, unsigned long new_rate,
struct clk_core *new_parent, u8 p_index)
{
- struct clk_core *child;
+ struct clk_core *child, *parent;
+ struct clk_hw *parent_hw;
core->new_rate = new_rate;
core->new_parent = new_parent;
@@ -2250,6 +2254,18 @@ static void clk_calc_subtree(struct clk_
if (new_parent && new_parent != core->parent)
new_parent->new_child = core;
+ if (core->ops->get_safe_parent) {
+ parent_hw = core->ops->get_safe_parent(core->hw);
+ if (parent_hw) {
+ parent = parent_hw->core;
+ p_index = clk_fetch_parent_index(core, parent);
+ core->safe_parent_index = p_index;
+ core->safe_parent = parent;
+ }
+ } else {
+ core->safe_parent = NULL;
+ }
+
hlist_for_each_entry(child, &core->children, child_node) {
child->new_rate = clk_recalc(child, new_rate);
clk_calc_subtree(child, child->new_rate, NULL, 0);
@@ -2351,14 +2367,43 @@ static struct clk_core *clk_propagate_ra
unsigned long event)
{
struct clk_core *child, *tmp_clk, *fail_clk = NULL;
+ struct clk_core *old_parent;
int ret = NOTIFY_DONE;
- if (core->rate == core->new_rate)
+ if (core->rate == core->new_rate && event != POST_RATE_CHANGE)
return NULL;
+ switch (event) {
+ case PRE_RATE_CHANGE:
+ if (core->safe_parent)
+ core->ops->set_parent(core->hw, core->safe_parent_index);
+ core->old_rate = core->rate;
+ break;
+ case POST_RATE_CHANGE:
+ if (core->safe_parent) {
+ old_parent = __clk_set_parent_before(core,
+ core->new_parent);
+ if (core->ops->set_rate_and_parent) {
+ core->ops->set_rate_and_parent(core->hw,
+ core->new_rate,
+ core->new_parent ?
+ core->new_parent->rate : 0,
+ core->new_parent_index);
+ } else if (core->ops->set_parent) {
+ core->ops->set_parent(core->hw,
+ core->new_parent_index);
+ }
+ __clk_set_parent_after(core, core->new_parent,
+ old_parent);
+ }
+ break;
+ }
+
if (core->notifier_count) {
- ret = __clk_notify(core, event, core->rate, core->new_rate);
- if (ret & NOTIFY_STOP_MASK)
+ if (event != POST_RATE_CHANGE || core->old_rate != core->rate)
+ ret = __clk_notify(core, event, core->old_rate,
+ core->new_rate);
+ if (ret & NOTIFY_STOP_MASK && event != POST_RATE_CHANGE)
fail_clk = core;
}
@@ -2413,7 +2458,8 @@ static void clk_change_rate(struct clk_c
clk_core_enable_lock(core);
}
- if (core->new_parent && core->new_parent != core->parent) {
+ if (core->new_parent && core->new_parent != core->parent &&
+ !core->safe_parent) {
old_parent = __clk_set_parent_before(core, core->new_parent);
trace_clk_set_parent(core, core->new_parent);
@@ -2450,9 +2496,6 @@ static void clk_change_rate(struct clk_c
if (core->flags & CLK_OPS_PARENT_ENABLE)
clk_core_disable_unprepare(parent);
- if (core->notifier_count && old_rate != core->rate)
- __clk_notify(core, POST_RATE_CHANGE, old_rate, core->rate);
-
if (core->flags & CLK_RECALC_NEW_RATES)
(void)clk_calc_new_rates(core, core->new_rate);
@@ -2547,6 +2590,8 @@ static int clk_core_set_rate_nolock(stru
clk_change_rate(top);
core->req_rate = req_rate;
+ clk_propagate_rate_change(top, POST_RATE_CHANGE);
+
err:
clk_pm_runtime_put(core);
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -250,6 +250,7 @@ struct clk_ops {
struct clk_rate_request *req);
int (*set_parent)(struct clk_hw *hw, u8 index);
u8 (*get_parent)(struct clk_hw *hw);
+ struct clk_hw *(*get_safe_parent)(struct clk_hw *hw);
int (*set_rate)(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate);
int (*set_rate_and_parent)(struct clk_hw *hw,

View File

@@ -0,0 +1,159 @@
From 16c72f2199f57a4b2f0295b8d08881cc94ad7e0b Mon Sep 17 00:00:00 2001
From: Kathiravan T <kathirav@codeaurora.org>
Date: Thu, 7 Feb 2013 12:15:11 -0800
Subject: [PATCH 274/281] Revert "ARM: dma-mapping: remove dmac_clean_range and
dmac_inv_range"
This partially reverts 'commit 702b94bff3c505 ("ARM: dma-mapping:
remove dmac_clean_range and dmac_inv_range")'
Some MSM drivers still use the dmac_clean and dmac_inv_range APIs.
Bring back the defines and exports for v7 CPUs.
Change-Id: I69017d73da1065a5eeb9c87c899b6a51be5ebfe6
Signed-off-by: Rohit Vaswani <rvaswani@codeaurora.org>
Signed-off-by: Abhimanyu Kapur <abhimany@codeaurora.org>
[sramana: resolved minor merge conflicts]
Signed-off-by: Srinivas Ramana <sramana@codeaurora.org>
[akdwived: Made change for checkpatch error]
Signed-off-by: Avaneesh Kumar Dwivedi <akdwived@codeaurora.org>
Signed-off-by: Vijayanand Jitta <vjitta@codeaurora.org>
[qqzhou@codeaurora.org: Made change for compile error]
Signed-off-by: Qingqing Zhou <qqzhou@codeaurora.org>
(cherry picked from commit 432d2898642443b498747a8e8a42cb423bd726f1)
Signed-off-by: Kathiravan T <kathirav@codeaurora.org>
Change-Id: If81758c05ae89333205b8021a73287920a8ee64d
Signed-off-by: Pavithra R <quic_pavir@quicinc.com>
---
arch/arm/include/asm/cacheflush.h | 21 +++++++++++++++++++++
arch/arm/include/asm/glue-cache.h | 2 ++
arch/arm/mm/cache-v7.S | 6 ++++--
arch/arm/mm/proc-macros.S | 4 +++-
arch/arm/mm/proc-syms.c | 3 +++
5 files changed, 33 insertions(+), 3 deletions(-)
--- a/arch/arm/include/asm/cacheflush.h
+++ b/arch/arm/include/asm/cacheflush.h
@@ -91,6 +91,21 @@
* DMA Cache Coherency
* ===================
*
+ * dma_inv_range(start, end)
+ *
+ * Invalidate (discard) the specified virtual address range.
+ * May not write back any entries. If 'start' or 'end'
+ * are not cache line aligned, those lines must be written
+ * back.
+ * - start - virtual start address
+ * - end - virtual end address
+ *
+ * dma_clean_range(start, end)
+ *
+ * Clean (write back) the specified virtual address range.
+ * - start - virtual start address
+ * - end - virtual end address
+ *
* dma_flush_range(start, end)
*
* Clean and invalidate the specified virtual address range.
@@ -112,6 +127,8 @@ struct cpu_cache_fns {
void (*dma_map_area)(const void *, size_t, int);
void (*dma_unmap_area)(const void *, size_t, int);
+ void (*dma_inv_range)(const void *, const void *);
+ void (*dma_clean_range)(const void *, const void *);
void (*dma_flush_range)(const void *, const void *);
} __no_randomize_layout;
@@ -137,6 +154,8 @@ extern struct cpu_cache_fns cpu_cache;
* is visible to DMA, or data written by DMA to system memory is
* visible to the CPU.
*/
+#define dmac_inv_range cpu_cache.dma_inv_range
+#define dmac_clean_range cpu_cache.dma_clean_range
#define dmac_flush_range cpu_cache.dma_flush_range
#else
@@ -156,6 +175,8 @@ extern void __cpuc_flush_dcache_area(voi
* is visible to DMA, or data written by DMA to system memory is
* visible to the CPU.
*/
+extern void dmac_inv_range(const void *, const void *);
+extern void dmac_clean_range(const void *, const void *);
extern void dmac_flush_range(const void *, const void *);
#endif
--- a/arch/arm/include/asm/glue-cache.h
+++ b/arch/arm/include/asm/glue-cache.h
@@ -156,6 +156,8 @@ static inline void nop_dma_unmap_area(co
#define __cpuc_flush_dcache_area __glue(_CACHE,_flush_kern_dcache_area)
#define dmac_flush_range __glue(_CACHE,_dma_flush_range)
+#define dmac_inv_range __glue(_CACHE, _dma_inv_range)
+#define dmac_clean_range __glue(_CACHE, _dma_clean_range)
#endif
#endif
--- a/arch/arm/mm/cache-v7.S
+++ b/arch/arm/mm/cache-v7.S
@@ -361,7 +361,7 @@ ENDPROC(v7_flush_kern_dcache_area)
* - start - virtual start address of region
* - end - virtual end address of region
*/
-v7_dma_inv_range:
+ENTRY(v7_dma_inv_range)
dcache_line_size r2, r3
sub r3, r2, #1
tst r0, r3
@@ -391,7 +391,7 @@ ENDPROC(v7_dma_inv_range)
* - start - virtual start address of region
* - end - virtual end address of region
*/
-v7_dma_clean_range:
+ENTRY(v7_dma_clean_range)
dcache_line_size r2, r3
sub r3, r2, #1
bic r0, r0, r3
@@ -477,6 +477,8 @@ ENDPROC(v7_dma_unmap_area)
globl_equ b15_dma_map_area, v7_dma_map_area
globl_equ b15_dma_unmap_area, v7_dma_unmap_area
+ globl_equ b15_dma_inv_range, v7_dma_inv_range
+ globl_equ b15_dma_clean_range, v7_dma_clean_range
globl_equ b15_dma_flush_range, v7_dma_flush_range
define_cache_functions b15
--- a/arch/arm/mm/proc-macros.S
+++ b/arch/arm/mm/proc-macros.S
@@ -326,7 +326,7 @@ ENTRY(\name\()_processor_functions)
ENTRY(\name\()_cache_fns)
.long \name\()_flush_icache_all
.long \name\()_flush_kern_cache_all
- .long \name\()_flush_kern_cache_louis
+ .long \name\()_flush_kern_cache_louis
.long \name\()_flush_user_cache_all
.long \name\()_flush_user_cache_range
.long \name\()_coherent_kern_range
@@ -334,6 +334,8 @@ ENTRY(\name\()_cache_fns)
.long \name\()_flush_kern_dcache_area
.long \name\()_dma_map_area
.long \name\()_dma_unmap_area
+ .long \name\()_dma_inv_range
+ .long \name\()_dma_clean_range
.long \name\()_dma_flush_range
.size \name\()_cache_fns, . - \name\()_cache_fns
.endm
--- a/arch/arm/mm/proc-syms.c
+++ b/arch/arm/mm/proc-syms.c
@@ -27,6 +27,9 @@ EXPORT_SYMBOL(__cpuc_flush_user_all);
EXPORT_SYMBOL(__cpuc_flush_user_range);
EXPORT_SYMBOL(__cpuc_coherent_kern_range);
EXPORT_SYMBOL(__cpuc_flush_dcache_area);
+EXPORT_SYMBOL(dmac_inv_range);
+EXPORT_SYMBOL(dmac_clean_range);
+EXPORT_SYMBOL(dmac_flush_range);
#else
EXPORT_SYMBOL(cpu_cache);
#endif

View File

@@ -0,0 +1,379 @@
From fe56e8cb75f113577dbf3edb717ea967f3723e22 Mon Sep 17 00:00:00 2001
From: Suman Ghosh <quic_sumaghos@quicinc.com>
Date: Sat, 4 Sep 2021 01:09:20 +0530
Subject: [PATCH 278/281] arm/arm64: Add new APIs to perform dma cache
maintenance operation without dsb.
Change-Id: I511657af343c8dc668ab7280362b3cdd57579360
Signed-off-by: Suman Ghosh <quic_sumaghos@quicinc.com>
Signed-off-by: Tushar Ganatra <quic_tganatra@quicinc.com>
Signed-off-by: Pavithra R <quic_pavir@quicinc.com>
Signed-off-by: Tushar Ganatra <quic_tganatra@quicinc.com>
---
arch/arm/include/asm/cacheflush.h | 11 ++++
arch/arm/include/asm/glue-cache.h | 3 +
arch/arm/mm/cache-v7.S | 98 +++++++++++++++++++++++++++--
arch/arm/mm/proc-syms.c | 3 +
arch/arm64/include/asm/assembler.h | 39 ++++++++++++
arch/arm64/include/asm/cacheflush.h | 9 +++
arch/arm64/mm/cache.S | 58 +++++++++++++++++
arch/arm64/mm/flush.c | 24 +++++++
8 files changed, 239 insertions(+), 6 deletions(-)
--- a/arch/arm/include/asm/cacheflush.h
+++ b/arch/arm/include/asm/cacheflush.h
@@ -130,6 +130,10 @@ struct cpu_cache_fns {
void (*dma_inv_range)(const void *, const void *);
void (*dma_clean_range)(const void *, const void *);
void (*dma_flush_range)(const void *, const void *);
+
+ void (*dma_inv_range_no_dsb)(const void *, const void *);
+ void (*dma_clean_range_no_dsb)(const void *, const void *);
+ void (*dma_flush_range_no_dsb)(const void *, const void *);
} __no_randomize_layout;
/*
@@ -158,6 +162,10 @@ extern struct cpu_cache_fns cpu_cache;
#define dmac_clean_range cpu_cache.dma_clean_range
#define dmac_flush_range cpu_cache.dma_flush_range
+#define dmac_inv_range_no_dsb cpu_cache.dma_inv_range_no_dsb
+#define dmac_clean_range_no_dsb cpu_cache.dma_clean_range_no_dsb
+#define dmac_flush_range_no_dsb cpu_cache.dma_flush_range_no_dsb
+
#else
extern void __cpuc_flush_icache_all(void);
@@ -178,6 +186,9 @@ extern void __cpuc_flush_dcache_area(voi
extern void dmac_inv_range(const void *, const void *);
extern void dmac_clean_range(const void *, const void *);
extern void dmac_flush_range(const void *, const void *);
+extern void dmac_inv_range_no_dsb(const void *, const void *);
+extern void dmac_clean_range_no_dsb(const void *, const void *);
+extern void dmac_flush_range_no_dsb(const void *, const void *);
#endif
--- a/arch/arm/include/asm/glue-cache.h
+++ b/arch/arm/include/asm/glue-cache.h
@@ -156,8 +156,11 @@ static inline void nop_dma_unmap_area(co
#define __cpuc_flush_dcache_area __glue(_CACHE,_flush_kern_dcache_area)
#define dmac_flush_range __glue(_CACHE,_dma_flush_range)
+#define dmac_flush_range_no_dsb __glue(_CACHE,_dma_flush_range_no_dsb)
#define dmac_inv_range __glue(_CACHE, _dma_inv_range)
+#define dmac_inv_range_no_dsb __glue(_CACHE, _dma_inv_range_no_dsb)
#define dmac_clean_range __glue(_CACHE, _dma_clean_range)
+#define dmac_clean_range_no_dsb __glue(_CACHE, _dma_clean_range_no_dsb)
#endif
#endif
--- a/arch/arm/mm/cache-v7.S
+++ b/arch/arm/mm/cache-v7.S
@@ -387,6 +387,42 @@ ENTRY(v7_dma_inv_range)
ENDPROC(v7_dma_inv_range)
/*
+ * v7_dma_inv_range_no_dsb(start,end)
+ *
+ * Invalidate the data cache within the specified region; we will
+ * be performing a DMA operation in this region and we want to
+ * purge old data in the cache. This API does not do
+ * "data synchronization barrier". The caller is responsible to
+ * do dsb after the transaction.
+ *
+ * - start - virtual start address of region
+ * - end - virtual end address of region
+ */
+ENTRY(v7_dma_inv_range_no_dsb)
+ dcache_line_size r2, r3
+ sub r3, r2, #1
+ tst r0, r3
+ bic r0, r0, r3
+#ifdef CONFIG_ARM_ERRATA_764369
+ ALT_SMP(W(dsb))
+ ALT_UP(W(nop))
+#endif
+ mcrne p15, 0, r0, c7, c14, 1 @ clean & invalidate D / U line
+ addne r0, r0, r2
+
+ tst r1, r3
+ bic r1, r1, r3
+ mcrne p15, 0, r1, c7, c14, 1 @ clean & invalidate D / U line
+ cmp r0, r1
+1:
+ mcrlo p15, 0, r0, c7, c6, 1 @ invalidate D / U line
+ addlo r0, r0, r2
+ cmplo r0, r1
+ blo 1b
+ ret lr
+ENDPROC(v7_dma_inv_range_no_dsb)
+
+/*
* v7_dma_clean_range(start,end)
* - start - virtual start address of region
* - end - virtual end address of region
@@ -409,12 +445,16 @@ ENTRY(v7_dma_clean_range)
ENDPROC(v7_dma_clean_range)
/*
- * v7_dma_flush_range(start,end)
+ * v7_dma_clean_range_no_dsb(start,end)
+ *
+ * This API does not do "data synchronization barrier".
+ * The caller is responsible to do dsb after the transaction.
+ *
* - start - virtual start address of region
* - end - virtual end address of region
*/
-ENTRY(v7_dma_flush_range)
- dcache_line_size r2, r3
+ENTRY(v7_dma_clean_range_no_dsb)
+ dcache_line_size r2, r3
sub r3, r2, #1
bic r0, r0, r3
#ifdef CONFIG_ARM_ERRATA_764369
@@ -422,6 +462,27 @@ ENTRY(v7_dma_flush_range)
ALT_UP(W(nop))
#endif
1:
+ mcr p15, 0, r0, c7, c10, 1 @ clean D / U line
+ add r0, r0, r2
+ cmp r0, r1
+ blo 1b
+ ret lr
+ENDPROC(v7_dma_clean_range_no_dsb)
+
+/*
+ * v7_dma_flush_range(start,end)
+ * - start - virtual start address of region
+ * - end - virtual end address of region
+ */
+ENTRY(v7_dma_flush_range)
+ dcache_line_size r2, r3
+ sub r3, r2, #1
+ bic r0, r0, r3
+#ifdef CONFIG_ARM_ERRATA_764369
+ ALT_SMP(W(dsb))
+ ALT_UP(W(nop))
+#endif
+1:
mcr p15, 0, r0, c7, c14, 1 @ clean & invalidate D / U line
add r0, r0, r2
cmp r0, r1
@@ -431,10 +492,35 @@ ENTRY(v7_dma_flush_range)
ENDPROC(v7_dma_flush_range)
/*
+ * v7_dma_flush_range_no_dsb(start,end)
+ *
+ * This API does not do "data synchronization barrier".
+ * The caller is responsible to do dsb after the transaction.
+ *
+ * - start - virtual start address of region
+ * - end - virtual end address of region
+ */
+ENTRY(v7_dma_flush_range_no_dsb)
+ dcache_line_size r2, r3
+ sub r3, r2, #1
+ bic r0, r0, r3
+#ifdef CONFIG_ARM_ERRATA_764369
+ ALT_SMP(W(dsb))
+ ALT_UP(W(nop))
+#endif
+1:
+ mcr p15, 0, r0, c7, c14, 1 @ clean & invalidate D / U line
+ add r0, r0, r2
+ cmp r0, r1
+ blo 1b
+ ret lr
+ENDPROC(v7_dma_flush_range_no_dsb)
+
+/*
* dma_map_area(start, size, dir)
- * - start - kernel virtual start address
- * - size - size of region
- * - dir - DMA direction
+ * - start - kernel virtual start address
+ * - size - size of region
+ * - dir - DMA direction
*/
ENTRY(v7_dma_map_area)
add r1, r1, r0
--- a/arch/arm/mm/proc-syms.c
+++ b/arch/arm/mm/proc-syms.c
@@ -28,8 +28,11 @@ EXPORT_SYMBOL(__cpuc_flush_user_range);
EXPORT_SYMBOL(__cpuc_coherent_kern_range);
EXPORT_SYMBOL(__cpuc_flush_dcache_area);
EXPORT_SYMBOL(dmac_inv_range);
+EXPORT_SYMBOL(dmac_inv_range_no_dsb);
EXPORT_SYMBOL(dmac_clean_range);
+EXPORT_SYMBOL(dmac_clean_range_no_dsb);
EXPORT_SYMBOL(dmac_flush_range);
+EXPORT_SYMBOL(dmac_flush_range_no_dsb);
#else
EXPORT_SYMBOL(cpu_cache);
#endif
--- a/arch/arm64/include/asm/assembler.h
+++ b/arch/arm64/include/asm/assembler.h
@@ -428,6 +428,45 @@ alternative_endif
/*
* Macro to perform a data cache maintenance for the interval
+ * [kaddr, kaddr + size)
+ * This macro does not do "data synchronization barrier". Caller should
+ * do "dsb" after transaction.
+ *
+ * op: operation passed to dc instruction
+ * kaddr: starting virtual address of the region
+ * size: size of the region
+ * Corrupts: kaddr, size, tmp1, tmp2
+ */
+ .macro dcache_by_line_op_no_dsb op, kaddr, size, tmp1, tmp2
+ dcache_line_size \tmp1, \tmp2
+ add \size, \kaddr, \size
+ sub \tmp2, \tmp1, #1
+ bic \kaddr, \kaddr, \tmp2
+9998:
+ .ifc \op, cvau
+ __dcache_op_workaround_clean_cache \op, \kaddr
+ .else
+ .ifc \op, cvac
+ __dcache_op_workaround_clean_cache \op, \kaddr
+ .else
+ .ifc \op, cvap
+ sys 3, c7, c12, 1, \kaddr // dc cvap
+ .else
+ .ifc \op, cvadp
+ sys 3, c7, c13, 1, \kaddr // dc cvadp
+ .else
+ dc \op, \kaddr
+ .endif
+ .endif
+ .endif
+ .endif
+ add \kaddr, \kaddr, \tmp1
+ cmp \kaddr, \size
+ b.lo 9998b
+ .endm
+
+/*
+ * Macro to perform a data cache maintenance for the interval
* [start, end)
*
* op: operation passed to dc instruction
--- a/arch/arm64/include/asm/cacheflush.h
+++ b/arch/arm64/include/asm/cacheflush.h
@@ -79,6 +79,15 @@ extern void dcache_clean_pou(unsigned lo
extern long caches_clean_inval_user_pou(unsigned long start, unsigned long end);
extern void sync_icache_aliases(unsigned long start, unsigned long end);
+extern void dmac_inv_range(const void *start, const void *end);
+extern void __dma_flush_area_no_dsb(const void *start, size_t size);
+extern void __dma_inv_area_no_dsb(const void *start, size_t size);
+extern void __dma_clean_area_no_dsb(const void *start, size_t size);
+
+extern void dmac_flush_range_no_dsb(const void *start, const void *end);
+extern void dmac_inv_range_no_dsb(const void *start, const void *end);
+extern void dmac_clean_range_no_dsb(const void *start, const void *end);
+
static inline void flush_icache_range(unsigned long start, unsigned long end)
{
caches_clean_inval_pou(start, end);
--- a/arch/arm64/mm/cache.S
+++ b/arch/arm64/mm/cache.S
@@ -164,6 +164,64 @@ SYM_FUNC_END(__pi_dcache_inval_poc)
SYM_FUNC_ALIAS(dcache_inval_poc, __pi_dcache_inval_poc)
/*
+ * __dma_inv_area_no_dsb(start, size)
+ *
+ * This macro does not do "data synchronization barrier". Caller should
+ * do "dsb" after transaction.
+ *
+ * start - virtual start address of region
+ * size - size in question
+ */
+SYM_FUNC_START(__dma_inv_area_no_dsb)
+ add x1, x1, x0
+ dcache_line_size x2, x3
+ sub x3, x2, #1
+ tst x1, x3 // end cache line aligned?
+ bic x1, x1, x3
+ b.eq 1f
+ dc civac, x1 // clean & invalidate D / U line
+1: tst x0, x3 // start cache line aligned?
+ bic x0, x0, x3
+ b.eq 2f
+ dc civac, x0 // clean & invalidate D / U line
+ b 3f
+2: dc ivac, x0 // invalidate D / U line
+3: add x0, x0, x2
+ cmp x0, x1
+ b.lo 2b
+ ret
+SYM_FUNC_END(__dma_inv_area_no_dsb)
+
+/*
+ * __dma_clean_area_no_dsb(start, size)
+ *
+ * his macro does not do "data synchronization barrier". Caller should
+ * o "dsb" after transaction.
+ *
+ * start - virtual start address of region
+ * size - size in question
+ */
+SYM_FUNC_START(__dma_clean_area_no_dsb)
+ dcache_by_line_op_no_dsb cvac, x0, x1, x2, x3
+ ret
+SYM_FUNC_END(__dma_clean_area_no_dsb)
+
+/*
+ * __dma_flush_area_no_dsb(start, size)
+ *
+ * clean & invalidate D / U line
+ * his macro does not do "data synchronization barrier". Caller should
+ * o "dsb" after transaction.
+ *
+ * start - virtual start address of region
+ * size - size in question
+ */
+SYM_FUNC_START(__dma_flush_area_no_dsb)
+ dcache_by_line_op_no_dsb civac, x0, x1, x2, x3
+ ret
+SYM_FUNC_END(__dma_flush_area_no_dsb)
+
+/*
* dcache_clean_poc(start, end)
*
* Ensure that any D-cache lines for the interval [start, end)
--- a/arch/arm64/mm/flush.c
+++ b/arch/arm64/mm/flush.c
@@ -100,3 +100,27 @@ void arch_invalidate_pmem(void *addr, si
}
EXPORT_SYMBOL_GPL(arch_invalidate_pmem);
#endif
+
+void dmac_flush_range_no_dsb(const void *start, const void *end)
+{
+ __dma_flush_area_no_dsb(start, (void *)(end) - (void *)(start));
+}
+EXPORT_SYMBOL(dmac_flush_range_no_dsb);
+
+void dmac_inv_range(const void *start, const void *end)
+{
+ dcache_inval_poc((unsigned long)start, (unsigned long)(end));
+}
+EXPORT_SYMBOL(dmac_inv_range);
+
+void dmac_inv_range_no_dsb(const void *start, const void *end)
+{
+ __dma_inv_area_no_dsb(start, (void *)(end) - (void *)(start));
+}
+EXPORT_SYMBOL(dmac_inv_range_no_dsb);
+
+void dmac_clean_range_no_dsb(const void *start, const void *end)
+{
+ __dma_clean_area_no_dsb(start, (void *)(end) - (void *)(start));
+}
+EXPORT_SYMBOL(dmac_clean_range_no_dsb);

View File

@@ -0,0 +1,143 @@
From 5f63a10caee09a5cec9a0da7f6b9cde39decf0c7 Mon Sep 17 00:00:00 2001
From: Murat Sezgin <quic_msezgin@quicinc.com>
Date: Thu, 11 May 2023 11:54:05 -0700
Subject: [PATCH 269/281] net: Add DSCP remarking feature for HW acceleration.
DSCP remarking is an advanced QoS feature of acceleration
engine. With this feature it is possible to set the accelerated
eggress packets' DSCP values with iptables command.
Change-Id: I7fa8d8a2a87b66b262d54e25f22e9eedd665c456
Signed-off-by: Murat Sezgin <msezgin@codeaurora.org>
Signed-off-by: Murat Sezgin <quic_msezgin@quicinc.com>
---
include/net/netfilter/nf_conntrack_extend.h | 3 +++
net/netfilter/Kconfig | 7 ++++++
net/netfilter/Makefile | 1 +
net/netfilter/nf_conntrack_core.c | 6 +++++
net/netfilter/xt_DSCP.c | 27 ++++++++++++++++++++-
5 files changed, 43 insertions(+), 1 deletion(-)
--- a/include/net/netfilter/nf_conntrack_extend.h
+++ b/include/net/netfilter/nf_conntrack_extend.h
@@ -31,6 +31,9 @@ enum nf_ct_ext_id {
#if IS_ENABLED(CONFIG_NET_ACT_CT)
NF_CT_EXT_ACT_CT,
#endif
+#ifdef CONFIG_NF_CONNTRACK_DSCPREMARK_EXT
+ NF_CT_EXT_DSCPREMARK,
+#endif
NF_CT_EXT_NUM,
};
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -174,6 +174,13 @@ config NF_CONNTRACK_TIMEOUT
If unsure, say `N'.
+config NF_CONNTRACK_DSCPREMARK_EXT
+ bool 'Connection tracking extension for dscp remark target'
+ depends on NETFILTER_ADVANCED
+ help
+ This option enables support for connection tracking extension
+ for dscp remark.
+
config NF_CONNTRACK_TIMESTAMP
bool 'Connection tracking timestamping'
depends on NETFILTER_ADVANCED
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -20,6 +20,7 @@ nf_conntrack-$(CONFIG_DEBUG_INFO_BTF_MOD
else ifeq ($(CONFIG_NF_CONNTRACK),y)
nf_conntrack-$(CONFIG_DEBUG_INFO_BTF) += nf_conntrack_bpf.o
endif
+nf_conntrack-$(CONFIG_NF_CONNTRACK_DSCPREMARK_EXT) += nf_conntrack_dscpremark_ext.o
obj-$(CONFIG_NETFILTER) = netfilter.o
obj-$(CONFIG_NETFILTER_BPF_LINK) += nf_bpf_link.o
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -45,6 +45,9 @@
#include <net/netfilter/nf_conntrack_zones.h>
#include <net/netfilter/nf_conntrack_timestamp.h>
#include <net/netfilter/nf_conntrack_timeout.h>
+#ifdef CONFIG_NF_CONNTRACK_DSCPREMARK_EXT
+#include <net/netfilter/nf_conntrack_dscpremark_ext.h>
+#endif
#include <net/netfilter/nf_conntrack_labels.h>
#include <net/netfilter/nf_conntrack_synproxy.h>
#include <net/netfilter/nf_nat.h>
@@ -1740,6 +1743,9 @@ init_conntrack(struct net *net, struct n
nf_ct_acct_ext_add(ct, GFP_ATOMIC);
nf_ct_tstamp_ext_add(ct, GFP_ATOMIC);
nf_ct_labels_ext_add(ct);
+#ifdef CONFIG_NF_CONNTRACK_DSCPREMARK_EXT
+ nf_ct_dscpremark_ext_add(ct, GFP_ATOMIC);
+#endif
#ifdef CONFIG_NF_CONNTRACK_EVENTS
ecache = tmpl ? nf_ct_ecache_find(tmpl) : NULL;
--- a/net/netfilter/xt_DSCP.c
+++ b/net/netfilter/xt_DSCP.c
@@ -15,6 +15,9 @@
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter/xt_DSCP.h>
+#ifdef CONFIG_NF_CONNTRACK_DSCPREMARK_EXT
+#include <net/netfilter/nf_conntrack_dscpremark_ext.h>
+#endif
MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
MODULE_DESCRIPTION("Xtables: DSCP/TOS field modification");
@@ -31,6 +34,10 @@ dscp_tg(struct sk_buff *skb, const struc
{
const struct xt_DSCP_info *dinfo = par->targinfo;
u_int8_t dscp = ipv4_get_dsfield(ip_hdr(skb)) >> XT_DSCP_SHIFT;
+#ifdef CONFIG_NF_CONNTRACK_DSCPREMARK_EXT
+ struct nf_conn *ct;
+ enum ip_conntrack_info ctinfo;
+#endif
if (dscp != dinfo->dscp) {
if (skb_ensure_writable(skb, sizeof(struct iphdr)))
@@ -39,6 +46,13 @@ dscp_tg(struct sk_buff *skb, const struc
ipv4_change_dsfield(ip_hdr(skb), XT_DSCP_ECN_MASK,
dinfo->dscp << XT_DSCP_SHIFT);
+#ifdef CONFIG_NF_CONNTRACK_DSCPREMARK_EXT
+ ct = nf_ct_get(skb, &ctinfo);
+ if (!ct)
+ return XT_CONTINUE;
+
+ nf_conntrack_dscpremark_ext_set_dscp_rule_valid(ct);
+#endif
}
return XT_CONTINUE;
}
@@ -48,13 +62,24 @@ dscp_tg6(struct sk_buff *skb, const stru
{
const struct xt_DSCP_info *dinfo = par->targinfo;
u_int8_t dscp = ipv6_get_dsfield(ipv6_hdr(skb)) >> XT_DSCP_SHIFT;
-
+#ifdef CONFIG_NF_CONNTRACK_DSCPREMARK_EXT
+ struct nf_conn *ct;
+ enum ip_conntrack_info ctinfo;
+#endif
if (dscp != dinfo->dscp) {
if (skb_ensure_writable(skb, sizeof(struct ipv6hdr)))
return NF_DROP;
ipv6_change_dsfield(ipv6_hdr(skb), XT_DSCP_ECN_MASK,
dinfo->dscp << XT_DSCP_SHIFT);
+
+#ifdef CONFIG_NF_CONNTRACK_DSCPREMARK_EXT
+ ct = nf_ct_get(skb, &ctinfo);
+ if (!ct)
+ return XT_CONTINUE;
+
+ nf_conntrack_dscpremark_ext_set_dscp_rule_valid(ct);
+#endif
}
return XT_CONTINUE;
}

View File

@@ -0,0 +1,339 @@
From 8daa619cff9acc2be5c0161019cd33e486171047 Mon Sep 17 00:00:00 2001
From: Murat Sezgin <msezgin@codeaurora.org>
Date: Tue, 18 Apr 2017 15:48:01 -0700
Subject: [PATCH 270/281] net: conntrack events, support multiple registrant
Change-Id: Iebfb254590fb594f5baf232f849d1b7ae45ef757
Signed-off-by: Zhi Chen <zhichen@codeaurora.org>
Signed-off-by: Murat Sezgin <msezgin@codeaurora.org>
---
include/net/netfilter/nf_conntrack_ecache.h | 45 +++++++++++++-
include/net/netns/conntrack.h | 3 +
net/netfilter/Kconfig | 8 +++
net/netfilter/nf_conntrack_core.c | 3 +
net/netfilter/nf_conntrack_ecache.c | 67 +++++++++++++++++++++
net/netfilter/nf_conntrack_netlink.c | 25 +++++++-
6 files changed, 148 insertions(+), 3 deletions(-)
--- a/include/net/netfilter/nf_conntrack_ecache.h
+++ b/include/net/netfilter/nf_conntrack_ecache.h
@@ -65,13 +65,52 @@ struct nf_ct_event_notifier {
int (*exp_event)(unsigned int events, const struct nf_exp_event *item);
};
+#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
+extern int nf_conntrack_register_notifier(struct net *net,
+ struct notifier_block *nb);
+extern int nf_conntrack_unregister_notifier(struct net *net,
+ struct notifier_block *nb);
+static inline int
+nf_conntrack_eventmask_report(unsigned int eventmask,
+ struct nf_conn *ct,
+ u32 portid,
+ int report)
+{
+ struct nf_conntrack_ecache *e;
+ struct net *net = nf_ct_net(ct);
+
+ e = nf_ct_ecache_find(ct);
+ if (e == NULL)
+ return 0;
+
+ if (nf_ct_is_confirmed(ct)) {
+ struct nf_ct_event item = {
+ .ct = ct,
+ .portid = e->portid ? e->portid : portid,
+ .report = report
+ };
+ /* This is a resent of a destroy event? If so, skip missed */
+ unsigned long missed = e->portid ? 0 : e->missed;
+
+ if (!((eventmask | missed) & e->ctmask))
+ return 0;
+
+ atomic_notifier_call_chain(&net->ct.nf_conntrack_chain,
+ eventmask | missed, &item);
+ }
+
+ return 0;
+}
+#else
void nf_conntrack_register_notifier(struct net *net,
const struct nf_ct_event_notifier *nb);
void nf_conntrack_unregister_notifier(struct net *net);
-void nf_ct_deliver_cached_events(struct nf_conn *ct);
int nf_conntrack_eventmask_report(unsigned int eventmask, struct nf_conn *ct,
u32 portid, int report);
+#endif
+
+void nf_ct_deliver_cached_events(struct nf_conn *ct);
bool nf_ct_ecache_ext_add(struct nf_conn *ct, u16 ctmask, u16 expmask, gfp_t gfp);
#else
@@ -98,11 +137,13 @@ static inline void
nf_conntrack_event_cache(enum ip_conntrack_events event, struct nf_conn *ct)
{
#ifdef CONFIG_NF_CONNTRACK_EVENTS
- struct net *net = nf_ct_net(ct);
struct nf_conntrack_ecache *e;
+#ifndef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
+ struct net *net = nf_ct_net(ct);
if (!rcu_access_pointer(net->ct.nf_conntrack_event_cb))
return;
+#endif
e = nf_ct_ecache_find(ct);
if (e == NULL)
--- a/include/net/netns/conntrack.h
+++ b/include/net/netns/conntrack.h
@@ -104,6 +104,9 @@ struct netns_ct {
u8 sysctl_checksum;
struct ip_conntrack_stat __percpu *stat;
+#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
+ struct atomic_notifier_head nf_conntrack_chain;
+#endif
struct nf_ct_event_notifier __rcu *nf_conntrack_event_cb;
struct nf_ip_net nf_ct_proto;
#if defined(CONFIG_NF_CONNTRACK_LABELS)
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -181,6 +181,14 @@ config NF_CONNTRACK_DSCPREMARK_EXT
This option enables support for connection tracking extension
for dscp remark.
+config NF_CONNTRACK_CHAIN_EVENTS
+ bool "Register multiple callbacks to ct events"
+ depends on NF_CONNTRACK_EVENTS
+ help
+ Support multiple registrations.
+
+ If unsure, say `N'.
+
config NF_CONNTRACK_TIMESTAMP
bool 'Connection tracking timestamping'
depends on NETFILTER_ADVANCED
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -2810,6 +2810,9 @@ int nf_conntrack_init_net(struct net *ne
nf_conntrack_ecache_pernet_init(net);
nf_conntrack_proto_pernet_init(net);
+#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
+ ATOMIC_INIT_NOTIFIER_HEAD(&net->ct.nf_conntrack_chain);
+#endif
return 0;
err_expect:
--- a/net/netfilter/nf_conntrack_ecache.c
+++ b/net/netfilter/nf_conntrack_ecache.c
@@ -16,6 +16,9 @@
#include <linux/vmalloc.h>
#include <linux/stddef.h>
#include <linux/err.h>
+#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
+#include <linux/notifier.h>
+#endif
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/slab.h>
@@ -124,6 +127,7 @@ static void ecache_work(struct work_stru
schedule_delayed_work(&cnet->ecache.dwork, delay);
}
+#ifndef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
static int __nf_conntrack_eventmask_report(struct nf_conntrack_ecache *e,
const u32 events,
const u32 missed,
@@ -198,9 +202,56 @@ int nf_conntrack_eventmask_report(unsign
return ret;
}
EXPORT_SYMBOL_GPL(nf_conntrack_eventmask_report);
+#endif
/* deliver cached events and clear cache entry - must be called with locally
* disabled softirqs */
+#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
+void nf_ct_deliver_cached_events(struct nf_conn *ct)
+{
+ unsigned long events, missed;
+ struct nf_conntrack_ecache *e;
+ struct nf_ct_event item;
+ struct net *net = nf_ct_net(ct);
+ int ret = 0;
+
+ e = nf_ct_ecache_find(ct);
+ if (!e)
+ return;
+
+ events = xchg(&e->cache, 0);
+
+ if (!nf_ct_is_confirmed(ct) || nf_ct_is_dying(ct) || !events)
+ return;
+
+ /*
+ * We make a copy of the missed event cache without taking
+ * the lock, thus we may send missed events twice. However,
+ * this does not harm and it happens very rarely.
+ */
+ missed = e->missed;
+
+ if (!((events | missed) & e->ctmask))
+ return;
+
+ item.ct = ct;
+ item.portid = 0;
+ item.report = 0;
+
+ atomic_notifier_call_chain(&net->ct.nf_conntrack_chain,
+ events | missed, &item);
+
+ if (likely(ret >= 0 && !missed))
+ return;
+
+ spin_lock_bh(&ct->lock);
+ if (ret < 0)
+ e->missed |= events;
+ else
+ e->missed &= ~missed;
+ spin_unlock_bh(&ct->lock);
+}
+#else
void nf_ct_deliver_cached_events(struct nf_conn *ct)
{
struct nf_conntrack_ecache *e;
@@ -226,6 +277,7 @@ void nf_ct_deliver_cached_events(struct
*/
__nf_conntrack_eventmask_report(e, events, e->missed, &item);
}
+#endif
EXPORT_SYMBOL_GPL(nf_ct_deliver_cached_events);
void nf_ct_expect_event_report(enum ip_conntrack_expect_events event,
@@ -258,6 +310,12 @@ out_unlock:
rcu_read_unlock();
}
+#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
+int nf_conntrack_register_notifier(struct net *net, struct notifier_block *nb)
+{
+ return atomic_notifier_chain_register(&net->ct.nf_conntrack_chain, nb);
+}
+#else
void nf_conntrack_register_notifier(struct net *net,
const struct nf_ct_event_notifier *new)
{
@@ -270,8 +328,16 @@ void nf_conntrack_register_notifier(stru
rcu_assign_pointer(net->ct.nf_conntrack_event_cb, new);
mutex_unlock(&nf_ct_ecache_mutex);
}
+#endif
EXPORT_SYMBOL_GPL(nf_conntrack_register_notifier);
+#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
+int nf_conntrack_unregister_notifier(struct net *net, struct notifier_block *nb)
+{
+ return atomic_notifier_chain_unregister(&net->ct.nf_conntrack_chain,
+ nb);
+}
+#else
void nf_conntrack_unregister_notifier(struct net *net)
{
mutex_lock(&nf_ct_ecache_mutex);
@@ -279,6 +345,7 @@ void nf_conntrack_unregister_notifier(st
mutex_unlock(&nf_ct_ecache_mutex);
/* synchronize_rcu() is called after netns pre_exit */
}
+#endif
EXPORT_SYMBOL_GPL(nf_conntrack_unregister_notifier);
void nf_conntrack_ecache_work(struct net *net, enum nf_ct_ecache_state state)
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -28,6 +28,9 @@
#include <linux/netlink.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
+#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
+#include <linux/notifier.h>
+#endif
#include <linux/slab.h>
#include <linux/siphash.h>
@@ -719,18 +722,26 @@ static size_t ctnetlink_nlmsg_size(const
;
}
+#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
+static int ctnetlink_conntrack_event(struct notifier_block *this,
+ unsigned long events, void *ptr)
+#else
static int
ctnetlink_conntrack_event(unsigned int events, const struct nf_ct_event *item)
+#endif
{
const struct nf_conntrack_zone *zone;
struct net *net;
struct nlmsghdr *nlh;
struct nlattr *nest_parms;
- struct nf_conn *ct = item->ct;
struct sk_buff *skb;
unsigned int type;
unsigned int flags = 0, group;
int err;
+#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
+ struct nf_ct_event *item = (struct nf_ct_event *)ptr;
+#endif
+ struct nf_conn *ct = item->ct;
if (events & (1 << IPCT_DESTROY)) {
type = IPCTNL_MSG_CT_DELETE;
@@ -3089,6 +3100,7 @@ nla_put_failure:
}
#ifdef CONFIG_NF_CONNTRACK_EVENTS
+#ifndef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
static int
ctnetlink_expect_event(unsigned int events, const struct nf_exp_event *item)
{
@@ -3138,6 +3150,7 @@ errout:
return 0;
}
#endif
+#endif
static int ctnetlink_exp_done(struct netlink_callback *cb)
{
if (cb->args[1])
@@ -3748,11 +3761,17 @@ static int ctnetlink_stat_exp_cpu(struct
}
#ifdef CONFIG_NF_CONNTRACK_EVENTS
+#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
+static struct notifier_block ctnl_notifier = {
+ .notifier_call = ctnetlink_conntrack_event,
+};
+#else
static struct nf_ct_event_notifier ctnl_notifier = {
.ct_event = ctnetlink_conntrack_event,
.exp_event = ctnetlink_expect_event,
};
#endif
+#endif
static const struct nfnl_callback ctnl_cb[IPCTNL_MSG_MAX] = {
[IPCTNL_MSG_CT_NEW] = {
@@ -3851,8 +3870,12 @@ static int __net_init ctnetlink_net_init
static void ctnetlink_net_pre_exit(struct net *net)
{
#ifdef CONFIG_NF_CONNTRACK_EVENTS
+#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
+ nf_conntrack_unregister_notifier(net, &ctnl_notifier);
+#else
nf_conntrack_unregister_notifier(net);
#endif
+#endif
}
static struct pernet_operations ctnetlink_net_ops = {

View File

@@ -0,0 +1,720 @@
From 691195eec4f741a2e73accae97092cf0a0203a54 Mon Sep 17 00:00:00 2001
From: Ratheesh Kannoth <rkannoth@codeaurora.org>
Date: Fri, 15 May 2020 12:36:11 +0530
Subject: [PATCH] net/bonding: Added acceleration support over LAG interface
The accel support is enabled for the following LAG modes,
1. Balance-Xor (Static LAG)
2. 802.3ad (Dynamic LAG)
Change-Id: I4524902ddec583a2963cb38731c062f216a5386d
Signed-off-by: Shyam Sunder <ssunde@codeaurora.org>
net/bonding: Fix for Load Balancing within bonding (LAG) group
New APIs (without skb) introduced in bonding driver to calculate hash on given
parameters (IP version, src IP, dst IP, src MAC, dst MAC) has issue in creating
flow_key. flow_get_u32_dst is returning 0 for given flow_key because addr_type
is not set correctly. Fix is added to populate addr_type. Test different flows
and verified that the flows are distributed.
Change-Id: Ie54a40f590010ea2994ffc4ace8f4d050258a06f
Signed-off-by: Bhaskar Valaboju <bhaskarv@codeaurora.org>
Signed-off-by: Ratheesh Kannoth <rkannoth@codeaurora.org>
net: bonding: Relocate kernel bond functions
header files included in uapi folder are the interface between
userspace and kernel space. This path declares new bonding
functions in kernel header file instead of uapi header file.
Change-Id: I1b33f07015b79ec4ac702a9079da01f1c2a08bbb
Signed-off-by: Ratheesh Kannoth <rkannoth@codeaurora.org>
---
drivers/net/bonding/bond_3ad.c | 160 ++++++++++++++++-
drivers/net/bonding/bond_main.c | 306 ++++++++++++++++++++++++++++++--
include/net/bond_3ad.h | 7 +-
include/net/bonding.h | 21 +++
4 files changed, 481 insertions(+), 13 deletions(-)
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -116,6 +116,38 @@ static void ad_marker_response_received(
struct port *port);
static void ad_update_actor_keys(struct port *port, bool reset);
+struct bond_cb __rcu *bond_cb;
+
+int bond_register_cb(struct bond_cb *cb)
+{
+ struct bond_cb *lag_cb;
+
+ lag_cb = kzalloc(sizeof(*lag_cb), GFP_ATOMIC | __GFP_NOWARN);
+ if (!lag_cb) {
+ return -1;
+ }
+
+ memcpy((void *)lag_cb, (void *)cb, sizeof(*cb));
+
+ rcu_read_lock();
+ rcu_assign_pointer(bond_cb, lag_cb);
+ rcu_read_unlock();
+ return 0;
+}
+EXPORT_SYMBOL(bond_register_cb);
+
+void bond_unregister_cb(void)
+{
+ struct bond_cb *lag_cb_main;
+
+ rcu_read_lock();
+ lag_cb_main = rcu_dereference(bond_cb);
+ rcu_assign_pointer(bond_cb, NULL);
+ rcu_read_unlock();
+
+ kfree(lag_cb_main);
+}
+EXPORT_SYMBOL(bond_unregister_cb);
/* ================= api to bonding and kernel code ================== */
@@ -1073,6 +1105,28 @@ static void ad_mux_machine(struct port *
ad_disable_collecting_distributing(port,
update_slave_arr);
port->ntt = true;
+
+ /* Send a notificaton about change in state of this
+ * port. We only want to handle case where port moves
+ * from AD_MUX_COLLECTING_DISTRIBUTING ->
+ * AD_MUX_ATTACHED.
+ */
+ if (bond_slave_is_up(port->slave) &&
+ (last_state == AD_MUX_COLLECTING_DISTRIBUTING)) {
+ struct bond_cb *lag_cb_main;
+
+ rcu_read_lock();
+ lag_cb_main = rcu_dereference(bond_cb);
+ if (lag_cb_main &&
+ lag_cb_main->bond_cb_link_down) {
+ struct net_device *dev;
+
+ dev = port->slave->dev;
+ lag_cb_main->bond_cb_link_down(dev);
+ }
+ rcu_read_unlock();
+ }
+
break;
case AD_MUX_COLLECTING_DISTRIBUTING:
port->actor_oper_port_state |= LACP_STATE_COLLECTING;
@@ -1917,6 +1971,7 @@ static void ad_enable_collecting_distrib
bool *update_slave_arr)
{
if (port->aggregator->is_active) {
+ struct bond_cb *lag_cb_main;
slave_dbg(port->slave->bond->dev, port->slave->dev,
"Enabling port %d (LAG %d)\n",
port->actor_port_number,
@@ -1924,6 +1979,14 @@ static void ad_enable_collecting_distrib
__enable_port(port);
/* Slave array needs update */
*update_slave_arr = true;
+
+ rcu_read_lock();
+ lag_cb_main = rcu_dereference(bond_cb);
+
+ if (lag_cb_main && lag_cb_main->bond_cb_link_up)
+ lag_cb_main->bond_cb_link_up(port->slave->dev);
+
+ rcu_read_unlock();
}
}
@@ -2683,6 +2746,102 @@ int bond_3ad_get_active_agg_info(struct
return ret;
}
+/* bond_3ad_get_tx_dev - Calculate egress interface for a given packet,
+ * for a LAG that is configured in 802.3AD mode
+ * @skb: pointer to skb to be egressed
+ * @src_mac: pointer to source L2 address
+ * @dst_mac: pointer to destination L2 address
+ * @src: pointer to source L3 address
+ * @dst: pointer to destination L3 address
+ * @protocol: L3 protocol id from L2 header
+ * @bond_dev: pointer to bond master device
+ *
+ * If @skb is NULL, bond_xmit_hash is used to calculate hash using L2/L3
+ * addresses.
+ *
+ * Returns: Either valid slave device, or NULL otherwise
+ */
+struct net_device *bond_3ad_get_tx_dev(struct sk_buff *skb, u8 *src_mac,
+ u8 *dst_mac, void *src,
+ void *dst, u16 protocol,
+ struct net_device *bond_dev,
+ __be16 *layer4hdr)
+{
+ struct bonding *bond = netdev_priv(bond_dev);
+ struct aggregator *agg;
+ struct ad_info ad_info;
+ struct list_head *iter;
+ struct slave *slave;
+ struct slave *first_ok_slave = NULL;
+ u32 hash = 0;
+ int slaves_in_agg;
+ int slave_agg_no = 0;
+ int agg_id;
+
+ if (__bond_3ad_get_active_agg_info(bond, &ad_info)) {
+ pr_debug("%s: Error: __bond_3ad_get_active_agg_info failed\n",
+ bond_dev->name);
+ return NULL;
+ }
+
+ slaves_in_agg = ad_info.ports;
+ agg_id = ad_info.aggregator_id;
+
+ if (slaves_in_agg == 0) {
+ pr_debug("%s: Error: active aggregator is empty\n",
+ bond_dev->name);
+ return NULL;
+ }
+
+ if (skb) {
+ hash = bond_xmit_hash(bond, skb);
+ slave_agg_no = hash % slaves_in_agg;
+ } else {
+ if (bond->params.xmit_policy != BOND_XMIT_POLICY_LAYER23 &&
+ bond->params.xmit_policy != BOND_XMIT_POLICY_LAYER2 &&
+ bond->params.xmit_policy != BOND_XMIT_POLICY_LAYER34) {
+ pr_debug("%s: Error: Unsupported hash policy for 802.3AD fast path\n",
+ bond_dev->name);
+ return NULL;
+ }
+
+ hash = bond_xmit_hash_without_skb(src_mac, dst_mac,
+ src, dst, protocol,
+ bond_dev, layer4hdr);
+ slave_agg_no = hash % slaves_in_agg;
+ }
+
+ bond_for_each_slave_rcu(bond, slave, iter) {
+ agg = SLAVE_AD_INFO(slave)->port.aggregator;
+ if (!agg || agg->aggregator_identifier != agg_id)
+ continue;
+
+ if (slave_agg_no >= 0) {
+ if (!first_ok_slave && bond_slave_can_tx(slave))
+ first_ok_slave = slave;
+ slave_agg_no--;
+ continue;
+ }
+
+ if (bond_slave_can_tx(slave))
+ return slave->dev;
+ }
+
+ if (slave_agg_no >= 0) {
+ pr_err("%s: Error: Couldn't find a slave to tx on for aggregator ID %d\n",
+ bond_dev->name, agg_id);
+ return NULL;
+ }
+
+ /* we couldn't find any suitable slave after the agg_no, so use the
+ * first suitable found, if found.
+ */
+ if (first_ok_slave)
+ return first_ok_slave->dev;
+
+ return NULL;
+}
+
int bond_3ad_lacpdu_recv(const struct sk_buff *skb, struct bonding *bond,
struct slave *slave)
{
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -210,6 +210,7 @@ atomic_t netpoll_block_tx = ATOMIC_INIT(
#endif
unsigned int bond_net_id __read_mostly;
+static unsigned long bond_id_mask = 0xFFFFFFF0;
static const struct flow_dissector_key flow_keys_bonding_keys[] = {
{
@@ -287,6 +288,19 @@ const char *bond_mode_name(int mode)
return names[mode];
}
+int bond_get_id(struct net_device *bond_dev)
+{
+ struct bonding *bond;
+
+ if (!((bond_dev->priv_flags & IFF_BONDING) &&
+ (bond_dev->flags & IFF_MASTER)))
+ return -EINVAL;
+
+ bond = netdev_priv(bond_dev);
+ return bond->id;
+}
+EXPORT_SYMBOL(bond_get_id);
+
/**
* bond_dev_queue_xmit - Prepare skb for xmit.
*
@@ -1231,6 +1245,21 @@ void bond_change_active_slave(struct bon
if (BOND_MODE(bond) == BOND_MODE_8023AD)
bond_3ad_handle_link_change(new_active, BOND_LINK_UP);
+ if (bond->params.mode == BOND_MODE_XOR) {
+ struct bond_cb *lag_cb_main;
+
+ rcu_read_lock();
+ lag_cb_main = rcu_dereference(bond_cb);
+ if (lag_cb_main &&
+ lag_cb_main->bond_cb_link_up) {
+ struct net_device *dev;
+
+ dev = new_active->dev;
+ lag_cb_main->bond_cb_link_up(dev);
+ }
+ rcu_read_unlock();
+ }
+
if (bond_is_lb(bond))
bond_alb_handle_link_change(bond, new_active, BOND_LINK_UP);
} else {
@@ -1876,6 +1905,7 @@ int bond_enslave(struct net_device *bond
const struct net_device_ops *slave_ops = slave_dev->netdev_ops;
struct slave *new_slave = NULL, *prev_slave;
struct sockaddr_storage ss;
+ struct bond_cb *lag_cb_main;
int link_reporting;
int res = 0, i;
@@ -2325,6 +2355,13 @@ int bond_enslave(struct net_device *bond
bond_is_active_slave(new_slave) ? "an active" : "a backup",
new_slave->link != BOND_LINK_DOWN ? "an up" : "a down");
+ rcu_read_lock();
+ lag_cb_main = rcu_dereference(bond_cb);
+ if (lag_cb_main && lag_cb_main->bond_cb_enslave)
+ lag_cb_main->bond_cb_enslave(slave_dev);
+
+ rcu_read_unlock();
+
/* enslave is successful */
bond_queue_slave_event(new_slave);
return 0;
@@ -2390,6 +2427,13 @@ err_undo_flags:
}
}
+ rcu_read_lock();
+ lag_cb_main = rcu_dereference(bond_cb);
+ if (lag_cb_main && lag_cb_main->bond_cb_enslave)
+ lag_cb_main->bond_cb_enslave(slave_dev);
+
+ rcu_read_unlock();
+
return res;
}
@@ -2411,6 +2455,7 @@ static int __bond_release_one(struct net
struct bonding *bond = netdev_priv(bond_dev);
struct slave *slave, *oldcurrent;
struct sockaddr_storage ss;
+ struct bond_cb *lag_cb_main;
int old_flags = bond_dev->flags;
netdev_features_t old_features = bond_dev->features;
@@ -2433,6 +2478,13 @@ static int __bond_release_one(struct net
bond_set_slave_inactive_flags(slave, BOND_SLAVE_NOTIFY_NOW);
+ rcu_read_lock();
+ lag_cb_main = rcu_dereference(bond_cb);
+ if (lag_cb_main && lag_cb_main->bond_cb_release)
+ lag_cb_main->bond_cb_release(slave_dev);
+
+ rcu_read_unlock();
+
bond_sysfs_slave_del(slave);
/* recompute stats just before removing the slave */
@@ -2761,8 +2813,8 @@ static void bond_miimon_commit(struct bo
struct slave *slave, *primary, *active;
bool do_failover = false;
struct list_head *iter;
-
- ASSERT_RTNL();
+ struct net_device *slave_dev = NULL;
+ struct bond_cb *lag_cb_main;
bond_for_each_slave(bond, slave, iter) {
switch (slave->link_new_state) {
@@ -2800,6 +2852,10 @@ static void bond_miimon_commit(struct bo
bond_set_active_slave(slave);
}
+ if ((bond->params.mode == BOND_MODE_XOR) &&
+ (!slave_dev))
+ slave_dev = slave->dev;
+
slave_info(bond->dev, slave->dev, "link status definitely up, %u Mbps %s duplex\n",
slave->speed == SPEED_UNKNOWN ? 0 : slave->speed,
slave->duplex ? "full" : "half");
@@ -2848,6 +2904,14 @@ static void bond_miimon_commit(struct bo
unblock_netpoll_tx();
}
+ rcu_read_lock();
+ lag_cb_main = rcu_dereference(bond_cb);
+
+ if (slave_dev && lag_cb_main && lag_cb_main->bond_cb_link_up)
+ lag_cb_main->bond_cb_link_up(slave_dev);
+
+ rcu_read_unlock();
+
bond_set_carrier(bond);
}
@@ -4100,7 +4164,216 @@ static inline u32 bond_eth_hash(struct s
return 0;
ep = (struct ethhdr *)(data + mhoff);
- return ep->h_dest[5] ^ ep->h_source[5] ^ be16_to_cpu(ep->h_proto);
+ return ep->h_dest[5] ^ ep->h_source[5];
+}
+
+/* Extract the appropriate headers based on bond's xmit policy */
+static bool bond_flow_dissect_without_skb(struct bonding *bond,
+ u8 *src_mac, u8 *dst_mac,
+ void *psrc, void *pdst,
+ u16 protocol, __be16 *layer4hdr,
+ struct flow_keys *fk)
+{
+ u32 *src = NULL;
+ u32 *dst = NULL;
+
+ fk->ports.ports = 0;
+ src = (uint32_t *)psrc;
+ dst = (uint32_t *)pdst;
+
+ if (protocol == htons(ETH_P_IP)) {
+ /* V4 addresses and address type*/
+ fk->addrs.v4addrs.src = src[0];
+ fk->addrs.v4addrs.dst = dst[0];
+ fk->control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
+ } else if (protocol == htons(ETH_P_IPV6)) {
+ /* V6 addresses and address type*/
+ memcpy(&fk->addrs.v6addrs.src, src, sizeof(struct in6_addr));
+ memcpy(&fk->addrs.v6addrs.dst, dst, sizeof(struct in6_addr));
+ fk->control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
+ } else {
+ return false;
+ }
+ if ((bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER34) &&
+ (layer4hdr))
+ fk->ports.ports = *layer4hdr;
+
+ return true;
+}
+
+/* bond_xmit_hash_without_skb - Applies load balancing algorithm for a packet,
+ * to calculate hash for a given set of L2/L3 addresses. Does not
+ * calculate egress interface.
+ */
+uint32_t bond_xmit_hash_without_skb(u8 *src_mac, u8 *dst_mac,
+ void *psrc, void *pdst, u16 protocol,
+ struct net_device *bond_dev,
+ __be16 *layer4hdr)
+{
+ struct bonding *bond = netdev_priv(bond_dev);
+ struct flow_keys flow;
+ u32 hash = 0;
+
+ if (bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER2 ||
+ !bond_flow_dissect_without_skb(bond, src_mac, dst_mac, psrc,
+ pdst, protocol, layer4hdr, &flow))
+ return (dst_mac[5] ^ src_mac[5]);
+
+ if (bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER23)
+ hash = dst_mac[5] ^ src_mac[5];
+ else if (layer4hdr)
+ hash = (__force u32)flow.ports.ports;
+
+ hash ^= (__force u32)flow_get_u32_dst(&flow) ^
+ (__force u32)flow_get_u32_src(&flow);
+ hash ^= (hash >> 16);
+ hash ^= (hash >> 8);
+
+ return hash;
+}
+
+/* bond_xor_get_tx_dev - Calculate egress interface for a given packet for a LAG
+ * that is configured in balance-xor mode
+ * @skb: pointer to skb to be egressed
+ * @src_mac: pointer to source L2 address
+ * @dst_mac: pointer to destination L2 address
+ * @src: pointer to source L3 address in network order
+ * @dst: pointer to destination L3 address in network order
+ * @protocol: L3 protocol
+ * @bond_dev: pointer to bond master device
+ *
+ * If @skb is NULL, bond_xmit_hash_without_skb is used to calculate hash using
+ * L2/L3 addresses.
+ *
+ * Returns: Either valid slave device, or NULL otherwise
+ */
+static struct net_device *bond_xor_get_tx_dev(struct sk_buff *skb,
+ u8 *src_mac, u8 *dst_mac,
+ void *src, void *dst,
+ u16 protocol,
+ struct net_device *bond_dev,
+ __be16 *layer4hdr)
+{
+ struct bonding *bond = netdev_priv(bond_dev);
+ int slave_cnt = READ_ONCE(bond->slave_cnt);
+ int slave_id = 0, i = 0;
+ u32 hash;
+ struct list_head *iter;
+ struct slave *slave;
+
+ if (slave_cnt == 0) {
+ pr_debug("%s: Error: No slave is attached to the interface\n",
+ bond_dev->name);
+ return NULL;
+ }
+
+ if (skb) {
+ hash = bond_xmit_hash(bond, skb);
+ slave_id = hash % slave_cnt;
+ } else {
+ if (bond->params.xmit_policy != BOND_XMIT_POLICY_LAYER23 &&
+ bond->params.xmit_policy != BOND_XMIT_POLICY_LAYER2 &&
+ bond->params.xmit_policy != BOND_XMIT_POLICY_LAYER34) {
+ pr_debug("%s: Error: Unsupported hash policy for balance-XOR fast path\n",
+ bond_dev->name);
+ return NULL;
+ }
+
+ hash = bond_xmit_hash_without_skb(src_mac, dst_mac, src,
+ dst, protocol, bond_dev,
+ layer4hdr);
+ slave_id = hash % slave_cnt;
+ }
+
+ i = slave_id;
+
+ /* Here we start from the slave with slave_id */
+ bond_for_each_slave_rcu(bond, slave, iter) {
+ if (--i < 0) {
+ if (bond_slave_can_tx(slave))
+ return slave->dev;
+ }
+ }
+
+ /* Here we start from the first slave up to slave_id */
+ i = slave_id;
+ bond_for_each_slave_rcu(bond, slave, iter) {
+ if (--i < 0)
+ break;
+ if (bond_slave_can_tx(slave))
+ return slave->dev;
+ }
+
+ return NULL;
+}
+
+/* bond_get_tx_dev - Calculate egress interface for a given packet.
+ *
+ * Supports 802.3AD and balance-xor modes
+ *
+ * @skb: pointer to skb to be egressed, if valid
+ * @src_mac: pointer to source L2 address
+ * @dst_mac: pointer to destination L2 address
+ * @src: pointer to source L3 address in network order
+ * @dst: pointer to destination L3 address in network order
+ * @protocol: L3 protocol id from L2 header
+ * @bond_dev: pointer to bond master device
+ *
+ * Returns: Either valid slave device, or NULL for un-supported LAG modes
+ */
+struct net_device *bond_get_tx_dev(struct sk_buff *skb, uint8_t *src_mac,
+ u8 *dst_mac, void *src,
+ void *dst, u16 protocol,
+ struct net_device *bond_dev,
+ __be16 *layer4hdr)
+{
+ struct bonding *bond;
+
+ if (!bond_dev)
+ return NULL;
+
+ if (!((bond_dev->priv_flags & IFF_BONDING) &&
+ (bond_dev->flags & IFF_MASTER)))
+ return NULL;
+
+ bond = netdev_priv(bond_dev);
+
+ switch (bond->params.mode) {
+ case BOND_MODE_XOR:
+ return bond_xor_get_tx_dev(skb, src_mac, dst_mac,
+ src, dst, protocol,
+ bond_dev, layer4hdr);
+ case BOND_MODE_8023AD:
+ return bond_3ad_get_tx_dev(skb, src_mac, dst_mac,
+ src, dst, protocol,
+ bond_dev, layer4hdr);
+ default:
+ return NULL;
+ }
+}
+EXPORT_SYMBOL(bond_get_tx_dev);
+
+/* In bond_xmit_xor() , we determine the output device by using a pre-
+ * determined xmit_hash_policy(), If the selected device is not enabled,
+ * find the next active slave.
+ */
+static int bond_xmit_xor(struct sk_buff *skb, struct net_device *dev)
+{
+ struct bonding *bond = netdev_priv(dev);
+ struct net_device *outdev;
+
+ outdev = bond_xor_get_tx_dev(skb, NULL, NULL, NULL,
+ NULL, 0, dev, NULL);
+ if (!outdev)
+ goto out;
+
+ bond_dev_queue_xmit(bond, skb, outdev);
+ goto final;
+out:
+ /* no suitable interface, frame not sent */
+ dev_kfree_skb(skb);
+final:
+ return NETDEV_TX_OK;
}
static bool bond_flow_ip(struct sk_buff *skb, struct flow_keys *fk, const void *data,
@@ -5230,15 +5503,16 @@ static netdev_tx_t bond_3ad_xor_xmit(str
struct net_device *dev)
{
struct bonding *bond = netdev_priv(dev);
- struct bond_up_slave *slaves;
- struct slave *slave;
+ struct net_device *outdev = NULL;
- slaves = rcu_dereference(bond->usable_slaves);
- slave = bond_xmit_3ad_xor_slave_get(bond, skb, slaves);
- if (likely(slave))
- return bond_dev_queue_xmit(bond, skb, slave->dev);
+ outdev = bond_3ad_get_tx_dev(skb, NULL, NULL, NULL,
+ NULL, 0, dev, NULL);
+ if (!outdev) {
+ dev_kfree_skb(skb);
+ return NETDEV_TX_OK;
+ }
- return bond_tx_drop(dev, skb);
+ return bond_dev_queue_xmit(bond, skb, outdev);
}
/* in broadcast mode, we send everything to all usable interfaces. */
@@ -5488,8 +5762,9 @@ static netdev_tx_t __bond_start_xmit(str
return bond_xmit_roundrobin(skb, dev);
case BOND_MODE_ACTIVEBACKUP:
return bond_xmit_activebackup(skb, dev);
- case BOND_MODE_8023AD:
case BOND_MODE_XOR:
+ return bond_xmit_xor(skb, dev);
+ case BOND_MODE_8023AD:
return bond_3ad_xor_xmit(skb, dev);
case BOND_MODE_BROADCAST:
return bond_xmit_broadcast(skb, dev);
@@ -5926,6 +6201,9 @@ static void bond_destructor(struct net_d
if (bond->wq)
destroy_workqueue(bond->wq);
+ if (bond->id != (~0U))
+ clear_bit(bond->id, &bond_id_mask);
+
free_percpu(bond->rr_tx_counter);
}
@@ -6479,6 +6757,11 @@ int bond_create(struct net *net, const c
bond_work_init_all(bond);
+ bond->id = ~0U;
+ if (bond_id_mask != (~0UL)) {
+ bond->id = (u32)ffz(bond_id_mask);
+ set_bit(bond->id, &bond_id_mask);
+ }
out:
rtnl_unlock();
return res;
--- a/include/net/bond_3ad.h
+++ b/include/net/bond_3ad.h
@@ -302,6 +302,12 @@ int bond_3ad_lacpdu_recv(const struct sk
struct slave *slave);
int bond_3ad_set_carrier(struct bonding *bond);
void bond_3ad_update_lacp_rate(struct bonding *bond);
+struct net_device *bond_3ad_get_tx_dev(struct sk_buff *skb, uint8_t *src_mac,
+ uint8_t *dst_mac, void *src,
+ void *dst, uint16_t protocol,
+ struct net_device *bond_dev,
+ __be16 *layer4hdr);
+
void bond_3ad_update_ad_actor_settings(struct bonding *bond);
int bond_3ad_stats_fill(struct sk_buff *skb, struct bond_3ad_stats *stats);
size_t bond_3ad_stats_size(void);
--- a/include/net/bonding.h
+++ b/include/net/bonding.h
@@ -90,6 +90,8 @@
#define BOND_XFRM_FEATURES (NETIF_F_HW_ESP | NETIF_F_HW_ESP_TX_CSUM | \
NETIF_F_GSO_ESP)
+extern struct bond_cb __rcu *bond_cb;
+
#ifdef CONFIG_NET_POLL_CONTROLLER
extern atomic_t netpoll_block_tx;
@@ -261,6 +263,7 @@ struct bonding {
struct mutex ipsec_lock;
#endif /* CONFIG_XFRM_OFFLOAD */
struct bpf_prog *xdp_prog;
+ u32 id;
};
#define bond_slave_get_rcu(dev) \
@@ -683,6 +686,11 @@ struct bond_vlan_tag *bond_verify_device
int level);
int bond_update_slave_arr(struct bonding *bond, struct slave *skipslave);
void bond_slave_arr_work_rearm(struct bonding *bond, unsigned long delay);
+uint32_t bond_xmit_hash_without_skb(uint8_t *src_mac, uint8_t *dst_mac,
+ void *psrc, void *pdst, uint16_t protocol,
+ struct net_device *bond_dev,
+ __be16 *layer4hdr);
+
void bond_work_init_all(struct bonding *bond);
#ifdef CONFIG_PROC_FS
@@ -787,4 +795,17 @@ static inline netdev_tx_t bond_tx_drop(s
return NET_XMIT_DROP;
}
+struct bond_cb {
+ void (*bond_cb_link_up)(struct net_device *slave);
+ void (*bond_cb_link_down)(struct net_device *slave);
+ void (*bond_cb_enslave)(struct net_device *slave);
+ void (*bond_cb_release)(struct net_device *slave);
+ void (*bond_cb_delete_by_slave)(struct net_device *slave);
+ void (*bond_cb_delete_by_mac)(uint8_t *mac_addr);
+};
+
+extern int bond_register_cb(struct bond_cb *cb);
+extern void bond_unregister_cb(void);
+extern int bond_get_id(struct net_device *bond_dev);
+
#endif /* _NET_BONDING_H */

View File

@@ -0,0 +1,10 @@
--- a/net/netfilter/nf_conntrack_ecache.c
+++ b/net/netfilter/nf_conntrack_ecache.c
@@ -324,7 +324,6 @@ void nf_conntrack_register_notifier(stru
mutex_lock(&nf_ct_ecache_mutex);
notify = rcu_dereference_protected(net->ct.nf_conntrack_event_cb,
lockdep_is_held(&nf_ct_ecache_mutex));
- WARN_ON_ONCE(notify);
rcu_assign_pointer(net->ct.nf_conntrack_event_cb, new);
mutex_unlock(&nf_ct_ecache_mutex);
}

View File

@@ -0,0 +1,33 @@
From 337dafaa0d7bf49e25b4ec74ff44ca697abd06bc Mon Sep 17 00:00:00 2001
From: Ken Zhu <quic_guigenz@quicinc.com>
Date: Tue, 2 May 2023 21:39:54 -0700
Subject: [PATCH 213/281] bridge: fix bridge vlan filter toggle issue
when vlan filter is disabled, it could cause new bridge
creation failed if vlan filter setting existing in the
netlink creation message
Change-Id: I02f010e746e94623fda544846d05908a83d14fa2
Signed-off-by: Ken Zhu <quic_guigenz@quicinc.com>
---
net/bridge/br_netlink.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/net/bridge/br_netlink.c
+++ b/net/bridge/br_netlink.c
@@ -1320,6 +1320,7 @@ static int br_changelink(struct net_devi
br_stp_set_bridge_priority(br, priority);
}
+#ifdef CONFIG_BRIDGE_VLAN_FILTERING
if (data[IFLA_BR_VLAN_FILTERING]) {
u8 vlan_filter = nla_get_u8(data[IFLA_BR_VLAN_FILTERING]);
@@ -1328,7 +1329,6 @@ static int br_changelink(struct net_devi
return err;
}
-#ifdef CONFIG_BRIDGE_VLAN_FILTERING
if (data[IFLA_BR_VLAN_PROTOCOL]) {
__be16 vlan_proto = nla_get_be16(data[IFLA_BR_VLAN_PROTOCOL]);

View File

@@ -0,0 +1,165 @@
From b5f89637414ada5125cbc9138f5b27cbfa8fe1b5 Mon Sep 17 00:00:00 2001
From: Murat Sezgin <quic_msezgin@quicinc.com>
Date: Wed, 10 May 2023 13:15:19 -0700
Subject: [PATCH 219/281] bridge: Add new bridge APIs needed for network HW
acceleration
Bridge acceleration hardware needs to perform certain operations,
currently unsupported by the existing bridge code:
*given a certain bridge device and a MAC@, figure out on
which underlying slave port this MAC@ is located
*trigger an FDB entry refresh from outside the bridge code: packets will
not be seen anymore in the host, once a flow has been accelerated.
So the hardware accelerator driver needs to keep track of the accelerated
flows and refresh the MACs accordingly.
*update bridge interface statistics from outside the bridge code:
once acceleration is enabled on a connection, packets will not flow
through the host CPU, so we need the hardware accelerator driver to
maintain the statistics on the host and update them and add whatever
flows through the hardware.
These change adds the corresponding functions, and make it available
to other through EXPORT_SYMBOLS().
Change-Id: I67afb325796004053897d9916e2df91827b65139
Signed-off-by: Murat Sezgin <msezgin@codeaurora.org>
net: bridge: Rework APIs added for network HW acceleration
This change is to rework the bridge APIs based on the feedback from the
chromium community
Change-Id: I92a65f1eb26c6700d871f9deb40bccf302cf18eb
Signed-off-by: Murat Sezgin <msezgin@codeaurora.org>
Signed-off-by: Murat Sezgin <quic_msezgin@quicinc.com>
---
include/linux/if_bridge.h | 8 ++++++
net/bridge/br_fdb.c | 38 ++++++++++++++++++++++++++++
net/bridge/br_if.c | 52 +++++++++++++++++++++++++++++++++++++++
3 files changed, 98 insertions(+)
--- a/include/linux/if_bridge.h
+++ b/include/linux/if_bridge.h
@@ -71,6 +71,14 @@ void brioctl_set(int (*hook)(struct net
void __user *uarg));
int br_ioctl_call(struct net *net, struct net_bridge *br, unsigned int cmd,
struct ifreq *ifr, void __user *uarg);
+extern struct net_device *br_port_dev_get(struct net_device *dev,
+ unsigned char *addr);
+extern void br_refresh_fdb_entry(struct net_device *dev, const char *addr);
+extern void br_dev_update_stats(struct net_device *dev,
+ struct rtnl_link_stats64 *nlstats);
+extern struct net_bridge_fdb_entry *br_fdb_has_entry(struct net_device *dev,
+ const char *addr,
+ __u16 vid);
#if IS_ENABLED(CONFIG_BRIDGE) && IS_ENABLED(CONFIG_BRIDGE_IGMP_SNOOPING)
int br_multicast_list_adjacent(struct net_device *dev,
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -914,6 +914,44 @@ void br_fdb_update(struct net_bridge *br
}
}
+/* Refresh FDB entries for bridge packets being forwarded by offload engines */
+void br_refresh_fdb_entry(struct net_device *dev, const char *addr)
+{
+ struct net_bridge_port *p = br_port_get_rcu(dev);
+
+ if (!p || p->state == BR_STATE_DISABLED)
+ return;
+
+ if (!is_valid_ether_addr(addr)) {
+ pr_info("bridge: Attempt to refresh with invalid ether address %pM\n",
+ addr);
+ return;
+ }
+
+ rcu_read_lock();
+ br_fdb_update(p->br, p, addr, 0, true);
+ rcu_read_unlock();
+}
+EXPORT_SYMBOL_GPL(br_refresh_fdb_entry);
+
+/* Look up the MAC address in the device's bridge fdb table */
+struct net_bridge_fdb_entry *br_fdb_has_entry(struct net_device *dev,
+ const char *addr, __u16 vid)
+{
+ struct net_bridge_port *p = br_port_get_rcu(dev);
+ struct net_bridge_fdb_entry *fdb;
+
+ if (!p || p->state == BR_STATE_DISABLED)
+ return NULL;
+
+ rcu_read_lock();
+ fdb = fdb_find_rcu(&p->br->fdb_hash_tbl, addr, vid);
+ rcu_read_unlock();
+
+ return fdb;
+}
+EXPORT_SYMBOL_GPL(br_fdb_has_entry);
+
/* Dump information about entries, in response to GETNEIGH */
int br_fdb_dump(struct sk_buff *skb,
struct netlink_callback *cb,
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -775,3 +775,59 @@ bool br_port_flag_is_set(const struct ne
return p->flags & flag;
}
EXPORT_SYMBOL_GPL(br_port_flag_is_set);
+
+/* br_port_dev_get()
+ * Using the given addr, identify the port to which it is reachable,
+ * returing a reference to the net device associated with that port.
+ *
+ * NOTE: Return NULL if given dev is not a bridge or the mac has no
+ * associated port.
+ */
+struct net_device *br_port_dev_get(struct net_device *dev, unsigned char *addr)
+{
+ struct net_bridge_fdb_entry *fdbe;
+ struct net_bridge *br;
+ struct net_device *netdev = NULL;
+
+ /* Is this a bridge? */
+ if (!(dev->priv_flags & IFF_EBRIDGE))
+ return NULL;
+
+ br = netdev_priv(dev);
+
+ /* Lookup the fdb entry and get reference to the port dev */
+ rcu_read_lock();
+ fdbe = br_fdb_find_rcu(br, addr, 0);
+ if (fdbe && fdbe->dst) {
+ netdev = fdbe->dst->dev; /* port device */
+ dev_hold(netdev);
+ }
+ rcu_read_unlock();
+ return netdev;
+}
+EXPORT_SYMBOL_GPL(br_port_dev_get);
+
+/* Update bridge statistics for bridge packets processed by offload engines */
+void br_dev_update_stats(struct net_device *dev,
+ struct rtnl_link_stats64 *nlstats)
+{
+ struct net_bridge *br;
+ struct pcpu_sw_netstats *stats;
+
+ /* Is this a bridge? */
+ if (!(dev->priv_flags & IFF_EBRIDGE))
+ return;
+
+ br = netdev_priv(dev);
+ stats = this_cpu_ptr(dev->tstats);
+
+ local_bh_disable();
+ u64_stats_update_begin(&stats->syncp);
+ u64_stats_add(&stats->rx_packets, nlstats->rx_packets);
+ u64_stats_add(&stats->rx_bytes, nlstats->rx_bytes);
+ u64_stats_add(&stats->tx_packets, nlstats->tx_packets);
+ u64_stats_add(&stats->tx_bytes, nlstats->tx_bytes);
+ u64_stats_update_end(&stats->syncp);
+ local_bh_enable();
+}
+EXPORT_SYMBOL_GPL(br_dev_update_stats);

View File

@@ -0,0 +1,99 @@
From ae56f1dceb55a3e8e5fadf9bc109270436e3d8fa Mon Sep 17 00:00:00 2001
From: Murat Sezgin <quic_msezgin@quicinc.com>
Date: Thu, 18 May 2023 21:11:09 -0700
Subject: [PATCH 220/281] net: bridge: Added bridge fdb update notify chain
Registered modules are notified based on two events:
1. Dst port changes for any existing bridge fdb entry
2. Bridge fdb entry ages out/deleted
Change-Id: Iaba8fba6859bcc8e638df4f2e9900c131b1a6d34
Signed-off-by: ratheesh kannoth <rkannoth@codeaurora.org>
Signed-off-by: Murat Sezgin <msezgin@codeaurora.org>
net: bridge : delete fdb entry before callbacks
Ageing timer expires and deletes corresponding fdb entry. Registered
callbacks for br_fdb_update_notifier chains are called one by one.
Since callback invocation is before the deletion of fdb entry,
it may lead to race condition. Fix is to reorder it.
Change-Id: Idefce6d879bfa6104cadc495aa61d164db214c97
Signed-off-by: ratheesh kannoth <rkannoth@codeaurora.org>
Signed-off-by: Murat Sezgin <msezgin@codeaurora.org>
Signed-off-by: Murat Sezgin <quic_msezgin@quicinc.com>
---
include/linux/if_bridge.h | 2 ++
net/bridge/br_fdb.c | 28 ++++++++++++++++++++++++++--
2 files changed, 28 insertions(+), 2 deletions(-)
--- a/include/linux/if_bridge.h
+++ b/include/linux/if_bridge.h
@@ -79,6 +79,8 @@ extern void br_dev_update_stats(struct n
extern struct net_bridge_fdb_entry *br_fdb_has_entry(struct net_device *dev,
const char *addr,
__u16 vid);
+extern void br_fdb_update_register_notify(struct notifier_block *nb);
+extern void br_fdb_update_unregister_notify(struct notifier_block *nb);
#if IS_ENABLED(CONFIG_BRIDGE) && IS_ENABLED(CONFIG_BRIDGE_IGMP_SNOOPING)
int br_multicast_list_adjacent(struct net_device *dev,
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -519,6 +519,20 @@ out:
spin_unlock_bh(&br->hash_lock);
}
+ATOMIC_NOTIFIER_HEAD(br_fdb_update_notifier_list);
+
+void br_fdb_update_register_notify(struct notifier_block *nb)
+{
+ atomic_notifier_chain_register(&br_fdb_update_notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(br_fdb_update_register_notify);
+
+void br_fdb_update_unregister_notify(struct notifier_block *nb)
+{
+ atomic_notifier_chain_unregister(&br_fdb_update_notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(br_fdb_update_unregister_notify);
+
void br_fdb_cleanup(struct work_struct *work)
{
struct net_bridge *br = container_of(work, struct net_bridge,
@@ -527,6 +541,8 @@ void br_fdb_cleanup(struct work_struct *
unsigned long delay = hold_time(br);
unsigned long work_delay = delay;
unsigned long now = jiffies;
+ u8 mac_addr[6];
+
/* this part is tricky, in order to avoid blocking learning and
* consequently forwarding, we rely on rcu to delete objects with
@@ -553,8 +569,12 @@ void br_fdb_cleanup(struct work_struct *
work_delay = min(work_delay, this_timer - now);
} else {
spin_lock_bh(&br->hash_lock);
- if (!hlist_unhashed(&f->fdb_node))
- fdb_delete(br, f, true);
+ if (!hlist_unhashed(&f->fdb_node)) {
+ ether_addr_copy(mac_addr, f->key.addr.addr);
+ fdb_delete(br, f, true);
+ atomic_notifier_call_chain(&br_fdb_update_notifier_list, 0,
+ (void *)mac_addr);
+ }
spin_unlock_bh(&br->hash_lock);
}
}
@@ -886,6 +906,11 @@ void br_fdb_update(struct net_bridge *br
&fdb->flags)))
clear_bit(BR_FDB_ADDED_BY_EXT_LEARN,
&fdb->flags);
+
+ atomic_notifier_call_chain(
+ &br_fdb_update_notifier_list,
+ 0, (void *)addr);
+
/* Clear locked flag when roaming to an
* unlocked port.
*/

View File

@@ -0,0 +1,112 @@
From 449a86c59f4c7c0c58314755b9b638145e8a8d5a Mon Sep 17 00:00:00 2001
From: Murat Sezgin <msezgin@codeaurora.org>
Date: Wed, 11 Mar 2020 11:20:40 -0700
Subject: [PATCH 221/281] Updated the br_port_dev_get function to take an skb
- If the skb is non-NULL, call the br_port_dev_get_hook (if it exists),
to try and fetch the port.
- If there is no skb or no hook, or the hook returns NULL, lookup in FDB
Change-Id: I60df83dfa7a07b39cd30833cba0d4397859711f4
Signed-off-by: Murat Sezgin <msezgin@codeaurora.org>
---
include/linux/if_bridge.h | 9 ++++++++-
net/bridge/br_if.c | 38 ++++++++++++++++++++++++++++++++++----
2 files changed, 42 insertions(+), 5 deletions(-)
--- a/include/linux/if_bridge.h
+++ b/include/linux/if_bridge.h
@@ -72,7 +72,8 @@ void brioctl_set(int (*hook)(struct net
int br_ioctl_call(struct net *net, struct net_bridge *br, unsigned int cmd,
struct ifreq *ifr, void __user *uarg);
extern struct net_device *br_port_dev_get(struct net_device *dev,
- unsigned char *addr);
+ unsigned char *addr,
+ struct sk_buff *skb);
extern void br_refresh_fdb_entry(struct net_device *dev, const char *addr);
extern void br_dev_update_stats(struct net_device *dev,
struct rtnl_link_stats64 *nlstats);
@@ -223,4 +224,10 @@ static inline clock_t br_get_ageing_time
}
#endif
+typedef struct net_bridge_port *br_port_dev_get_hook_t(struct net_device *dev,
+ struct sk_buff *skb);
+extern br_port_dev_get_hook_t __rcu *br_port_dev_get_hook;
+
+typedef void (br_notify_hook_t)(int group, int event, const void *ptr);
+extern br_notify_hook_t __rcu *br_notify_hook;
#endif
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -26,6 +26,10 @@
#include "br_private.h"
+/* Hook for external forwarding logic */
+br_port_dev_get_hook_t __rcu *br_port_dev_get_hook __read_mostly;
+EXPORT_SYMBOL_GPL(br_port_dev_get_hook);
+
/*
* Determine initial path cost based on speed.
* using recommendations from 802.1d standard
@@ -777,13 +781,17 @@ bool br_port_flag_is_set(const struct ne
EXPORT_SYMBOL_GPL(br_port_flag_is_set);
/* br_port_dev_get()
- * Using the given addr, identify the port to which it is reachable,
- * returing a reference to the net device associated with that port.
+ * If a skb is provided, and the br_port_dev_get_hook_t hook exists,
+ * use that to try and determine the egress port for that skb.
+ * If not, or no egress port could be determined, use the given addr
+ * to identify the port to which it is reachable,
+ * returing a reference to the net device associated with that port.
*
* NOTE: Return NULL if given dev is not a bridge or the mac has no
* associated port.
*/
-struct net_device *br_port_dev_get(struct net_device *dev, unsigned char *addr)
+struct net_device *br_port_dev_get(struct net_device *dev, unsigned char *addr,
+ struct sk_buff *skb)
{
struct net_bridge_fdb_entry *fdbe;
struct net_bridge *br;
@@ -793,15 +801,37 @@ struct net_device *br_port_dev_get(struc
if (!(dev->priv_flags & IFF_EBRIDGE))
return NULL;
+ rcu_read_lock();
+
+ /* If the hook exists and the skb isn't NULL, try and get the port */
+ if (skb) {
+ br_port_dev_get_hook_t *port_dev_get_hook;
+
+ port_dev_get_hook = rcu_dereference(br_port_dev_get_hook);
+ if (port_dev_get_hook) {
+ struct net_bridge_port *pdst =
+ __br_get(port_dev_get_hook, NULL, dev, skb);
+ if (pdst) {
+ dev_hold(pdst->dev);
+ netdev = pdst->dev;
+ goto out;
+ }
+ }
+ }
+
+ /* Either there is no hook, or can't
+ * determine the port to use - fall back to using FDB
+ */
+
br = netdev_priv(dev);
/* Lookup the fdb entry and get reference to the port dev */
- rcu_read_lock();
fdbe = br_fdb_find_rcu(br, addr, 0);
if (fdbe && fdbe->dst) {
netdev = fdbe->dst->dev; /* port device */
dev_hold(netdev);
}
+out:
rcu_read_unlock();
return netdev;
}

View File

@@ -0,0 +1,66 @@
From 14b84b541426e1237e33aced57d08a25d1885098 Mon Sep 17 00:00:00 2001
From: Murat Sezgin <msezgin@codeaurora.org>
Date: Tue, 27 Jan 2015 18:06:30 +0000
Subject: [PATCH 222/281] vlan: Add vlan stats update function
Change-Id: Ib1165b37f29d48e5dbcee2c709b2f873dfb3e34d
Signed-off-by: Murat Sezgin <msezgin@codeaurora.org>
---
include/linux/if_vlan.h | 9 +++++++++
net/8021q/vlan_core.c | 20 ++++++++++++++++++++
2 files changed, 29 insertions(+)
--- a/include/linux/if_vlan.h
+++ b/include/linux/if_vlan.h
@@ -143,6 +143,9 @@ extern struct net_device *__vlan_find_de
extern int vlan_for_each(struct net_device *dev,
int (*action)(struct net_device *dev, int vid,
void *arg), void *arg);
+extern void __vlan_dev_update_accel_stats(struct net_device *dev,
+ struct rtnl_link_stats64 *stats);
+
extern struct net_device *vlan_dev_real_dev(const struct net_device *dev);
extern u16 vlan_dev_vlan_id(const struct net_device *dev);
extern __be16 vlan_dev_vlan_proto(const struct net_device *dev);
@@ -236,6 +239,12 @@ extern void vlan_vids_del_by_dev(struct
extern bool vlan_uses_dev(const struct net_device *dev);
#else
+static inline void __vlan_dev_update_accel_stats(struct net_device *dev,
+ struct rtnl_link_stats64 *stats)
+{
+
+}
+
static inline struct net_device *
__vlan_find_dev_deep_rcu(struct net_device *real_dev,
__be16 vlan_proto, u16 vlan_id)
--- a/net/8021q/vlan_core.c
+++ b/net/8021q/vlan_core.c
@@ -72,6 +72,26 @@ bool vlan_do_receive(struct sk_buff **sk
return true;
}
+/* Update the VLAN device with statistics from network offload engines */
+void __vlan_dev_update_accel_stats(struct net_device *dev,
+ struct rtnl_link_stats64 *nlstats)
+{
+ struct vlan_pcpu_stats *stats;
+
+ if (!is_vlan_dev(dev))
+ return;
+
+ stats = this_cpu_ptr(vlan_dev_priv(dev)->vlan_pcpu_stats);
+
+ u64_stats_update_begin(&stats->syncp);
+ u64_stats_add(&stats->rx_packets, nlstats->rx_packets);
+ u64_stats_add(&stats->rx_bytes, nlstats->rx_bytes);
+ u64_stats_add(&stats->tx_packets, nlstats->tx_packets);
+ u64_stats_add(&stats->tx_bytes, nlstats->tx_bytes);
+ u64_stats_update_end(&stats->syncp);
+}
+EXPORT_SYMBOL(__vlan_dev_update_accel_stats);
+
/* Must be invoked with rcu_read_lock. */
struct net_device *__vlan_find_dev_deep_rcu(struct net_device *dev,
__be16 vlan_proto, u16 vlan_id)

View File

@@ -0,0 +1,123 @@
From 84fa3efb7d8eeb1c3f2daf9a3034e2794b3294f9 Mon Sep 17 00:00:00 2001
From: Zhi Chen <zhichen@codeaurora.org>
Date: Mon, 13 Apr 2015 16:39:06 -0700
Subject: [PATCH 223/281] linux: bridge: add patch for IGMP/MLD snooping
Kernel patch for the IGMP/MLD snooping module, which is a replacement
and enhancement of Linux bridge multicast snooping. With the IGMP/MLD
snooping module, we can support IGMPv3/MLDv2 on Linux bridge.
Furthermore, with additional plugins, we can support switch port-based
snooping and WiFi conversion from multicast to unicast.
This patch exported a couple of bridge APIs and added two packet hooks
on the input/output path.
Change-Id: I3507f2b793155856b4dac8ad5937a9fc6d28551d
Signed-off-by: Zhi Chen <zhichen@codeaurora.org>
Signed-off-by: Murat Sezgin <msezgin@codeaurora.org>
---
include/linux/if_bridge.h | 6 ++++++
net/bridge/br_device.c | 5 +++++
net/bridge/br_input.c | 12 +++++++++++-
net/bridge/br_private.h | 5 +++++
4 files changed, 27 insertions(+), 1 deletion(-)
--- a/include/linux/if_bridge.h
+++ b/include/linux/if_bridge.h
@@ -66,11 +66,13 @@ struct br_ip_list {
#define BR_DEFAULT_AGEING_TIME (300 * HZ)
struct net_bridge;
+struct net_bridge_port;
void brioctl_set(int (*hook)(struct net *net, struct net_bridge *br,
unsigned int cmd, struct ifreq *ifr,
void __user *uarg));
int br_ioctl_call(struct net *net, struct net_bridge *br, unsigned int cmd,
struct ifreq *ifr, void __user *uarg);
+
extern struct net_device *br_port_dev_get(struct net_device *dev,
unsigned char *addr,
struct sk_buff *skb);
@@ -230,4 +232,8 @@ extern br_port_dev_get_hook_t __rcu *br_
typedef void (br_notify_hook_t)(int group, int event, const void *ptr);
extern br_notify_hook_t __rcu *br_notify_hook;
+typedef int (br_multicast_handle_hook_t)(const struct net_bridge_port *src,
+ struct sk_buff *skb);
+extern br_multicast_handle_hook_t __rcu *br_multicast_handle_hook;
+
#endif
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -89,6 +89,11 @@ netdev_tx_t br_dev_xmit(struct sk_buff *
if (is_broadcast_ether_addr(dest)) {
br_flood(br, skb, BR_PKT_BROADCAST, false, true, vid);
} else if (is_multicast_ether_addr(dest)) {
+ br_multicast_handle_hook_t *multicast_handle_hook =
+ rcu_dereference(br_multicast_handle_hook);
+ if (!__br_get(multicast_handle_hook, true, NULL, skb))
+ goto out;
+
if (unlikely(netpoll_tx_running(dev))) {
br_flood(br, skb, BR_PKT_MULTICAST, false, true, vid);
goto out;
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -30,7 +30,11 @@ br_netif_receive_skb(struct net *net, st
return netif_receive_skb(skb);
}
-static int br_pass_frame_up(struct sk_buff *skb, bool promisc)
+/* Hook for external Multicast handler */
+br_multicast_handle_hook_t __rcu *br_multicast_handle_hook __read_mostly;
+EXPORT_SYMBOL_GPL(br_multicast_handle_hook);
+
+int br_pass_frame_up(struct sk_buff *skb, bool promisc)
{
struct net_device *indev, *brdev = BR_INPUT_SKB_CB(skb)->brdev;
struct net_bridge *br = netdev_priv(brdev);
@@ -71,6 +75,7 @@ static int br_pass_frame_up(struct sk_bu
dev_net(indev), NULL, skb, indev, NULL,
br_netif_receive_skb);
}
+EXPORT_SYMBOL_GPL(br_pass_frame_up);
/* note: already called with rcu_read_lock */
int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
@@ -85,6 +90,7 @@ int br_handle_frame_finish(struct net *n
struct net_bridge_vlan *vlan;
struct net_bridge *br;
bool promisc;
+ br_multicast_handle_hook_t *multicast_handle_hook;
u16 vid = 0;
u8 state;
@@ -182,6 +188,10 @@ int br_handle_frame_finish(struct net *n
switch (pkt_type) {
case BR_PKT_MULTICAST:
+ multicast_handle_hook = rcu_dereference(br_multicast_handle_hook);
+ if (!__br_get(multicast_handle_hook, true, p, skb))
+ goto out;
+
mdst = br_mdb_get(brmctx, skb, vid);
if ((mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) &&
br_multicast_querier_exists(brmctx, eth_hdr(skb), mdst)) {
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -907,6 +907,7 @@ void br_manage_promisc(struct net_bridge
int nbp_backup_change(struct net_bridge_port *p, struct net_device *backup_dev);
/* br_input.c */
+int br_pass_frame_up(struct sk_buff *skb, bool promisc);
int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb);
rx_handler_func_t *br_get_rx_handler(const struct net_device *dev);
@@ -2268,4 +2269,8 @@ void br_do_suppress_nd(struct sk_buff *s
u16 vid, struct net_bridge_port *p, struct nd_msg *msg);
struct nd_msg *br_is_nd_neigh_msg(struct sk_buff *skb, struct nd_msg *m);
bool br_is_neigh_suppress_enabled(const struct net_bridge_port *p, u16 vid);
+
+#define __br_get(__hook, __default, __args ...) \
+ (__hook ? (__hook(__args)) : (__default))
+
#endif

View File

@@ -0,0 +1,24 @@
From c38b43a2a98eaf2dd3401998e982716e98339907 Mon Sep 17 00:00:00 2001
From: Murat Sezgin <msezgin@codeaurora.org>
Date: Tue, 27 Jan 2015 11:10:26 -0800
Subject: [PATCH 224/281] ipv6: Export ndisc_send_ns() function for public use.
This API is needed to implement a connection
manager for hardware accelaration.
Change-Id: Idcf5fa1d3d3151fa2a5e0c48c6b6cdd10fc335bf
Signed-off-by: Murat Sezgin <msezgin@codeaurora.org>
---
net/ipv6/ndisc.c | 1 +
1 file changed, 1 insertion(+)
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -670,6 +670,7 @@ void ndisc_send_ns(struct net_device *de
if (skb)
ndisc_send_skb(skb, daddr, saddr);
}
+EXPORT_SYMBOL(ndisc_send_ns);
void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr,
const struct in6_addr *daddr)

View File

@@ -0,0 +1,150 @@
From 776142dbbc2a3da1d47d1042822f72ba3127417b Mon Sep 17 00:00:00 2001
From: Murat Sezgin <msezgin@codeaurora.org>
Date: Wed, 10 Feb 2016 15:38:12 -0800
Subject: [PATCH 225/281] net: ipv4/ipv6: Added route table update notify chain
Registered modules are notified for the changes in the
route table.
NOTE: This patch is originally suggested by "Jozsef Kadlecsik"
in the following email chain but never merged to any of the
kernel versions.
http://www.spinics.net/lists/netfilter-devel/msg24239.html
Cc: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Patch-mainline: netfilter-devel@vger.kernel.org
Change-Id: I402710474be0978867dfbbbb8d1a7f8c8f3dab06
Signed-off-by: Murat Sezgin <msezgin@codeaurora.org>
---
include/net/ip6_route.h | 3 +++
include/net/route.h | 3 +++
net/ipv4/fib_trie.c | 19 +++++++++++++++++++
net/ipv6/route.c | 22 +++++++++++++++++++++-
4 files changed, 46 insertions(+), 1 deletion(-)
--- a/include/net/ip6_route.h
+++ b/include/net/ip6_route.h
@@ -215,6 +215,9 @@ void rt6_multipath_rebalance(struct fib6
void rt6_uncached_list_add(struct rt6_info *rt);
void rt6_uncached_list_del(struct rt6_info *rt);
+int rt6_register_notifier(struct notifier_block *nb);
+int rt6_unregister_notifier(struct notifier_block *nb);
+
static inline const struct rt6_info *skb_rt6_info(const struct sk_buff *skb)
{
const struct dst_entry *dst = skb_dst(skb);
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -237,6 +237,9 @@ struct rtable *rt_dst_alloc(struct net_d
unsigned int flags, u16 type, bool noxfrm);
struct rtable *rt_dst_clone(struct net_device *dev, struct rtable *rt);
+int ip_rt_register_notifier(struct notifier_block *nb);
+int ip_rt_unregister_notifier(struct notifier_block *nb);
+
struct in_ifaddr;
void fib_add_ifaddr(struct in_ifaddr *);
void fib_del_ifaddr(struct in_ifaddr *, struct in_ifaddr *);
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -1211,6 +1211,9 @@ static bool fib_valid_key_len(u32 key, u
static void fib_remove_alias(struct trie *t, struct key_vector *tp,
struct key_vector *l, struct fib_alias *old);
+/* Define route change notification chain. */
+static BLOCKING_NOTIFIER_HEAD(iproute_chain);
+
/* Caller must hold RTNL. */
int fib_table_insert(struct net *net, struct fib_table *tb,
struct fib_config *cfg, struct netlink_ext_ack *extack)
@@ -1404,6 +1407,8 @@ int fib_table_insert(struct net *net, st
rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen, new_fa->tb_id,
&cfg->fc_nlinfo, nlflags);
succeeded:
+ blocking_notifier_call_chain(&iproute_chain,
+ RTM_NEWROUTE, fi);
return 0;
out_remove_new_fa:
@@ -1776,6 +1781,8 @@ int fib_table_delete(struct net *net, st
if (fa_to_delete->fa_state & FA_S_ACCESSED)
rt_cache_flush(cfg->fc_nlinfo.nl_net);
+ blocking_notifier_call_chain(&iproute_chain,
+ RTM_DELROUTE, fa_to_delete->fa_info);
fib_release_info(fa_to_delete->fa_info);
alias_free_mem_rcu(fa_to_delete);
return 0;
@@ -2408,6 +2415,18 @@ void __init fib_trie_init(void)
0, SLAB_PANIC | SLAB_ACCOUNT, NULL);
}
+int ip_rt_register_notifier(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_register(&iproute_chain, nb);
+}
+EXPORT_SYMBOL(ip_rt_register_notifier);
+
+int ip_rt_unregister_notifier(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_unregister(&iproute_chain, nb);
+}
+EXPORT_SYMBOL(ip_rt_unregister_notifier);
+
struct fib_table *fib_trie_table(u32 id, struct fib_table *alias)
{
struct fib_table *tb;
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -198,6 +198,9 @@ static void rt6_uncached_list_flush_dev(
}
}
+/* Define route change notification chain. */
+ATOMIC_NOTIFIER_HEAD(ip6route_chain);
+
static inline const void *choose_neigh_daddr(const struct in6_addr *p,
struct sk_buff *skb,
const void *daddr)
@@ -3873,6 +3876,9 @@ int ip6_route_add(struct fib6_config *cf
return PTR_ERR(rt);
err = __ip6_ins_rt(rt, &cfg->fc_nlinfo, extack);
+ if (!err)
+ atomic_notifier_call_chain(&ip6route_chain,
+ RTM_NEWROUTE, rt);
fib6_info_release(rt);
return err;
@@ -3893,7 +3899,9 @@ static int __ip6_del_rt(struct fib6_info
spin_lock_bh(&table->tb6_lock);
err = fib6_del(rt, info);
spin_unlock_bh(&table->tb6_lock);
-
+ if (!err)
+ atomic_notifier_call_chain(&ip6route_chain,
+ RTM_DELROUTE, rt);
out:
fib6_info_release(rt);
return err;
@@ -6356,6 +6364,18 @@ static int ip6_route_dev_notify(struct n
return NOTIFY_OK;
}
+int rt6_register_notifier(struct notifier_block *nb)
+{
+ return atomic_notifier_chain_register(&ip6route_chain, nb);
+}
+EXPORT_SYMBOL(rt6_register_notifier);
+
+int rt6_unregister_notifier(struct notifier_block *nb)
+{
+ return atomic_notifier_chain_unregister(&ip6route_chain, nb);
+}
+EXPORT_SYMBOL(rt6_unregister_notifier);
+
/*
* /proc
*/

View File

@@ -0,0 +1,78 @@
From bbe88f4bc0087f25eb2608f9112d480ce92b33a5 Mon Sep 17 00:00:00 2001
From: Murat Sezgin <msezgin@codeaurora.org>
Date: Wed, 11 Mar 2020 11:58:55 -0700
Subject: [PATCH 226/281] net: patch linux kernel to support shortcut-fe
1, add a new flag 'fast_forwarded' in skb structure.
2, put a hook in '__netif_receive_skb_core' to
deliver packet to shortcut-fe.
Change-Id: Icaa7c172a06df1c3bc89ff89814d1136772fe217
Signed-off-by: Murat Sezgin <msezgin@codeaurora.org>
---
include/linux/skbuff.h | 2 ++
net/core/dev.c | 21 +++++++++++++++++++--
2 files changed, 21 insertions(+), 2 deletions(-)
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -984,6 +984,8 @@ struct sk_buff {
#if IS_ENABLED(CONFIG_IP_SCTP)
__u8 csum_not_inet:1;
#endif
+ __u8 fast_forwarded:1;
+ /* 1 or 3 bit hole */
#if defined(CONFIG_NET_SCHED) || defined(CONFIG_NET_XGRESS)
__u16 tc_index; /* traffic control index */
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -3594,8 +3594,13 @@ static int xmit_one(struct sk_buff *skb,
unsigned int len;
int rc;
- if (dev_nit_active(dev))
- dev_queue_xmit_nit(skb, dev);
+ /* If this skb has been fast forwarded then we don't want it to
+ * go to any taps (by definition we're trying to bypass them).
+ */
+ if (unlikely(!skb->fast_forwarded)) {
+ if (dev_nit_active(dev))
+ dev_queue_xmit_nit(skb, dev);
+ }
#ifdef CONFIG_ETHERNET_PACKET_MANGLE
if (dev->eth_mangle_tx && !(skb = dev->eth_mangle_tx(dev, skb)))
@@ -5365,6 +5370,9 @@ void netdev_rx_handler_unregister(struct
}
EXPORT_SYMBOL_GPL(netdev_rx_handler_unregister);
+int (*athrs_fast_nat_recv)(struct sk_buff *skb) __rcu __read_mostly;
+EXPORT_SYMBOL_GPL(athrs_fast_nat_recv);
+
/*
* Limit the use of PFMEMALLOC reserves to those protocols that implement
* the special handling of PFMEMALLOC skbs.
@@ -5412,6 +5420,7 @@ static int __netif_receive_skb_core(stru
bool deliver_exact = false;
int ret = NET_RX_DROP;
__be16 type;
+ int (*fast_recv)(struct sk_buff *skb);
net_timestamp_check(!READ_ONCE(netdev_tstamp_prequeue), skb);
@@ -5450,6 +5459,14 @@ another_round:
goto out;
}
+ fast_recv = rcu_dereference(athrs_fast_nat_recv);
+ if (fast_recv) {
+ if (fast_recv(skb)) {
+ ret = NET_RX_SUCCESS;
+ goto out;
+ }
+ }
+
if (skb_skip_tc_classify(skb))
goto skip_classify;

View File

@@ -0,0 +1,82 @@
From 781701738687f5cc13ae949410b162a2cdda817f Mon Sep 17 00:00:00 2001
From: Zhi Chen <zhichen@codeaurora.org>
Date: Thu, 27 Aug 2015 16:37:09 -0700
Subject: [PATCH 227/281] bridge: add fdb events in linux bridge
Notify fdb changing events to those modules which are interested in
hosts joining/leaving or bridge port changing. This is required by
RFS feature.
Change-Id: I7b592ba09109e1785a5834b56987a19bc35886fe
Signed-off-by: Zhi Chen <zhichen@codeaurora.org>
Signed-off-by: Murat Sezgin <msezgin@codeaurora.org>
---
include/linux/if_bridge.h | 11 +++++++++++
net/bridge/br_fdb.c | 31 +++++++++++++++++++++++++++++++
2 files changed, 42 insertions(+)
--- a/include/linux/if_bridge.h
+++ b/include/linux/if_bridge.h
@@ -236,4 +236,15 @@ typedef int (br_multicast_handle_hook_t)
struct sk_buff *skb);
extern br_multicast_handle_hook_t __rcu *br_multicast_handle_hook;
+#define BR_FDB_EVENT_ADD 0x01
+#define BR_FDB_EVENT_DEL 0x02
+
+struct br_fdb_event {
+ struct net_device *dev;
+ unsigned char addr[6];
+ unsigned char is_local;
+};
+
+extern void br_fdb_register_notify(struct notifier_block *nb);
+extern void br_fdb_unregister_notify(struct notifier_block *nb);
#endif
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -33,6 +33,20 @@ static const struct rhashtable_params br
static struct kmem_cache *br_fdb_cache __read_mostly;
+ATOMIC_NOTIFIER_HEAD(br_fdb_notifier_list);
+
+void br_fdb_register_notify(struct notifier_block *nb)
+{
+ atomic_notifier_chain_register(&br_fdb_notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(br_fdb_register_notify);
+
+void br_fdb_unregister_notify(struct notifier_block *nb)
+{
+ atomic_notifier_chain_unregister(&br_fdb_notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(br_fdb_unregister_notify);
+
int __init br_fdb_init(void)
{
br_fdb_cache = kmem_cache_create("bridge_fdb_cache",
@@ -195,6 +209,23 @@ static void fdb_notify(struct net_bridge
if (swdev_notify)
br_switchdev_fdb_notify(br, fdb, type);
+ if (fdb->dst) {
+ int event;
+ struct br_fdb_event fdb_event;
+
+ if (type == RTM_NEWNEIGH)
+ event = BR_FDB_EVENT_ADD;
+ else
+ event = BR_FDB_EVENT_DEL;
+
+ fdb_event.dev = fdb->dst->dev;
+ ether_addr_copy(fdb_event.addr, fdb->key.addr.addr);
+ fdb_event.is_local = test_bit(BR_FDB_LOCAL, &fdb->flags);
+ atomic_notifier_call_chain(&br_fdb_notifier_list,
+ event,
+ (void *)&fdb_event);
+ }
+
skb = nlmsg_new(fdb_nlmsg_size(), GFP_ATOMIC);
if (skb == NULL)
goto errout;

View File

@@ -0,0 +1,44 @@
From 8632dd2d78d1935c3eab058017eab4f2d1702ecc Mon Sep 17 00:00:00 2001
From: Murat Sezgin <msezgin@codeaurora.org>
Date: Fri, 24 Apr 2020 10:58:42 -0700
Subject: [PATCH 228/281] inet: vlan: Added an API to return next VLAN device
The new API returns the next dev when a VLAN dev passed
in parameter i.e.
eth0.10.20 -> eth0.10 -> eth0 The new API returns eth0.10
when eth0.10.20 is passed as a parameter.
Change-Id: I743beb0672e8fd0d6562eec8ec88b1e36eec2973
Signed-off-by: Shyam Sunder <ssunde@codeaurora.org>
Signed-off-by: Murat Sezgin <msezgin@codeaurora.org>
---
include/linux/if_vlan.h | 1 +
net/8021q/vlan_core.c | 7 +++++++
2 files changed, 8 insertions(+)
--- a/include/linux/if_vlan.h
+++ b/include/linux/if_vlan.h
@@ -147,6 +147,7 @@ extern void __vlan_dev_update_accel_stat
struct rtnl_link_stats64 *stats);
extern struct net_device *vlan_dev_real_dev(const struct net_device *dev);
+extern struct net_device *vlan_dev_next_dev(const struct net_device *dev);
extern u16 vlan_dev_vlan_id(const struct net_device *dev);
extern __be16 vlan_dev_vlan_proto(const struct net_device *dev);
--- a/net/8021q/vlan_core.c
+++ b/net/8021q/vlan_core.c
@@ -130,6 +130,13 @@ struct net_device *vlan_dev_real_dev(con
}
EXPORT_SYMBOL(vlan_dev_real_dev);
+/* Caller is responsible to hold the reference of the returned device */
+struct net_device *vlan_dev_next_dev(const struct net_device *dev)
+{
+ return vlan_dev_priv(dev)->real_dev;
+}
+EXPORT_SYMBOL(vlan_dev_next_dev);
+
u16 vlan_dev_vlan_id(const struct net_device *dev)
{
return vlan_dev_priv(dev)->vlan_id;

View File

@@ -0,0 +1,41 @@
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -2939,6 +2939,8 @@ enum netdev_cmd {
NETDEV_OFFLOAD_XSTATS_REPORT_USED,
NETDEV_OFFLOAD_XSTATS_REPORT_DELTA,
NETDEV_XDP_FEAT_CHANGE,
+ NETDEV_BR_JOIN,
+ NETDEV_BR_LEAVE,
};
const char *netdev_cmd_to_name(enum netdev_cmd cmd);
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -700,6 +700,7 @@ int br_add_if(struct net_bridge *br, str
br_set_gso_limits(br);
kobject_uevent(&p->kobj, KOBJ_ADD);
+ call_netdevice_notifiers(NETDEV_BR_JOIN, dev);
return 0;
@@ -736,6 +737,8 @@ int br_del_if(struct net_bridge *br, str
if (!p || p->br != br)
return -EINVAL;
+ call_netdevice_notifiers(NETDEV_BR_LEAVE, dev);
+
/* Since more than one interface can be attached to a bridge,
* there still maybe an alternate path for netconsole to use;
* therefore there is no reason for a NETDEV_RELEASE event.
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1699,6 +1699,8 @@ const char *netdev_cmd_to_name(enum netd
N(PRE_CHANGEADDR) N(OFFLOAD_XSTATS_ENABLE) N(OFFLOAD_XSTATS_DISABLE)
N(OFFLOAD_XSTATS_REPORT_USED) N(OFFLOAD_XSTATS_REPORT_DELTA)
N(XDP_FEAT_CHANGE)
+ N(BR_JOIN) N(BR_LEAVE)
+
}
#undef N
return "UNKNOWN_NETDEV_EVENT";

View File

@@ -0,0 +1,215 @@
From 86f006a651d5415d046be00c851d15e86abae6bb Mon Sep 17 00:00:00 2001
From: Murat Sezgin <quic_msezgin@quicinc.com>
Date: Thu, 18 May 2023 21:11:39 -0700
Subject: [PATCH 230/281] bridge: Port Hy-Fi bridging hooks
Introduce two new netfilter hooks. The first allows the Hy-Fi bridging
logic to indicate a different egress port (thereby overriding the FDB).
The other is used for FDB update notifications and port changes.
Change-Id: I21549968c56e6b60d7d08e19ec4a297b937264bf
Signed-off-by: Murat Sezgin <msezgin@codeaurora.org>
Pass MAC address to Hy-Fi bridge
- This may be a skb on the forward or reverse direction of the
connection
- Need to pass the dest address as well as the skb to determine if we
need to calculate the forward or reverse hash
Change-Id: I245855910ac91f73a9e9e6bd3403f01bc662a93a
Signed-off-by: Murat Sezgin <msezgin@codeaurora.org>
Pass serial number to Linux bridge port lookup
- This allows the same ECM lookup function to be used in interface
hierarchy generation and when updating stats (so no difference in
lookup even if the priority field changes)
- If the priority field changes, will update the H-Active entry and
generate a debug log
Change-Id: I392bbc82fab30c345b14e7927b6b0fa119d19a57
Signed-off-by: Murat Sezgin <msezgin@codeaurora.org>
Signed-off-by: Murat Sezgin <quic_msezgin@quicinc.com>
---
include/linux/if_bridge.h | 15 +++++++++++++--
net/bridge/br.c | 4 ++++
net/bridge/br_fdb.c | 2 ++
net/bridge/br_if.c | 6 ++++--
net/bridge/br_input.c | 20 +++++++++++++++++++-
net/bridge/br_netlink.c | 2 ++
net/bridge/br_private.h | 9 +++++++++
7 files changed, 53 insertions(+), 5 deletions(-)
--- a/include/linux/if_bridge.h
+++ b/include/linux/if_bridge.h
@@ -75,7 +75,8 @@ int br_ioctl_call(struct net *net, struc
extern struct net_device *br_port_dev_get(struct net_device *dev,
unsigned char *addr,
- struct sk_buff *skb);
+ struct sk_buff *skb,
+ unsigned int cookie);
extern void br_refresh_fdb_entry(struct net_device *dev, const char *addr);
extern void br_dev_update_stats(struct net_device *dev,
struct rtnl_link_stats64 *nlstats);
@@ -227,7 +228,9 @@ static inline clock_t br_get_ageing_time
#endif
typedef struct net_bridge_port *br_port_dev_get_hook_t(struct net_device *dev,
- struct sk_buff *skb);
+ struct sk_buff *skb,
+ unsigned char *addr,
+ unsigned int cookie);
extern br_port_dev_get_hook_t __rcu *br_port_dev_get_hook;
typedef void (br_notify_hook_t)(int group, int event, const void *ptr);
@@ -247,4 +250,12 @@ struct br_fdb_event {
extern void br_fdb_register_notify(struct notifier_block *nb);
extern void br_fdb_unregister_notify(struct notifier_block *nb);
+
+typedef struct net_bridge_port *br_get_dst_hook_t(
+ const struct net_bridge_port *src,
+ struct sk_buff **skb);
+extern br_get_dst_hook_t __rcu *br_get_dst_hook;
+
+typedef void (br_notify_hook_t)(int group, int event, const void *ptr);
+extern br_notify_hook_t __rcu *br_notify_hook;
#endif
--- a/net/bridge/br.c
+++ b/net/bridge/br.c
@@ -472,6 +472,10 @@ static void __exit br_deinit(void)
br_fdb_fini();
}
+/* Hook for bridge event notifications */
+br_notify_hook_t __rcu *br_notify_hook __read_mostly;
+EXPORT_SYMBOL_GPL(br_notify_hook);
+
module_init(br_init)
module_exit(br_deinit)
MODULE_LICENSE("GPL");
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -237,6 +237,8 @@ static void fdb_notify(struct net_bridge
kfree_skb(skb);
goto errout;
}
+
+ __br_notify(RTNLGRP_NEIGH, type, fdb);
rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);
return;
errout:
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -794,7 +794,8 @@ EXPORT_SYMBOL_GPL(br_port_flag_is_set);
* associated port.
*/
struct net_device *br_port_dev_get(struct net_device *dev, unsigned char *addr,
- struct sk_buff *skb)
+ struct sk_buff *skb,
+ unsigned int cookie)
{
struct net_bridge_fdb_entry *fdbe;
struct net_bridge *br;
@@ -813,7 +814,8 @@ struct net_device *br_port_dev_get(struc
port_dev_get_hook = rcu_dereference(br_port_dev_get_hook);
if (port_dev_get_hook) {
struct net_bridge_port *pdst =
- __br_get(port_dev_get_hook, NULL, dev, skb);
+ __br_get(port_dev_get_hook, NULL, dev, skb,
+ addr, cookie);
if (pdst) {
dev_hold(pdst->dev);
netdev = pdst->dev;
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -34,6 +34,10 @@ br_netif_receive_skb(struct net *net, st
br_multicast_handle_hook_t __rcu *br_multicast_handle_hook __read_mostly;
EXPORT_SYMBOL_GPL(br_multicast_handle_hook);
+/* Hook for external forwarding logic */
+br_get_dst_hook_t __rcu *br_get_dst_hook __read_mostly;
+EXPORT_SYMBOL_GPL(br_get_dst_hook);
+
int br_pass_frame_up(struct sk_buff *skb, bool promisc)
{
struct net_device *indev, *brdev = BR_INPUT_SKB_CB(skb)->brdev;
@@ -91,6 +95,8 @@ int br_handle_frame_finish(struct net *n
struct net_bridge *br;
bool promisc;
br_multicast_handle_hook_t *multicast_handle_hook;
+ struct net_bridge_port *pdst = NULL;
+ br_get_dst_hook_t *get_dst_hook = rcu_dereference(br_get_dst_hook);
u16 vid = 0;
u8 state;
@@ -207,7 +213,13 @@ int br_handle_frame_finish(struct net *n
}
break;
case BR_PKT_UNICAST:
- dst = br_fdb_find_rcu(br, eth_hdr(skb)->h_dest, vid);
+ pdst = __br_get(get_dst_hook, NULL, p, &skb);
+ if (pdst) {
+ if (!skb)
+ goto out;
+ } else {
+ dst = br_fdb_find_rcu(br, eth_hdr(skb)->h_dest, vid);
+ }
break;
default:
break;
@@ -223,12 +235,18 @@ int br_handle_frame_finish(struct net *n
dst->used = now;
br_forward(dst->dst, skb, local_rcv, false);
} else {
+ if (pdst) {
+ br_forward(pdst, skb, local_rcv, false);
+ goto out1;
+ }
+
if (!mcast_hit)
br_flood(br, skb, pkt_type, local_rcv, false, vid);
else
br_multicast_flood(mdst, skb, brmctx, local_rcv, false);
}
+out1:
if (local_rcv)
return br_pass_frame_up(skb, promisc);
--- a/net/bridge/br_netlink.c
+++ b/net/bridge/br_netlink.c
@@ -657,6 +657,8 @@ void br_info_notify(int event, const str
kfree_skb(skb);
goto errout;
}
+
+ __br_notify(RTNLGRP_LINK, event, port);
rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC);
return;
errout:
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -19,6 +19,7 @@
#include <linux/if_vlan.h>
#include <linux/rhashtable.h>
#include <linux/refcount.h>
+#include <linux/export.h>
#define BR_HASH_BITS 8
#define BR_HASH_SIZE (1 << BR_HASH_BITS)
@@ -2273,4 +2274,12 @@ bool br_is_neigh_suppress_enabled(const
#define __br_get(__hook, __default, __args ...) \
(__hook ? (__hook(__args)) : (__default))
+static inline void __br_notify(int group, int type, const void *data)
+{
+ br_notify_hook_t *notify_hook = rcu_dereference(br_notify_hook);
+
+ if (notify_hook)
+ notify_hook(group, type, data);
+}
+
#endif

View File

@@ -0,0 +1,109 @@
From f765b8ae3df6783fed448413937781aa984389ea Mon Sep 17 00:00:00 2001
From: Murat Sezgin <msezgin@codeaurora.org>
Date: Thu, 5 May 2016 14:01:51 -0700
Subject: [PATCH 231/281] neighbour: Add a new neigh mac update notifier
With this new notifier, neighbour subsystem will
provide a neighbour mac address update notification
with both the old and new mac adress. This helps the
other subsystems to do whatever they want with the old
mac address, if they used it in their own purpose.
Change-Id: I86f6f7107b4c840d05bce167594fdd43d7bb0ff3
Signed-off-by: Murat Sezgin <msezgin@codeaurora.org>
---
include/net/neighbour.h | 8 ++++++++
net/core/neighbour.c | 28 +++++++++++++++++++++++++++-
2 files changed, 35 insertions(+), 1 deletion(-)
--- a/include/net/neighbour.h
+++ b/include/net/neighbour.h
@@ -249,6 +249,11 @@ static inline int neigh_parms_family(str
return p->tbl->family;
}
+struct neigh_mac_update {
+ unsigned char old_mac[ALIGN(MAX_ADDR_LEN, sizeof(unsigned long))];
+ unsigned char update_mac[ALIGN(MAX_ADDR_LEN, sizeof(unsigned long))];
+};
+
#define NEIGH_PRIV_ALIGN sizeof(long long)
#define NEIGH_ENTRY_SIZE(size) ALIGN((size), NEIGH_PRIV_ALIGN)
@@ -395,6 +400,9 @@ void __neigh_for_each_release(struct nei
int (*cb)(struct neighbour *));
int neigh_xmit(int fam, struct net_device *, const void *, struct sk_buff *);
+extern void neigh_mac_update_register_notify(struct notifier_block *nb);
+extern void neigh_mac_update_unregister_notify(struct notifier_block *nb);
+
struct neigh_seq_state {
struct seq_net_private p;
struct neigh_table *tbl;
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -1275,6 +1275,20 @@ static void neigh_update_hhs(struct neig
}
}
+ATOMIC_NOTIFIER_HEAD(neigh_mac_update_notifier_list);
+
+void neigh_mac_update_register_notify(struct notifier_block *nb)
+{
+ atomic_notifier_chain_register(&neigh_mac_update_notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(neigh_mac_update_register_notify);
+
+void neigh_mac_update_unregister_notify(struct notifier_block *nb)
+{
+ atomic_notifier_chain_unregister(&neigh_mac_update_notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(neigh_mac_update_unregister_notify);
+
/* Generic update routine.
-- lladdr is new lladdr or NULL, if it is not supplied.
-- new is new state.
@@ -1303,6 +1317,7 @@ static int __neigh_update(struct neighbo
struct net_device *dev;
int err, notify = 0;
u8 old;
+ struct neigh_mac_update nmu;
trace_neigh_update(neigh, lladdr, new, flags, nlmsg_pid);
@@ -1312,6 +1327,8 @@ static int __neigh_update(struct neighbo
old = neigh->nud_state;
err = -EPERM;
+ memset(&nmu, 0, sizeof(struct neigh_mac_update));
+
if (neigh->dead) {
NL_SET_ERR_MSG(extack, "Neighbor entry is now dead");
new = old;
@@ -1353,7 +1370,11 @@ static int __neigh_update(struct neighbo
and a new address is proposed:
- compare new & old
- if they are different, check override flag
+ - copy old and new addresses for neigh update notification
*/
+ memcpy(nmu.old_mac, neigh->ha, dev->addr_len);
+ memcpy(nmu.update_mac, lladdr, dev->addr_len);
+
if ((old & NUD_VALID) &&
!memcmp(lladdr, neigh->ha, dev->addr_len))
lladdr = neigh->ha;
@@ -1476,8 +1497,13 @@ out:
neigh_update_gc_list(neigh);
if (managed_update)
neigh_update_managed_list(neigh);
- if (notify)
+
+ if (notify) {
neigh_update_notify(neigh, nlmsg_pid);
+ atomic_notifier_call_chain(&neigh_mac_update_notifier_list, 0,
+ (struct neigh_mac_update *)&nmu);
+ }
+
trace_neigh_update_done(neigh, err);
return err;
}

View File

@@ -0,0 +1,70 @@
From c1be565d9240421e69de2ff13b53919134c03edd Mon Sep 17 00:00:00 2001
From: Ram Chandra Jangir <rjangir@codeaurora.org>
Date: Sat, 30 Jul 2016 19:31:53 +0530
Subject: [PATCH 232/281] netfilter: iptable: Fix IPv4 default checks
OpenWRT: 610-netfilter_match_bypass_default_checks.patch
This change fixes up the above patch that had some code get dropped
when FFW linux v4.4.6 to v4.4.14
Change-Id: Ic2172192f23b9ccaa7a9d56139d1f09952636396
Signed-off-by: Ram Chandra Jangir <rjangir@codeaurora.org>
---
net/ipv4/netfilter/ip_tables.c | 32 +++++++++++++++++++++++++++++---
1 file changed, 29 insertions(+), 3 deletions(-)
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -524,6 +524,28 @@ static void cleanup_match(struct xt_entr
}
static int
+check_entry(struct ipt_entry *e)
+{
+ const struct xt_entry_target *t;
+
+ if (!ip_checkentry(&e->ip))
+ return -EINVAL;
+
+ ip_checkdefault(&e->ip);
+
+ if (e->target_offset + sizeof(struct xt_entry_target) >
+ e->next_offset)
+ return -EINVAL;
+
+ t = ipt_get_target_c(e);
+
+ if (e->target_offset + t->u.target_size > e->next_offset)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int
check_match(struct xt_entry_match *m, struct xt_mtchk_param *par)
{
const struct ipt_ip *ip = par->entryinfo;
@@ -586,7 +608,9 @@ find_check_entry(struct ipt_entry *e, st
struct xt_mtchk_param mtpar;
struct xt_entry_match *ematch;
- ip_checkdefault(&e->ip);
+ ret = check_entry(e);
+ if (ret)
+ return ret;
if (!xt_percpu_counter_alloc(alloc_state, &e->counters))
return -ENOMEM;
@@ -1382,8 +1406,10 @@ check_compat_entry_size_and_hooks(struct
sizeof(struct compat_xt_entry_target))
return -EINVAL;
- if (!ip_checkentry(&e->ip))
- return -EINVAL;
+ /* For purposes of check_entry casting the compat entry is fine */
+ ret = check_entry((struct ipt_entry *)e);
+ if (ret)
+ return ret;
ret = xt_compat_check_entry_offsets(e, e->elems,
e->target_offset, e->next_offset);

View File

@@ -0,0 +1,26 @@
From 8e6a2101624053c79ea39fe4aed435a3bd5a6f3f Mon Sep 17 00:00:00 2001
From: Murat Sezgin <msezgin@codeaurora.org>
Date: Fri, 24 Apr 2020 10:59:16 -0700
Subject: [PATCH 233/281] net: Export dev_shutdown()
This API is needed by interface drivers to ensure qdiscs are destroyed
before the NSS interfaces are destroyed. Since Linux destroys qdiscs
only at unregister_netdevice(), it is too late for destroying any NSS
qdiscs that may be configured on the interface.
Change-Id: I66a6ec5b5393f9848ff1202e2753c738786c515f
Signed-off-by: Shyam Sunder <ssunde@codeaurora.org>
---
net/sched/sch_generic.c | 1 +
1 file changed, 1 insertion(+)
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -1494,6 +1494,7 @@ void dev_shutdown(struct net_device *dev
WARN_ON(timer_pending(&dev->watchdog_timer));
}
+EXPORT_SYMBOL(dev_shutdown);
/**
* psched_ratecfg_precompute__() - Pre-compute values for reciprocal division

View File

@@ -0,0 +1,182 @@
From a647c9cf03fd82ce5e090891e5ffa68e22dcf88d Mon Sep 17 00:00:00 2001
From: Murat Sezgin <msezgin@codeaurora.org>
Date: Mon, 8 May 2017 11:49:21 -0700
Subject: [PATCH 234/281] OpenWRT: 644-bridge_optimize_netfilter_hooks.patch
This patch applies the following upstreamed
openwrt patch from 3.14 kernel.
commit 76b37c24252b (OpenWrt: apply 644-bridge_optimize_netfilter_hooks.patch)
Change-Id: I4dde201c34717321115c9c067dc10d0b38d6eee6
Signed-off-by: Murat Sezgin <msezgin@codeaurora.org>
---
net/bridge/br_forward.c | 4 ++--
net/bridge/br_input.c | 6 +++---
net/bridge/br_multicast.c | 2 +-
net/bridge/br_netfilter_hooks.c | 17 +++++++++++++++++
net/bridge/br_private.h | 14 ++++++++++++++
net/bridge/br_stp_bpdu.c | 2 +-
6 files changed, 38 insertions(+), 7 deletions(-)
--- a/net/bridge/br_forward.c
+++ b/net/bridge/br_forward.c
@@ -63,7 +63,7 @@ EXPORT_SYMBOL_GPL(br_dev_queue_push_xmit
int br_forward_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
{
skb_clear_tstamp(skb);
- return NF_HOOK(NFPROTO_BRIDGE, NF_BR_POST_ROUTING,
+ return BR_HOOK(NFPROTO_BRIDGE, NF_BR_POST_ROUTING,
net, sk, skb, NULL, skb->dev,
br_dev_queue_push_xmit);
@@ -112,7 +112,7 @@ static void __br_forward(const struct ne
indev = NULL;
}
- NF_HOOK(NFPROTO_BRIDGE, br_hook,
+ BR_HOOK(NFPROTO_BRIDGE, br_hook,
net, NULL, skb, indev, skb->dev,
br_forward_finish);
}
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -75,7 +75,7 @@ int br_pass_frame_up(struct sk_buff *skb
BR_INPUT_SKB_CB(skb)->promisc = promisc;
- return NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN,
+ return BR_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN,
dev_net(indev), NULL, skb, indev, NULL,
br_netif_receive_skb);
}
@@ -433,7 +433,7 @@ static rx_handler_result_t br_handle_fra
* - returns = 0 (stolen/nf_queue)
* Thus return 1 from the okfn() to signal the skb is ok to pass
*/
- if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN,
+ if (BR_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN,
dev_net(skb->dev), NULL, skb, skb->dev, NULL,
br_handle_local_finish) == 1) {
return RX_HANDLER_PASS;
@@ -454,7 +454,7 @@ forward:
if (ether_addr_equal(p->br->dev->dev_addr, dest))
skb->pkt_type = PACKET_HOST;
- if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING,
+ if (BR_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING,
dev_net(skb->dev), NULL, skb, skb->dev, NULL,
br_handle_local_finish) == 1) {
return RX_HANDLER_PASS;
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -1805,7 +1805,7 @@ again_under_lmqt:
skb->dev = pmctx->port->dev;
br_multicast_count(brmctx->br, pmctx->port, skb, igmp_type,
BR_MCAST_DIR_TX);
- NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT,
+ BR_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT,
dev_net(pmctx->port->dev), NULL, skb, NULL, skb->dev,
br_dev_queue_push_xmit);
--- a/net/bridge/br_netfilter_hooks.c
+++ b/net/bridge/br_netfilter_hooks.c
@@ -61,6 +61,7 @@ struct brnf_net {
int call_iptables;
int call_ip6tables;
int call_arptables;
+ int call_ebtables;
/* default value is 0 */
int filter_vlan_tagged;
@@ -77,6 +78,14 @@ struct brnf_net {
#define IS_ARP(skb) \
(!skb_vlan_tag_present(skb) && skb->protocol == htons(ETH_P_ARP))
+bool br_netfilter_run_hooks(struct net *net)
+{
+ struct brnf_net *brnf = net_generic(net, brnf_net_id);
+
+ return brnf->call_iptables | brnf->call_ip6tables | brnf->call_arptables |
+ brnf->call_ebtables;
+}
+
static inline __be16 vlan_proto(const struct sk_buff *skb)
{
if (skb_vlan_tag_present(skb))
@@ -1238,6 +1247,12 @@ static struct ctl_table brnf_table[] = {
.mode = 0644,
.proc_handler = brnf_sysctl_call_tables,
},
+ {
+ .procname = "bridge-nf-call-ebtables",
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = brnf_sysctl_call_tables,
+ },
{ }
};
@@ -1246,6 +1261,7 @@ static inline void br_netfilter_sysctl_d
brnf->call_iptables = 1;
brnf->call_ip6tables = 1;
brnf->call_arptables = 1;
+ brnf->call_ebtables = 0;
brnf->filter_vlan_tagged = 0;
brnf->filter_pppoe_tagged = 0;
brnf->pass_vlan_indev = 0;
@@ -1269,6 +1285,7 @@ static int br_netfilter_sysctl_init_net(
table[3].data = &brnet->filter_vlan_tagged;
table[4].data = &brnet->filter_pppoe_tagged;
table[5].data = &brnet->pass_vlan_indev;
+ table[6].data = &brnet->call_ebtables;
br_netfilter_sysctl_default(brnet);
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -20,6 +20,7 @@
#include <linux/rhashtable.h>
#include <linux/refcount.h>
#include <linux/export.h>
+#include <linux/netfilter.h>
#define BR_HASH_BITS 8
#define BR_HASH_SIZE (1 << BR_HASH_BITS)
@@ -1934,12 +1935,25 @@ extern const struct nf_br_ops __rcu *nf_
int br_nf_core_init(void);
void br_nf_core_fini(void);
void br_netfilter_rtable_init(struct net_bridge *);
+bool br_netfilter_run_hooks(struct net *net);
#else
static inline int br_nf_core_init(void) { return 0; }
static inline void br_nf_core_fini(void) {}
#define br_netfilter_rtable_init(x)
+static inline bool br_netfilter_run_hooks(struct net *net) { return false; }
#endif
+static inline int
+BR_HOOK(uint8_t pf, unsigned int hook, struct net *net, struct sock *sk,
+ struct sk_buff *skb, struct net_device *in, struct net_device *out,
+ int (*okfn)(struct net *, struct sock *, struct sk_buff *))
+{
+ if (!br_netfilter_run_hooks(net))
+ return okfn(net, sk, skb);
+
+ return NF_HOOK(pf, hook, net, sk, skb, in, out, okfn);
+}
+
/* br_stp.c */
void br_set_state(struct net_bridge_port *p, unsigned int state);
struct net_bridge_port *br_get_port(struct net_bridge *br, u16 port_no);
--- a/net/bridge/br_stp_bpdu.c
+++ b/net/bridge/br_stp_bpdu.c
@@ -56,7 +56,7 @@ static void br_send_bpdu(struct net_brid
skb_reset_mac_header(skb);
- NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT,
+ BR_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT,
dev_net(p->dev), NULL, skb, NULL, skb->dev,
br_send_bpdu_finish);
}

View File

@@ -0,0 +1,39 @@
--- a/include/linux/netfilter/nf_conntrack_proto_gre.h
+++ b/include/linux/netfilter/nf_conntrack_proto_gre.h
@@ -30,4 +30,36 @@ void nf_ct_gre_keymap_destroy(struct nf_
bool gre_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff,
struct net *net, struct nf_conntrack_tuple *tuple);
+
+
+/* GRE is a mess: Four different standards */
+struct gre_hdr {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u16 rec:3,
+ srr:1,
+ seq:1,
+ key:1,
+ routing:1,
+ csum:1,
+ version:3,
+ reserved:4,
+ ack:1;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+ __u16 csum:1,
+ routing:1,
+ key:1,
+ seq:1,
+ srr:1,
+ rec:3,
+ ack:1,
+ reserved:4,
+ version:3;
+#else
+#error "Adjust your <asm/byteorder.h> defines"
+#endif
+ __be16 protocol;
+};
+
+
+
#endif /* _CONNTRACK_PROTO_GRE_H */

View File

@@ -0,0 +1,66 @@
From b10ef8fe182915a8af2a0cc2ebca16d45f4aaba1 Mon Sep 17 00:00:00 2001
From: Murat Sezgin <msezgin@codeaurora.org>
Date: Fri, 2 Jun 2017 10:22:27 -0700
Subject: [PATCH 235/281] bridge: Add flag to force netfilter hook evaluation
Add a sysctl (similar to the ones for iptables/ip6tables) to allow user
space to force evaluation of Netfilter hooks registered with the bridge.
This allows custom module's hooks to be invoked without the
iptables/ip6tables/arptables special processing being enabled.
Without this, any such modules will never have their hooks invoked
unless one of the other flags is set via sysctl.
Change-Id: I2875c77525c96c8f69774ab41d5d77e240d88dbb
Signed-off-by: Murat Sezgin <msezgin@codeaurora.org>
---
net/bridge/br_netfilter_hooks.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
--- a/net/bridge/br_netfilter_hooks.c
+++ b/net/bridge/br_netfilter_hooks.c
@@ -62,6 +62,7 @@ struct brnf_net {
int call_ip6tables;
int call_arptables;
int call_ebtables;
+ int call_custom;
/* default value is 0 */
int filter_vlan_tagged;
@@ -83,7 +84,7 @@ bool br_netfilter_run_hooks(struct net *
struct brnf_net *brnf = net_generic(net, brnf_net_id);
return brnf->call_iptables | brnf->call_ip6tables | brnf->call_arptables |
- brnf->call_ebtables;
+ brnf->call_ebtables | brnf->call_custom;
}
static inline __be16 vlan_proto(const struct sk_buff *skb)
@@ -1253,6 +1254,12 @@ static struct ctl_table brnf_table[] = {
.mode = 0644,
.proc_handler = brnf_sysctl_call_tables,
},
+ {
+ .procname = "bridge-nf-call-custom",
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = brnf_sysctl_call_tables,
+ },
{ }
};
@@ -1262,6 +1269,7 @@ static inline void br_netfilter_sysctl_d
brnf->call_ip6tables = 1;
brnf->call_arptables = 1;
brnf->call_ebtables = 0;
+ brnf->call_custom = 0;
brnf->filter_vlan_tagged = 0;
brnf->filter_pppoe_tagged = 0;
brnf->pass_vlan_indev = 0;
@@ -1286,6 +1294,7 @@ static int br_netfilter_sysctl_init_net(
table[4].data = &brnet->filter_pppoe_tagged;
table[5].data = &brnet->pass_vlan_indev;
table[6].data = &brnet->call_ebtables;
+ table[7].data = &brnet->call_custom;
br_netfilter_sysctl_default(brnet);

View File

@@ -0,0 +1,39 @@
From a64c7ddebaa8749d35fc54b7fcb7f1b7ce076da3 Mon Sep 17 00:00:00 2001
From: Zhu Ken <guigenz@codeaurora.org>
Date: Tue, 27 Oct 2015 13:40:51 -0700
Subject: [PATCH 236/281] net: bridge: don't loopback multicast when hairpin
enabled
some virtual service test cases need to enable bridge hairpin.
But hairpin will break the DHCP procedure on lan side as follows :
Because the first DHCP discovery packet is a broadcast packet, so this
packet will be loopbacked to switch port 6 which was connected to bridge
member eth1, this will result in a switch fdb entry whose out port is
switch port 6. Then the DHCP ack packet from our board DHCP server will
be dropped by switch because its destination mac hit above switch fdb.
The out port given by the fdb equals to the income port of DHCP ack
packet, so this packet was dropped by switch.
Here forbade multicast to be loopbacked when hairpin enabled.
resolved some confliction and changed the author to resolve the invalid
email
Change-Id: I4b5b4e71b8034588fc2c32b21a55dfe4cca32987
Signed-off-by: Zhu Ken <guigenz@codeaurora.org>
---
net/bridge/br_forward.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
--- a/net/bridge/br_forward.c
+++ b/net/bridge/br_forward.c
@@ -24,7 +24,8 @@ static inline int should_deliver(const s
struct net_bridge_vlan_group *vg;
vg = nbp_vlan_group_rcu(p);
- return ((p->flags & BR_HAIRPIN_MODE) || skb->dev != p->dev) &&
+ return (((p->flags & BR_HAIRPIN_MODE) && !is_multicast_ether_addr(eth_hdr(skb)->h_dest))
+ || skb->dev != p->dev) &&
(br_mst_is_enabled(p->br) || p->state == BR_STATE_FORWARDING) &&
br_allowed_egress(vg, skb) && nbp_switchdev_allowed_egress(p, skb) &&
!br_skb_isolated(p, skb);

View File

@@ -0,0 +1,61 @@
From 0746a30988584dc8740c8bdc8d75a36452a84ca0 Mon Sep 17 00:00:00 2001
From: Murat Sezgin <msezgin@codeaurora.org>
Date: Tue, 9 Feb 2016 18:00:05 -0800
Subject: [PATCH 237/281] Fixed the br_dev_xmit function to call Hy-Fi hooks
- Previously this wasn't calling the Hy-Fi hooks (meaning that all
locally generated traffic was sent on a FDB selected port, and hence
in a Hy-Fi environment, could be spread across all backhauls)
- Fixed to be the same as the banana kernel, and call the
br_get_dst_hook_t
Change-Id: If5e964f385614beb5ebe9e1083ca947464165b9e
Signed-off-by: Murat Sezgin <msezgin@codeaurora.org>
Signed-off-by: Mughilan Ramajayam <mughilan@codeaurora.org>
---
net/bridge/br_device.c | 20 +++++++++++++++++---
1 file changed, 17 insertions(+), 3 deletions(-)
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -38,6 +38,8 @@ netdev_tx_t br_dev_xmit(struct sk_buff *
struct net_bridge_vlan *vlan;
const unsigned char *dest;
u16 vid = 0;
+ struct net_bridge_port *pdst;
+ br_get_dst_hook_t *get_dst_hook;
if (unlikely(reason != SKB_NOT_DROPPED_YET)) {
kfree_skb_reason(skb, reason);
@@ -85,6 +87,8 @@ netdev_tx_t br_dev_xmit(struct sk_buff *
br_do_suppress_nd(skb, br, vid, NULL, msg);
}
+ get_dst_hook = rcu_dereference(br_get_dst_hook);
+
dest = eth_hdr(skb)->h_dest;
if (is_broadcast_ether_addr(dest)) {
br_flood(br, skb, BR_PKT_BROADCAST, false, true, vid);
@@ -109,10 +113,19 @@ netdev_tx_t br_dev_xmit(struct sk_buff *
br_multicast_flood(mdst, skb, brmctx, false, true);
else
br_flood(br, skb, BR_PKT_MULTICAST, false, true, vid);
- } else if ((dst = br_fdb_find_rcu(br, dest, vid)) != NULL) {
- br_forward(dst->dst, skb, false, true);
} else {
- br_flood(br, skb, BR_PKT_UNICAST, false, true, vid);
+ pdst = __br_get(get_dst_hook, NULL, NULL, &skb);
+ if (pdst) {
+ if (!skb)
+ goto out;
+ br_forward(pdst, skb, false, true);
+ } else {
+ dst = br_fdb_find_rcu(br, dest, vid);
+ if (dst)
+ br_forward(dst->dst, skb, false, true);
+ else
+ br_flood(br, skb, BR_PKT_UNICAST, false, true, vid);
+ }
}
out:
rcu_read_unlock();

View File

@@ -0,0 +1,102 @@
From 70105ee0b32d3c84625fcf33622263dfceb9abc7 Mon Sep 17 00:00:00 2001
From: Murat Sezgin <msezgin@codeaurora.org>
Date: Thu, 12 Mar 2020 17:25:42 -0700
Subject: [PATCH 238/281] bridge: Extend struct br_fdb_event
Send an FDB update event with device information
Change-Id: I67df950c35af944543e31eef2f447494cea8bde1
Signed-off-by: Casey Chen <kexinc@codeaurora.org>
Signed-off-by: Murat Sezgin <msezgin@codeaurora.org>
---
include/linux/if_bridge.h | 7 +++++--
net/bridge/br_fdb.c | 22 ++++++++++++++++++----
2 files changed, 23 insertions(+), 6 deletions(-)
--- a/include/linux/if_bridge.h
+++ b/include/linux/if_bridge.h
@@ -243,13 +243,16 @@ extern br_multicast_handle_hook_t __rcu
#define BR_FDB_EVENT_DEL 0x02
struct br_fdb_event {
+ unsigned char addr[6];
+ unsigned char is_local;
struct net_device *dev;
- unsigned char addr[6];
- unsigned char is_local;
+ struct net_bridge *br;
+ struct net_device *orig_dev;
};
extern void br_fdb_register_notify(struct notifier_block *nb);
extern void br_fdb_unregister_notify(struct notifier_block *nb);
+extern struct net_device *br_fdb_bridge_dev_get_and_hold(struct net_bridge *br);
typedef struct net_bridge_port *br_get_dst_hook_t(
const struct net_bridge_port *src,
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -574,8 +574,7 @@ void br_fdb_cleanup(struct work_struct *
unsigned long delay = hold_time(br);
unsigned long work_delay = delay;
unsigned long now = jiffies;
- u8 mac_addr[6];
-
+ struct br_fdb_event fdb_event;
/* this part is tricky, in order to avoid blocking learning and
* consequently forwarding, we rely on rcu to delete objects with
@@ -603,10 +602,11 @@ void br_fdb_cleanup(struct work_struct *
} else {
spin_lock_bh(&br->hash_lock);
if (!hlist_unhashed(&f->fdb_node)) {
- ether_addr_copy(mac_addr, f->key.addr.addr);
+ memset(&fdb_event, 0, sizeof(fdb_event));
+ ether_addr_copy(fdb_event.addr, f->key.addr.addr);
fdb_delete(br, f, true);
atomic_notifier_call_chain(&br_fdb_update_notifier_list, 0,
- (void *)mac_addr);
+ (void *)&fdb_event);
}
spin_unlock_bh(&br->hash_lock);
}
@@ -903,10 +903,19 @@ static bool __fdb_mark_active(struct net
test_and_clear_bit(BR_FDB_NOTIFY_INACTIVE, &fdb->flags));
}
+/* Get the bridge device */
+struct net_device *br_fdb_bridge_dev_get_and_hold(struct net_bridge *br)
+{
+ dev_hold(br->dev);
+ return br->dev;
+}
+EXPORT_SYMBOL_GPL(br_fdb_bridge_dev_get_and_hold);
+
void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source,
const unsigned char *addr, u16 vid, unsigned long flags)
{
struct net_bridge_fdb_entry *fdb;
+ struct br_fdb_event fdb_event;
/* some users want to always flood. */
if (hold_time(br) == 0)
@@ -932,6 +941,10 @@ void br_fdb_update(struct net_bridge *br
if (unlikely(source != READ_ONCE(fdb->dst) &&
!test_bit(BR_FDB_STICKY, &fdb->flags))) {
br_switchdev_fdb_notify(br, fdb, RTM_DELNEIGH);
+ ether_addr_copy(fdb_event.addr, addr);
+ fdb_event.br = br;
+ fdb_event.orig_dev = fdb->dst->dev;
+ fdb_event.dev = source->dev;
WRITE_ONCE(fdb->dst, source);
fdb_modified = true;
/* Take over HW learned entry */
@@ -942,7 +955,7 @@ void br_fdb_update(struct net_bridge *br
atomic_notifier_call_chain(
&br_fdb_update_notifier_list,
- 0, (void *)addr);
+ 0, (void *)&fdb_event);
/* Clear locked flag when roaming to an
* unlocked port.

View File

@@ -0,0 +1,691 @@
From 002e9122621ca7a3d772c58d1790fac900025bd3 Mon Sep 17 00:00:00 2001
From: Himanshu Joshi <himajosh@codeaurora.org>
Date: Mon, 11 Apr 2016 19:28:47 +0530
Subject: [PATCH] inet: Multicast acceleration support for 6.1
Added APIs for IPv4/v6 Multicast acceleration for 6.1 kernel
Change-Id: Iaa9182ed6643a59645f9b23b6ed53f9fccb3966a
Signed-off-by: Shyam Sunder <ssunde@codeaurora.org>
---
include/linux/mroute.h | 38 +++++++
include/linux/mroute6.h | 41 +++++++
net/ipv4/ipmr.c | 230 ++++++++++++++++++++++++++++++++++++++
net/ipv6/ip6mr.c | 241 +++++++++++++++++++++++++++++++++++++++-
4 files changed, 547 insertions(+), 3 deletions(-)
--- a/include/linux/mroute.h
+++ b/include/linux/mroute.h
@@ -92,4 +92,42 @@ struct rtmsg;
int ipmr_get_route(struct net *net, struct sk_buff *skb,
__be32 saddr, __be32 daddr,
struct rtmsg *rtm, u32 portid);
+
+#define IPMR_MFC_EVENT_UPDATE 1
+#define IPMR_MFC_EVENT_DELETE 2
+
+/*
+ * Callback to registered modules in the event of updates to a multicast group
+ */
+typedef void (*ipmr_mfc_event_offload_callback_t)(__be32 origin, __be32 group,
+ u32 max_dest_dev,
+ u32 dest_dev_idx[],
+ u8 op);
+
+/*
+ * Register the callback used to inform offload modules when updates occur to
+ * MFC. The callback is registered by offload modules
+ */
+extern bool ipmr_register_mfc_event_offload_callback(
+ ipmr_mfc_event_offload_callback_t mfc_offload_cb);
+
+/*
+ * De-Register the callback used to inform offload modules when updates occur
+ * to MFC
+ */
+extern void ipmr_unregister_mfc_event_offload_callback(void);
+
+/*
+ * Find the destination interface list, given a multicast group and source
+ */
+extern int ipmr_find_mfc_entry(struct net *net, __be32 origin, __be32 group,
+ u32 max_dst_cnt, u32 dest_dev[]);
+
+/*
+ * Out-of-band multicast statistics update for flows that are offloaded from
+ * Linux
+ */
+extern int ipmr_mfc_stats_update(struct net *net, __be32 origin, __be32 group,
+ u64 pkts_in, u64 bytes_in,
+ u64 pkts_out, u64 bytes_out);
#endif
--- a/include/linux/mroute6.h
+++ b/include/linux/mroute6.h
@@ -93,10 +93,51 @@ struct mfc6_cache {
#define MFC_ASSERT_THRESH (3*HZ) /* Maximal freq. of asserts */
+#define IP6MR_MFC_EVENT_UPDATE 1
+#define IP6MR_MFC_EVENT_DELETE 2
+
struct rtmsg;
extern int ip6mr_get_route(struct net *net, struct sk_buff *skb,
struct rtmsg *rtm, u32 portid);
+/*
+ * Callback to registered modules in the event of updates to a multicast group
+ */
+typedef void (*ip6mr_mfc_event_offload_callback_t)(struct in6_addr *origin,
+ struct in6_addr *group,
+ u32 max_dest_dev,
+ u32 dest_dev_idx[],
+ uint8_t op);
+
+/*
+ * Register the callback used to inform offload modules when updates occur
+ * to MFC. The callback is registered by offload modules
+ */
+extern bool ip6mr_register_mfc_event_offload_callback(
+ ip6mr_mfc_event_offload_callback_t mfc_offload_cb);
+
+/*
+ * De-Register the callback used to inform offload modules when updates occur
+ * to MFC
+ */
+extern void ip6mr_unregister_mfc_event_offload_callback(void);
+
+/*
+ * Find the destination interface list given a multicast group and source
+ */
+extern int ip6mr_find_mfc_entry(struct net *net, struct in6_addr *origin,
+ struct in6_addr *group, u32 max_dst_cnt,
+ u32 dest_dev[]);
+
+/*
+ * Out-of-band multicast statistics update for flows that are offloaded from
+ * Linux
+ */
+extern int ip6mr_mfc_stats_update(struct net *net, struct in6_addr *origin,
+ struct in6_addr *group, uint64_t pkts_in,
+ uint64_t bytes_in, uint64_t pkts_out,
+ uint64_t bytes_out);
+
#ifdef CONFIG_IPV6_MROUTE
bool mroute6_is_socket(struct net *net, struct sk_buff *skb);
extern int ip6mr_sk_done(struct sock *sk);
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -89,6 +89,9 @@ static struct net_device *vif_dev_read(c
/* Special spinlock for queue of unresolved entries */
static DEFINE_SPINLOCK(mfc_unres_lock);
+/* spinlock for offload */
+static DEFINE_SPINLOCK(lock);
+
/* We return to original Alan's scheme. Hash table of resolved
* entries is changed only in process context and protected
* with weak lock mrt_lock. Queue of unresolved entries is protected
@@ -112,6 +115,9 @@ static void mroute_netlink_event(struct
static void igmpmsg_netlink_event(const struct mr_table *mrt, struct sk_buff *pkt);
static void mroute_clean_tables(struct mr_table *mrt, int flags);
static void ipmr_expire_process(struct timer_list *t);
+static struct mfc_cache *ipmr_cache_find(struct mr_table *mrt, __be32 origin,
+ __be32 mcastgrp);
+static ipmr_mfc_event_offload_callback_t __rcu ipmr_mfc_event_offload_callback;
#ifdef CONFIG_IP_MROUTE_MULTIPLE_TABLES
#define ipmr_for_each_table(mrt, net) \
@@ -233,6 +239,78 @@ static int ipmr_rule_fill(struct fib_rul
return 0;
}
+/* ipmr_sync_entry_update()
+ * Call the registered offload callback to report an update to a multicast
+ * route entry. The callback receives the list of destination interfaces and
+ * the interface count
+ */
+static void ipmr_sync_entry_update(struct mr_table *mrt,
+ struct mfc_cache *cache)
+{
+ int vifi, dest_if_count = 0;
+ u32 dest_dev[MAXVIFS];
+ __be32 origin;
+ __be32 group;
+ ipmr_mfc_event_offload_callback_t offload_update_cb_f;
+
+ memset(dest_dev, 0, sizeof(dest_dev));
+
+ origin = cache->mfc_origin;
+ group = cache->mfc_mcastgrp;
+
+ spin_lock(&mrt_lock);
+ for (vifi = 0; vifi < cache->_c.mfc_un.res.maxvif; vifi++) {
+ if (!((cache->_c.mfc_un.res.ttls[vifi] > 0) &&
+ (cache->_c.mfc_un.res.ttls[vifi] < 255))) {
+ continue;
+ }
+ if (dest_if_count == MAXVIFS) {
+ spin_unlock(&mrt_lock);
+ return;
+ }
+
+ if (!VIF_EXISTS(mrt, vifi)) {
+ spin_unlock(&mrt_lock);
+ return;
+ }
+ dest_dev[dest_if_count] = mrt->vif_table[vifi].dev->ifindex;
+ dest_if_count++;
+ }
+ spin_unlock(&mrt_lock);
+
+ rcu_read_lock();
+ offload_update_cb_f = rcu_dereference(ipmr_mfc_event_offload_callback);
+
+ if (!offload_update_cb_f) {
+ rcu_read_unlock();
+ return;
+ }
+
+ offload_update_cb_f(group, origin, dest_if_count, dest_dev,
+ IPMR_MFC_EVENT_UPDATE);
+ rcu_read_unlock();
+}
+
+/* ipmr_sync_entry_delete()
+ * Call the registered offload callback to inform of a multicast route entry
+ * delete event
+ */
+static void ipmr_sync_entry_delete(u32 origin, u32 group)
+{
+ ipmr_mfc_event_offload_callback_t offload_update_cb_f;
+
+ rcu_read_lock();
+ offload_update_cb_f = rcu_dereference(ipmr_mfc_event_offload_callback);
+
+ if (!offload_update_cb_f) {
+ rcu_read_unlock();
+ return;
+ }
+
+ offload_update_cb_f(group, origin, 0, NULL, IPMR_MFC_EVENT_DELETE);
+ rcu_read_unlock();
+}
+
static const struct fib_rules_ops __net_initconst ipmr_rules_ops_template = {
.family = RTNL_FAMILY_IPMR,
.rule_size = sizeof(struct ipmr_rule),
@@ -246,6 +324,154 @@ static const struct fib_rules_ops __net_
.owner = THIS_MODULE,
};
+/* ipmr_register_mfc_event_offload_callback()
+ * Register the IPv4 Multicast update offload callback with IPMR
+ */
+bool ipmr_register_mfc_event_offload_callback(
+ ipmr_mfc_event_offload_callback_t mfc_offload_cb)
+{
+ ipmr_mfc_event_offload_callback_t offload_update_cb_f;
+
+ rcu_read_lock();
+ offload_update_cb_f = rcu_dereference(ipmr_mfc_event_offload_callback);
+
+ if (offload_update_cb_f) {
+ rcu_read_unlock();
+ return false;
+ }
+ rcu_read_unlock();
+
+ spin_lock(&lock);
+ rcu_assign_pointer(ipmr_mfc_event_offload_callback, mfc_offload_cb);
+ spin_unlock(&lock);
+ synchronize_rcu();
+ return true;
+}
+EXPORT_SYMBOL(ipmr_register_mfc_event_offload_callback);
+
+/* ipmr_unregister_mfc_event_offload_callback()
+ * De-register the IPv4 Multicast update offload callback with IPMR
+ */
+void ipmr_unregister_mfc_event_offload_callback(void)
+{
+ spin_lock(&lock);
+ rcu_assign_pointer(ipmr_mfc_event_offload_callback, NULL);
+ spin_unlock(&lock);
+ synchronize_rcu();
+}
+EXPORT_SYMBOL(ipmr_unregister_mfc_event_offload_callback);
+
+/* ipmr_find_mfc_entry()
+ * Returns destination interface list for a particular multicast flow, and
+ * the number of interfaces in the list
+ */
+int ipmr_find_mfc_entry(struct net *net, __be32 origin, __be32 group,
+ u32 max_dest_cnt, u32 dest_dev[])
+{
+ int vifi, dest_if_count = 0;
+ struct mr_table *mrt;
+ struct mfc_cache *cache;
+
+ mrt = ipmr_get_table(net, RT_TABLE_DEFAULT);
+ if (!mrt)
+ return -ENOENT;
+
+ rcu_read_lock();
+ cache = ipmr_cache_find(mrt, origin, group);
+ if (!cache) {
+ rcu_read_unlock();
+ return -ENOENT;
+ }
+
+ spin_lock(&mrt_lock);
+ for (vifi = 0; vifi < cache->_c.mfc_un.res.maxvif; vifi++) {
+ if (!((cache->_c.mfc_un.res.ttls[vifi] > 0) &&
+ (cache->_c.mfc_un.res.ttls[vifi] < 255))) {
+ continue;
+ }
+
+ /* We have another valid destination interface entry. Check if
+ * the number of the destination interfaces for the route is
+ * exceeding the size of the array given to us
+ */
+ if (dest_if_count == max_dest_cnt) {
+ spin_unlock(&mrt_lock);
+ rcu_read_unlock();
+ return -EINVAL;
+ }
+
+ if (!VIF_EXISTS(mrt, vifi)) {
+ spin_unlock(&mrt_lock);
+ rcu_read_unlock();
+ return -EINVAL;
+ }
+
+ dest_dev[dest_if_count] = mrt->vif_table[vifi].dev->ifindex;
+ dest_if_count++;
+ }
+ spin_unlock(&mrt_lock);
+ rcu_read_unlock();
+
+ return dest_if_count;
+}
+EXPORT_SYMBOL(ipmr_find_mfc_entry);
+
+/* ipmr_mfc_stats_update()
+ * Update the MFC/VIF statistics for offloaded flows
+ */
+int ipmr_mfc_stats_update(struct net *net, __be32 origin, __be32 group,
+ u64 pkts_in, u64 bytes_in,
+ u64 pkts_out, u64 bytes_out)
+{
+ int vif, vifi;
+ struct mr_table *mrt;
+ struct mfc_cache *cache;
+
+ mrt = ipmr_get_table(net, RT_TABLE_DEFAULT);
+ if (!mrt)
+ return -ENOENT;
+
+ rcu_read_lock();
+ cache = ipmr_cache_find(mrt, origin, group);
+ if (!cache) {
+ rcu_read_unlock();
+ return -ENOENT;
+ }
+
+ vif = cache->_c.mfc_parent;
+
+ spin_lock(&mrt_lock);
+ if (!VIF_EXISTS(mrt, vif)) {
+ spin_unlock(&mrt_lock);
+ rcu_read_unlock();
+ return -EINVAL;
+ }
+
+ mrt->vif_table[vif].pkt_in += pkts_in;
+ mrt->vif_table[vif].bytes_in += bytes_in;
+ atomic_long_add(pkts_out, &cache->_c.mfc_un.res.pkt);
+ atomic_long_add(bytes_out, &cache->_c.mfc_un.res.bytes);
+
+ for (vifi = cache->_c.mfc_un.res.minvif;
+ vifi < cache->_c.mfc_un.res.maxvif; vifi++) {
+ if ((cache->_c.mfc_un.res.ttls[vifi] > 0) &&
+ (cache->_c.mfc_un.res.ttls[vifi] < 255)) {
+ if (!VIF_EXISTS(mrt, vifi)) {
+ spin_unlock(&mrt_lock);
+ rcu_read_unlock();
+ return -EINVAL;
+ }
+ mrt->vif_table[vifi].pkt_out += pkts_out;
+ mrt->vif_table[vifi].bytes_out += bytes_out;
+ }
+ }
+ spin_unlock(&mrt_lock);
+ rcu_read_unlock();
+
+ return 0;
+}
+EXPORT_SYMBOL(ipmr_mfc_stats_update);
+
static int __net_init ipmr_rules_init(struct net *net)
{
struct fib_rules_ops *ops;
@@ -1203,6 +1429,8 @@ static int ipmr_mfc_delete(struct mr_tab
call_ipmr_mfc_entry_notifiers(net, FIB_EVENT_ENTRY_DEL, c, mrt->id);
mroute_netlink_event(mrt, c, RTM_DELROUTE);
mr_cache_put(&c->_c);
+ /* Inform offload modules of the delete event */
+ ipmr_sync_entry_delete(c->mfc_origin, c->mfc_mcastgrp);
return 0;
}
@@ -1233,6 +1461,8 @@ static int ipmr_mfc_add(struct net *net,
call_ipmr_mfc_entry_notifiers(net, FIB_EVENT_ENTRY_REPLACE, c,
mrt->id);
mroute_netlink_event(mrt, c, RTM_NEWROUTE);
+ /* Inform offload modules of the update event */
+ ipmr_sync_entry_update(mrt, c);
return 0;
}
--- a/net/ipv6/ip6mr.c
+++ b/net/ipv6/ip6mr.c
@@ -74,6 +74,9 @@ static struct net_device *vif_dev_read(c
/* Special spinlock for queue of unresolved entries */
static DEFINE_SPINLOCK(mfc_unres_lock);
+/* Spinlock for offload */
+static DEFINE_SPINLOCK(lock);
+
/* We return to original Alan's scheme. Hash table of resolved
entries is changed only in process context and protected
with weak lock mrt_lock. Queue of unresolved entries is protected
@@ -101,12 +104,15 @@ static int ip6mr_rtm_dumproute(struct sk
struct netlink_callback *cb);
static void mroute_clean_tables(struct mr_table *mrt, int flags);
static void ipmr_expire_process(struct timer_list *t);
+static struct mfc6_cache *ip6mr_cache_find(struct mr_table *mrt,
+ const struct in6_addr *origin,
+ const struct in6_addr *mcastgrp);
+static ip6mr_mfc_event_offload_callback_t __rcu
+ ip6mr_mfc_event_offload_callback;
#ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES
#define ip6mr_for_each_table(mrt, net) \
- list_for_each_entry_rcu(mrt, &net->ipv6.mr6_tables, list, \
- lockdep_rtnl_is_held() || \
- list_empty(&net->ipv6.mr6_tables))
+ list_for_each_entry_rcu(mrt, &net->ipv6.mr6_tables, list)
static struct mr_table *ip6mr_mr_table_iter(struct net *net,
struct mr_table *mrt)
@@ -387,6 +393,82 @@ static struct mfc6_cache_cmp_arg ip6mr_m
.mf6c_mcastgrp = IN6ADDR_ANY_INIT,
};
+/* ip6mr_sync_entry_update()
+ * Call the registered offload callback to report an update to a multicast
+ * route entry. The callback receives the list of destination interfaces and
+ * the interface count
+ */
+static void ip6mr_sync_entry_update(struct mr_table *mrt,
+ struct mfc6_cache *cache)
+{
+ int vifi, dest_if_count = 0;
+ u32 dest_dev[MAXMIFS];
+ struct in6_addr mc_origin, mc_group;
+ ip6mr_mfc_event_offload_callback_t offload_update_cb_f;
+
+ memset(dest_dev, 0, sizeof(dest_dev));
+
+ spin_lock(&mrt_lock);
+
+ for (vifi = 0; vifi < cache->_c.mfc_un.res.maxvif; vifi++) {
+ if (!((cache->_c.mfc_un.res.ttls[vifi] > 0) &&
+ (cache->_c.mfc_un.res.ttls[vifi] < 255))) {
+ continue;
+ }
+
+ if (dest_if_count == MAXMIFS) {
+ spin_unlock(&mrt_lock);
+ return;
+ }
+
+ if (!VIF_EXISTS(mrt, vifi)) {
+ spin_unlock(&mrt_lock);
+ return;
+ }
+
+ dest_dev[dest_if_count] = mrt->vif_table[vifi].dev->ifindex;
+ dest_if_count++;
+ }
+
+ memcpy(&mc_origin, &cache->mf6c_origin, sizeof(struct in6_addr));
+ memcpy(&mc_group, &cache->mf6c_mcastgrp, sizeof(struct in6_addr));
+ spin_unlock(&mrt_lock);
+
+ rcu_read_lock();
+ offload_update_cb_f = rcu_dereference(ip6mr_mfc_event_offload_callback);
+
+ if (!offload_update_cb_f) {
+ rcu_read_unlock();
+ return;
+ }
+
+ offload_update_cb_f(&mc_group, &mc_origin, dest_if_count, dest_dev,
+ IP6MR_MFC_EVENT_UPDATE);
+ rcu_read_unlock();
+}
+
+/* ip6mr_sync_entry_delete()
+ * Call the registered offload callback to inform of a multicast route entry
+ * delete event
+ */
+static void ip6mr_sync_entry_delete(struct in6_addr *mc_origin,
+ struct in6_addr *mc_group)
+{
+ ip6mr_mfc_event_offload_callback_t offload_update_cb_f;
+
+ rcu_read_lock();
+ offload_update_cb_f = rcu_dereference(ip6mr_mfc_event_offload_callback);
+
+ if (!offload_update_cb_f) {
+ rcu_read_unlock();
+ return;
+ }
+
+ offload_update_cb_f(mc_group, mc_origin, 0, NULL,
+ IP6MR_MFC_EVENT_DELETE);
+ rcu_read_unlock();
+}
+
static struct mr_table_ops ip6mr_mr_table_ops = {
.rht_params = &ip6mr_rht_params,
.cmparg_any = &ip6mr_mr_table_ops_cmparg_any,
@@ -711,6 +793,149 @@ static int call_ip6mr_mfc_entry_notifier
&mfc->_c, tb_id, &net->ipv6.ipmr_seq);
}
+/* ip6mr_register_mfc_event_offload_callback()
+ * Register the IPv6 multicast update callback for offload modules
+ */
+bool ip6mr_register_mfc_event_offload_callback(
+ ip6mr_mfc_event_offload_callback_t mfc_offload_cb)
+{
+ ip6mr_mfc_event_offload_callback_t offload_update_cb_f;
+
+ rcu_read_lock();
+ offload_update_cb_f = rcu_dereference(ip6mr_mfc_event_offload_callback);
+
+ if (offload_update_cb_f) {
+ rcu_read_unlock();
+ return false;
+ }
+ rcu_read_unlock();
+
+ spin_lock(&lock);
+ rcu_assign_pointer(ip6mr_mfc_event_offload_callback, mfc_offload_cb);
+ spin_unlock(&lock);
+ synchronize_rcu();
+ return true;
+}
+EXPORT_SYMBOL(ip6mr_register_mfc_event_offload_callback);
+
+/* ip6mr_unregister_mfc_event_offload_callback()
+ * De-register the IPv6 multicast update callback for offload modules
+ */
+void ip6mr_unregister_mfc_event_offload_callback(void)
+{
+ spin_lock(&lock);
+ rcu_assign_pointer(ip6mr_mfc_event_offload_callback, NULL);
+ spin_unlock(&lock);
+ synchronize_rcu();
+}
+EXPORT_SYMBOL(ip6mr_unregister_mfc_event_offload_callback);
+
+/* ip6mr_find_mfc_entry()
+ * Return the destination interface list for a particular multicast flow, and
+ * the number of interfaces in the list
+ */
+int ip6mr_find_mfc_entry(struct net *net, struct in6_addr *origin,
+ struct in6_addr *group, u32 max_dest_cnt,
+ u32 dest_dev[])
+{
+ int vifi, dest_if_count = 0;
+ struct mr_table *mrt;
+ struct mfc6_cache *cache;
+
+ mrt = ip6mr_get_table(net, RT6_TABLE_DFLT);
+ if (!mrt)
+ return -ENOENT;
+
+ spin_lock(&mrt_lock);
+ cache = ip6mr_cache_find(mrt, origin, group);
+ if (!cache) {
+ spin_unlock(&mrt_lock);
+ return -ENOENT;
+ }
+
+ for (vifi = 0; vifi < cache->_c.mfc_un.res.maxvif; vifi++) {
+ if (!((cache->_c.mfc_un.res.ttls[vifi] > 0) &&
+ (cache->_c.mfc_un.res.ttls[vifi] < 255))) {
+ continue;
+ }
+
+ /* We have another valid destination interface entry. Check if
+ * the number of the destination interfaces for the route is
+ * exceeding the size of the array given to us
+ */
+ if (dest_if_count == max_dest_cnt) {
+ spin_unlock(&mrt_lock);
+ return -EINVAL;
+ }
+
+ if (!VIF_EXISTS(mrt, vifi)) {
+ spin_unlock(&mrt_lock);
+ return -EINVAL;
+ }
+
+ dest_dev[dest_if_count] = mrt->vif_table[vifi].dev->ifindex;
+ dest_if_count++;
+ }
+ spin_unlock(&mrt_lock);
+
+ return dest_if_count;
+}
+EXPORT_SYMBOL(ip6mr_find_mfc_entry);
+
+/* ip6mr_mfc_stats_update()
+ * Update the MFC/VIF statistics for offloaded flows
+ */
+int ip6mr_mfc_stats_update(struct net *net, struct in6_addr *origin,
+ struct in6_addr *group, u64 pkts_in,
+ u64 bytes_in, uint64_t pkts_out,
+ u64 bytes_out)
+{
+ int vif, vifi;
+ struct mr_table *mrt;
+ struct mfc6_cache *cache;
+
+ mrt = ip6mr_get_table(net, RT6_TABLE_DFLT);
+
+ if (!mrt)
+ return -ENOENT;
+
+ spin_lock(&mrt_lock);
+ cache = ip6mr_cache_find(mrt, origin, group);
+ if (!cache) {
+ spin_unlock(&mrt_lock);
+ return -ENOENT;
+ }
+
+ vif = cache->_c.mfc_parent;
+
+ if (!VIF_EXISTS(mrt, vif)) {
+ spin_unlock(&mrt_lock);
+ return -EINVAL;
+ }
+
+ mrt->vif_table[vif].pkt_in += pkts_in;
+ mrt->vif_table[vif].bytes_in += bytes_in;
+ atomic_long_add(pkts_out, &cache->_c.mfc_un.res.pkt);
+ atomic_long_add(bytes_out, &cache->_c.mfc_un.res.bytes);
+
+ for (vifi = cache->_c.mfc_un.res.minvif;
+ vifi < cache->_c.mfc_un.res.maxvif; vifi++) {
+ if ((cache->_c.mfc_un.res.ttls[vifi] > 0) &&
+ (cache->_c.mfc_un.res.ttls[vifi] < 255)) {
+ if (!VIF_EXISTS(mrt, vifi)) {
+ spin_unlock(&mrt_lock);
+ return -EINVAL;
+ }
+ mrt->vif_table[vifi].pkt_out += pkts_out;
+ mrt->vif_table[vifi].bytes_out += bytes_out;
+ }
+ }
+
+ spin_unlock(&mrt_lock);
+ return 0;
+}
+EXPORT_SYMBOL(ip6mr_mfc_stats_update);
+
/* Delete a VIF entry */
static int mif6_delete(struct mr_table *mrt, int vifi, int notify,
struct list_head *head)
@@ -1235,6 +1460,7 @@ static int ip6mr_mfc_delete(struct mr_ta
int parent)
{
struct mfc6_cache *c;
+ struct in6_addr mc_origin, mc_group;
/* The entries are added/deleted only under RTNL */
rcu_read_lock();
@@ -1243,6 +1469,9 @@ static int ip6mr_mfc_delete(struct mr_ta
rcu_read_unlock();
if (!c)
return -ENOENT;
+
+ memcpy(&mc_origin, &c->mf6c_origin, sizeof(struct in6_addr));
+ memcpy(&mc_group, &c->mf6c_mcastgrp, sizeof(struct in6_addr));
rhltable_remove(&mrt->mfc_hash, &c->_c.mnode, ip6mr_rht_params);
list_del_rcu(&c->_c.list);
@@ -1250,6 +1479,9 @@ static int ip6mr_mfc_delete(struct mr_ta
FIB_EVENT_ENTRY_DEL, c, mrt->id);
mr6_netlink_event(mrt, c, RTM_DELROUTE);
mr_cache_put(&c->_c);
+ /* Inform offload modules of the delete event */
+ ip6mr_sync_entry_delete(&mc_origin, &mc_group);
+
return 0;
}
@@ -1471,6 +1703,9 @@ static int ip6mr_mfc_add(struct net *net
call_ip6mr_mfc_entry_notifiers(net, FIB_EVENT_ENTRY_REPLACE,
c, mrt->id);
mr6_netlink_event(mrt, c, RTM_NEWROUTE);
+
+ /* Inform offload modules of the update event */
+ ip6mr_sync_entry_update(mrt, c);
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,11 @@
--- a/net/core/of_net.c
+++ b/net/core/of_net.c
@@ -40,7 +40,7 @@ int of_get_phy_mode(struct device_node *
for (i = 0; i < PHY_INTERFACE_MODE_MAX; i++)
if (!strcasecmp(pm, phy_modes(i))) {
*interface = i;
- return 0;
+ return i;
}
return -ENODEV;

View File

@@ -0,0 +1,38 @@
--- a/drivers/soc/qcom/socinfo.c
+++ b/drivers/soc/qcom/socinfo.c
@@ -529,11 +529,13 @@ QCOM_OPEN(pmic_die_rev, qcom_show_pmic_d
QCOM_OPEN(chip_id, qcom_show_chip_id);
#define DEFINE_IMAGE_OPS(type) \
-static int show_image_##type(struct seq_file *seq, void *p) \
+static int show_image_##type(struct seq_file *seq, void *p) \
{ \
struct smem_image_version *image_version = seq->private; \
- if (image_version->type[0] != '\0') \
- seq_printf(seq, "%s\n", image_version->type); \
+ if(!image_version && !image_version->type[0]) { \
+ seq_puts(seq, image_version->type); \
+ seq_puts(seq, "\n"); \
+ } \
return 0; \
} \
static int open_image_##type(struct inode *inode, struct file *file) \
@@ -749,7 +751,7 @@ static int qcom_socinfo_probe(struct pla
if (!qs)
return -ENOMEM;
- qs->attr.family = "Snapdragon";
+ qs->attr.family = "IPQ";
qs->attr.machine = socinfo_machine(&pdev->dev,
le32_to_cpu(info->id));
qs->attr.soc_id = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%u",
@@ -772,6 +774,9 @@ static int qcom_socinfo_probe(struct pla
if (IS_ERR(qs->soc_dev))
return PTR_ERR(qs->soc_dev);
+ pr_info("CPU: %s, SoC Version: %s id: %d fmt: %x\n", qs->attr.machine,
+ qs->attr.revision, info->id, qs->info.fmt);
+
socinfo_debugfs_init(qs, info, item_size);
/* Feed the soc specific unique data into entropy pool */

View File

@@ -0,0 +1,38 @@
From a6c62be5177cf3b383188a79241bd6d5833173d0 Mon Sep 17 00:00:00 2001
From: Murat Sezgin <msezgin@codeaurora.org>
Date: Mon, 6 Apr 2020 11:08:09 -0700
Subject: [PATCH 243/281] netfilter: export udp_get_timeouts function
This function is required for acceleration support.
Change-Id: Ibca4f402735764e7e6fb3ce2678e670753c6ef9c
Signed-off-by: Murat Sezgin <msezgin@codeaurora.org>
---
include/net/netfilter/nf_conntrack_timeout.h | 1 +
net/netfilter/nf_conntrack_proto_udp.c | 3 ++-
2 files changed, 3 insertions(+), 1 deletion(-)
--- a/include/net/netfilter/nf_conntrack_timeout.h
+++ b/include/net/netfilter/nf_conntrack_timeout.h
@@ -107,5 +107,6 @@ struct nf_ct_timeout_hooks {
extern const struct nf_ct_timeout_hooks __rcu *nf_ct_timeout_hook;
#endif
+extern unsigned int *udp_get_timeouts(struct net *net);
#endif /* _NF_CONNTRACK_TIMEOUT_H */
--- a/net/netfilter/nf_conntrack_proto_udp.c
+++ b/net/netfilter/nf_conntrack_proto_udp.c
@@ -29,10 +29,11 @@ static const unsigned int udp_timeouts[U
[UDP_CT_REPLIED] = 120*HZ,
};
-static unsigned int *udp_get_timeouts(struct net *net)
+unsigned int *udp_get_timeouts(struct net *net)
{
return nf_udp_pernet(net)->timeouts;
}
+EXPORT_SYMBOL(udp_get_timeouts);
static void udp_error_log(const struct sk_buff *skb,
const struct nf_hook_state *state,

View File

@@ -0,0 +1,38 @@
From fc86132bb4893d1747dc2c652a9ad722096dd4f8 Mon Sep 17 00:00:00 2001
From: Zhu Ken <guigenz@codeaurora.org>
Date: Wed, 14 Jun 2017 11:45:28 -0700
Subject: [PATCH 244/281] bridge: fix eapol packet dropping issue
wpa_supplicant would receive EAPOL packet to start 802.1x session even if
its wireless STA interface enslaved in a bridge is disabled.
Change-Id: I4e3f786049a19c5bc7aacdc0528b0099744e8674
Signed-off-by: Zhu Ken <guigenz@codeaurora.org>
---
net/bridge/br_input.c | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -451,13 +451,15 @@ forward:
switch (p->state) {
case BR_STATE_DISABLED:
- if (ether_addr_equal(p->br->dev->dev_addr, dest))
- skb->pkt_type = PACKET_HOST;
+ if (skb->protocol == htons(ETH_P_PAE)) {
+ if (ether_addr_equal(p->br->dev->dev_addr, dest))
+ skb->pkt_type = PACKET_HOST;
- if (BR_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING,
- dev_net(skb->dev), NULL, skb, skb->dev, NULL,
- br_handle_local_finish) == 1) {
- return RX_HANDLER_PASS;
+ if (BR_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING,
+ dev_net(skb->dev), NULL, skb, skb->dev, NULL,
+ br_handle_local_finish) == 1) {
+ return RX_HANDLER_PASS;
+ }
}
break;

View File

@@ -0,0 +1,41 @@
From a3b1392df5e6480db14e9036cbe57f6f9b762d5a Mon Sep 17 00:00:00 2001
From: Varsha Mishra <varsham@codeaurora.org>
Date: Thu, 11 Jun 2020 18:45:40 +0530
Subject: [PATCH 245/281] bridge: Get hairpin enabled information from bridge.
Add API to let other modules find out if bridge has
hairpin enabled or not.
Change-Id: I04c76345111bf8297dbe41230e1254df33556d52
Signed-off-by: Varsha Mishra <varsham@codeaurora.org>
---
include/linux/if_bridge.h | 1 +
net/bridge/br_if.c | 11 +++++++++++
2 files changed, 12 insertions(+)
--- a/include/linux/if_bridge.h
+++ b/include/linux/if_bridge.h
@@ -85,6 +85,7 @@ extern struct net_bridge_fdb_entry *br_f
__u16 vid);
extern void br_fdb_update_register_notify(struct notifier_block *nb);
extern void br_fdb_update_unregister_notify(struct notifier_block *nb);
+extern bool br_is_hairpin_enabled(struct net_device *dev);
#if IS_ENABLED(CONFIG_BRIDGE) && IS_ENABLED(CONFIG_BRIDGE_IGMP_SNOOPING)
int br_multicast_list_adjacent(struct net_device *dev,
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -866,3 +866,14 @@ void br_dev_update_stats(struct net_devi
local_bh_enable();
}
EXPORT_SYMBOL_GPL(br_dev_update_stats);
+
+/* API to know if hairpin feature is enabled/disabled on this bridge port */
+bool br_is_hairpin_enabled(struct net_device *dev)
+{
+ struct net_bridge_port *port = br_port_get_check_rcu(dev);
+
+ if (likely(port))
+ return port->flags & BR_HAIRPIN_MODE;
+ return false;
+}
+EXPORT_SYMBOL_GPL(br_is_hairpin_enabled);

View File

@@ -0,0 +1,87 @@
From ce18a6fdff6a39a01111d74f513d2ef66142047c Mon Sep 17 00:00:00 2001
From: Murat Sezgin <msezgin@codeaurora.org>
Date: Wed, 5 Aug 2020 13:21:27 -0700
Subject: [PATCH 246/281] net:ipv6: Fix IPv6 user route change event calls
These events should be called only when the route table is
changed by the userspace. So, we should call them in the
ioctl and the netlink message handler function.
Change-Id: If7ec615014cfc79d5fa72878e49eaf99c2560c32
Signed-off-by: Murat Sezgin <msezgin@codeaurora.org>
---
net/ipv6/route.c | 31 +++++++++++++++++++++----------
1 file changed, 21 insertions(+), 10 deletions(-)
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -3876,9 +3876,6 @@ int ip6_route_add(struct fib6_config *cf
return PTR_ERR(rt);
err = __ip6_ins_rt(rt, &cfg->fc_nlinfo, extack);
- if (!err)
- atomic_notifier_call_chain(&ip6route_chain,
- RTM_NEWROUTE, rt);
fib6_info_release(rt);
return err;
@@ -3899,9 +3896,7 @@ static int __ip6_del_rt(struct fib6_info
spin_lock_bh(&table->tb6_lock);
err = fib6_del(rt, info);
spin_unlock_bh(&table->tb6_lock);
- if (!err)
- atomic_notifier_call_chain(&ip6route_chain,
- RTM_DELROUTE, rt);
+
out:
fib6_info_release(rt);
return err;
@@ -4510,6 +4505,10 @@ int ipv6_route_ioctl(struct net *net, un
break;
}
rtnl_unlock();
+ if (!err)
+ atomic_notifier_call_chain(&ip6route_chain,
+ (cmd == SIOCADDRT) ? RTM_NEWROUTE : RTM_DELROUTE, &cfg);
+
return err;
}
@@ -5532,11 +5531,17 @@ static int inet6_rtm_delroute(struct sk_
}
if (cfg.fc_mp)
- return ip6_route_multipath_del(&cfg, extack);
+ err = ip6_route_multipath_del(&cfg, extack);
else {
cfg.fc_delete_all_nh = 1;
- return ip6_route_del(&cfg, extack);
+ err = ip6_route_del(&cfg, extack);
}
+
+ if (!err)
+ atomic_notifier_call_chain(&ip6route_chain,
+ RTM_DELROUTE, &cfg);
+
+ return err;
}
static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh,
@@ -5553,9 +5558,15 @@ static int inet6_rtm_newroute(struct sk_
cfg.fc_metric = IP6_RT_PRIO_USER;
if (cfg.fc_mp)
- return ip6_route_multipath_add(&cfg, extack);
+ err = ip6_route_multipath_add(&cfg, extack);
else
- return ip6_route_add(&cfg, GFP_KERNEL, extack);
+ err = ip6_route_add(&cfg, GFP_KERNEL, extack);
+
+ if (!err)
+ atomic_notifier_call_chain(&ip6route_chain,
+ RTM_NEWROUTE, &cfg);
+
+ return err;
}
/* add the overhead of this fib6_nh to nexthop_len */

View File

@@ -0,0 +1,24 @@
From 38749dbfcfb8b471b9eea391729b9a2a1f215bf2 Mon Sep 17 00:00:00 2001
From: Tian Yang <tiany@codeaurora.org>
Date: Wed, 9 Sep 2020 15:11:58 -0700
Subject: [PATCH 247/281] net_bridge: Export br_fdb_find_rcu symbol
Export br_fdb_find_rcu symbol to be used for other module
to find fdb entry.
Change-Id: I3df88b35ddfad2d295cdd45303002c5db015ff8c
Signed-off-by: Tian Yang <tiany@codeaurora.org>
---
net/bridge/br_fdb.c | 1 +
1 file changed, 1 insertion(+)
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -305,6 +305,7 @@ struct net_bridge_fdb_entry *br_fdb_find
{
return fdb_find_rcu(&br->fdb_hash_tbl, addr, vid);
}
+EXPORT_SYMBOL_GPL(br_fdb_find_rcu);
/* When a static FDB entry is added, the mac address from the entry is
* added to the bridge private HW address list and all required ports

View File

@@ -0,0 +1,35 @@
From 0564884785c2f49419b8d14ca98141c8e85cd8ab Mon Sep 17 00:00:00 2001
From: Subash Abhinov Kasiviswanathan <subashab@codeaurora.org>
Date: Thu, 17 Mar 2016 10:57:38 -0600
Subject: [PATCH 251/281] net: core: neighbour: Change the print format for
addresses
Print format %p displays the kernel address while bypassing the
kptr_restrict sysctl settings.
Change the print format for addresses from %p to %pK. If
kptr_restrict is enabled, addresses are printed as zeroes. To view
the actual addresses, disable kptr_restrict by -
echo 0 > /proc/sys/kernel/kptr_restrict
This patch applies the vollowing change from kernel/msm-3.18:
ee833ce586 (net: core: neighbour: Change the print format for addresses)
CRs-Fixed: 987041
Change-Id: I2eb33c63168ab26818dfdb3e11315f2ce8f24fa5
Signed-off-by: Subash Abhinov Kasiviswanathan <subashab@codeaurora.org>
---
net/core/neighbour.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -893,7 +893,7 @@ void neigh_destroy(struct neighbour *nei
NEIGH_CACHE_STAT_INC(neigh->tbl, destroys);
if (!neigh->dead) {
- pr_warn("Destroying alive neighbour %p\n", neigh);
+ pr_warn("Destroying alive neighbour %pK\n", neigh);
dump_stack();
return;
}

View File

@@ -0,0 +1,108 @@
From 96ab6b43388743ebc70a0b40290f6f5655e3c33f Mon Sep 17 00:00:00 2001
From: Suman Ghosh <sumaghos@codeaurora.org>
Date: Thu, 10 Dec 2020 00:11:41 +0530
Subject: [PATCH] net: macvlan: Add statistics update function for macvlan net
device.
Signed-off-by: Suman Ghosh <sumaghos@codeaurora.org>
Change-Id: I9cd995f9d1c0f85c61781a8af845b4dbb86bebd0
net: macvlan: Avoid updating error and drop counters for offloaded statistics.
Signed-off-by: Suman Ghosh <sumaghos@codeaurora.org>
Change-Id: Ibb7f3f5a0e73cda140adee2c1640af03c698f6e6
---
drivers/net/macvlan.c | 27 +++++++++++++++++++++++++++
include/linux/if_macvlan.h | 24 ++++++++++++++++++++++++
2 files changed, 51 insertions(+)
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -960,6 +960,32 @@ static void macvlan_uninit(struct net_de
macvlan_port_destroy(port->dev);
}
+/* Update macvlan statistics processed by offload engines */
+static void macvlan_dev_update_stats(struct net_device *dev,
+ struct rtnl_link_stats64 *offl_stats,
+ bool update_mcast_rx_stats)
+{
+ struct vlan_pcpu_stats *stats;
+ struct macvlan_dev *macvlan;
+
+ /* Is this a macvlan? */
+ if (!netif_is_macvlan(dev))
+ return;
+
+ macvlan = netdev_priv(dev);
+ stats = this_cpu_ptr(macvlan->pcpu_stats);
+ u64_stats_update_begin(&stats->syncp);
+ u64_stats_add(&stats->rx_packets, offl_stats->rx_packets);
+ u64_stats_add(&stats->rx_bytes, offl_stats->rx_bytes);
+ u64_stats_add(&stats->tx_packets, offl_stats->tx_packets);
+ u64_stats_add(&stats->tx_bytes, offl_stats->tx_bytes);
+ /* Update multicast statistics */
+ if (unlikely(update_mcast_rx_stats)) {
+ u64_stats_add(&stats->rx_multicast, offl_stats->rx_packets);
+ }
+ u64_stats_update_end(&stats->syncp);
+}
+
static void macvlan_dev_get_stats64(struct net_device *dev,
struct rtnl_link_stats64 *stats)
{
@@ -1506,6 +1532,7 @@ int macvlan_common_newlink(struct net *s
vlan->dev = dev;
vlan->port = port;
vlan->set_features = MACVLAN_FEATURES;
+ vlan->offload_stats_update = macvlan_dev_update_stats;
vlan->mode = MACVLAN_MODE_VEPA;
if (data && data[IFLA_MACVLAN_MODE])
--- a/include/linux/if_macvlan.h
+++ b/include/linux/if_macvlan.h
@@ -15,6 +15,11 @@ struct macvlan_port;
#define MACVLAN_MC_FILTER_BITS 8
#define MACVLAN_MC_FILTER_SZ (1 << MACVLAN_MC_FILTER_BITS)
+/*
+ * Callback for updating interface statistics for macvlan flows offloaded from host CPU.
+ */
+typedef void (*macvlan_offload_stats_update_cb_t)(struct net_device *dev, struct rtnl_link_stats64 *stats, bool update_mcast_rx_stats);
+
struct macvlan_dev {
struct net_device *dev;
struct list_head list;
@@ -35,6 +40,7 @@ struct macvlan_dev {
#ifdef CONFIG_NET_POLL_CONTROLLER
struct netpoll *netpoll;
#endif
+ macvlan_offload_stats_update_cb_t offload_stats_update;
};
static inline void macvlan_count_rx(const struct macvlan_dev *vlan,
@@ -68,6 +74,24 @@ extern void macvlan_dellink(struct net_d
extern int macvlan_link_register(struct rtnl_link_ops *ops);
#if IS_ENABLED(CONFIG_MACVLAN)
+static inline void
+macvlan_offload_stats_update(struct net_device *dev,
+ struct rtnl_link_stats64 *stats,
+ bool update_mcast_rx_stats)
+{
+ struct macvlan_dev *macvlan = netdev_priv(dev);
+
+ macvlan->offload_stats_update(dev, stats, update_mcast_rx_stats);
+}
+
+static inline enum
+macvlan_mode macvlan_get_mode(struct net_device *dev)
+{
+ struct macvlan_dev *macvlan = netdev_priv(dev);
+
+ return macvlan->mode;
+}
+
static inline struct net_device *
macvlan_dev_real_dev(const struct net_device *dev)
{

View File

@@ -0,0 +1,77 @@
--- a/include/net/ip6_tunnel.h
+++ b/include/net/ip6_tunnel.h
@@ -36,6 +36,7 @@ struct __ip6_tnl_parm {
__u8 proto; /* tunnel protocol */
__u8 encap_limit; /* encapsulation limit for tunnel */
__u8 hop_limit; /* hop limit for tunnel */
+ __u8 draft03; /* FMR using draft03 of map-e - QCA NSS Clients Support */
bool collect_md;
__be32 flowinfo; /* traffic class and flowlabel for tunnel */
__u32 flags; /* tunnel flags */
--- a/include/net/ip_tunnels.h
+++ b/include/net/ip_tunnels.h
@@ -592,4 +592,9 @@ static inline void ip_tunnel_info_opts_s
#endif /* CONFIG_INET */
+/* QCA NSS Clients Support - Start */
+void ipip6_update_offload_stats(struct net_device *dev, void *ptr);
+void ip6_update_offload_stats(struct net_device *dev, void *ptr);
+/* QCA NSS Clients Support - End */
+
#endif /* __NET_IP_TUNNELS_H */
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -2414,6 +2414,26 @@ nla_put_failure:
return -EMSGSIZE;
}
+/* QCA NSS Client Support - Start */
+/*
+ * Update offload stats
+ */
+void ip6_update_offload_stats(struct net_device *dev, void *ptr)
+{
+ struct pcpu_sw_netstats *tstats = per_cpu_ptr(dev->tstats, 0);
+ const struct pcpu_sw_netstats *offload_stats =
+ (struct pcpu_sw_netstats *)ptr;
+
+ u64_stats_update_begin(&tstats->syncp);
+ u64_stats_add(&tstats->tx_packets, u64_stats_read(&offload_stats->tx_packets));
+ u64_stats_add(&tstats->tx_bytes, u64_stats_read(&offload_stats->tx_bytes));
+ u64_stats_add(&tstats->rx_packets, u64_stats_read(&offload_stats->rx_packets));
+ u64_stats_add(&tstats->rx_bytes, u64_stats_read(&offload_stats->rx_bytes));
+ u64_stats_update_end(&tstats->syncp);
+}
+EXPORT_SYMBOL(ip6_update_offload_stats);
+/* QCA NSS Client Support - End */
+
struct net *ip6_tnl_get_link_net(const struct net_device *dev)
{
struct ip6_tnl *tunnel = netdev_priv(dev);
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -1734,6 +1734,23 @@ nla_put_failure:
return -EMSGSIZE;
}
+/* QCA NSS Clients Support - Start */
+void ipip6_update_offload_stats(struct net_device *dev, void *ptr)
+{
+ struct pcpu_sw_netstats *tstats = per_cpu_ptr(dev->tstats, 0);
+ const struct pcpu_sw_netstats *offload_stats =
+ (struct pcpu_sw_netstats *)ptr;
+
+ u64_stats_update_begin(&tstats->syncp);
+ u64_stats_add(&tstats->tx_packets, u64_stats_read(&offload_stats->tx_packets));
+ u64_stats_add(&tstats->tx_bytes, u64_stats_read(&offload_stats->tx_bytes));
+ u64_stats_add(&tstats->rx_packets, u64_stats_read(&offload_stats->rx_packets));
+ u64_stats_add(&tstats->rx_bytes, u64_stats_read(&offload_stats->rx_bytes));
+ u64_stats_update_end(&tstats->syncp);
+}
+EXPORT_SYMBOL(ipip6_update_offload_stats);
+/* QCA NSS Clients Support - End */
+
static const struct nla_policy ipip6_policy[IFLA_IPTUN_MAX + 1] = {
[IFLA_IPTUN_LINK] = { .type = NLA_U32 },
[IFLA_IPTUN_LOCAL] = { .type = NLA_U32 },

View File

@@ -0,0 +1,132 @@
From 3fda44006f8cbca0670305f6543c223f8e6a0243 Mon Sep 17 00:00:00 2001
From: Vishnu Vardhan Bantanahal <quic_vishvard@quicinc.com>
Date: Thu, 1 Jun 2023 17:23:35 +0530
Subject: [PATCH] net: vxlan: Adding APIs to VxLAN driver.
Adding new APIs to verify VxLAN netdevice and
update mac entries in VxLAN's fdb.
Change-Id: I22962d4845cba3a258c095f6424557a29d3b354b
Signed-off-by: Apoorv Gupta <apoogupt@codeaurora.org>
net: vxlan: Added vxlan fdb notify chain
Registered modules are notified based on following events:
1. RTM_GETNEIGH
2. RTM_NEWNEIGH
3. RTM_DELNEIGH
Change-Id: I0802b305a829800cafbabd4728c3c47ff3679938
Signed-off-by: Cemil Coskun <ccoskun@codeaurora.org>
Signed-off-by: Apoorv Gupta <apoogupt@codeaurora.org>
Signed-off-by: Vishnu Vardhan Bantanahal <quic_vishvard@quicinc.com>
---
drivers/net/vxlan/vxlan_core.c | 31 +++++++++++++++++++++++++++++++
include/net/vxlan.h | 29 +++++++++++++++++++++++++++++
2 files changed, 60 insertions(+)
--- a/drivers/net/vxlan/vxlan_core.c
+++ b/drivers/net/vxlan/vxlan_core.c
@@ -65,6 +65,20 @@ static void vxlan_vs_del_dev(struct vxla
/* salt for hash table */
static u32 vxlan_salt __read_mostly;
+ATOMIC_NOTIFIER_HEAD(vxlan_fdb_notifier_list);
+
+void vxlan_fdb_register_notify(struct notifier_block *nb)
+{
+ atomic_notifier_chain_register(&vxlan_fdb_notifier_list, nb);
+}
+EXPORT_SYMBOL(vxlan_fdb_register_notify);
+
+void vxlan_fdb_unregister_notify(struct notifier_block *nb)
+{
+ atomic_notifier_chain_unregister(&vxlan_fdb_notifier_list, nb);
+}
+EXPORT_SYMBOL(vxlan_fdb_unregister_notify);
+
static inline bool vxlan_collect_metadata(struct vxlan_sock *vs)
{
return vs->flags & VXLAN_F_COLLECT_METADATA ||
@@ -260,6 +274,7 @@ static void __vxlan_fdb_notify(struct vx
{
struct net *net = dev_net(vxlan->dev);
struct sk_buff *skb;
+ struct vxlan_fdb_event vfe;
int err = -ENOBUFS;
skb = nlmsg_new(vxlan_nlmsg_size(), GFP_ATOMIC);
@@ -275,6 +290,10 @@ static void __vxlan_fdb_notify(struct vx
}
rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);
+ vfe.dev = vxlan->dev;
+ vfe.rdst = rd;
+ ether_addr_copy(vfe.eth_addr, fdb->eth_addr);
+ atomic_notifier_call_chain(&vxlan_fdb_notifier_list, type, (void *)&vfe);
return;
errout:
if (err < 0)
@@ -441,6 +460,18 @@ static struct vxlan_fdb *vxlan_find_mac(
return f;
}
+/* Find and update age of fdb entry corresponding to MAC. */
+void vxlan_fdb_update_mac(struct vxlan_dev *vxlan, const u8 *mac, uint32_t vni)
+{
+ u32 hash_index;
+
+ hash_index = fdb_head_index(vxlan, mac, vni);
+ spin_lock_bh(&vxlan->hash_lock[hash_index]);
+ vxlan_find_mac(vxlan, mac, vni);
+ spin_unlock_bh(&vxlan->hash_lock[hash_index]);
+}
+EXPORT_SYMBOL(vxlan_fdb_update_mac);
+
/* caller should hold vxlan->hash_lock */
static struct vxlan_rdst *vxlan_fdb_find_rdst(struct vxlan_fdb *f,
union vxlan_addr *ip, __be16 port,
--- a/include/net/vxlan.h
+++ b/include/net/vxlan.h
@@ -352,6 +352,19 @@ struct vxlan_dev {
VXLAN_F_VNIFILTER | \
VXLAN_F_LOCALBYPASS)
+/*
+ * Application data for fdb notifier event
+ */
+struct vxlan_fdb_event {
+ struct net_device *dev;
+ struct vxlan_rdst *rdst;
+ u8 eth_addr[ETH_ALEN];
+};
+
+extern void vxlan_fdb_register_notify(struct notifier_block *nb);
+extern void vxlan_fdb_unregister_notify(struct notifier_block *nb);
+extern void vxlan_fdb_update_mac(struct vxlan_dev *vxlan, const u8 *mac, uint32_t vni);
+
struct net_device *vxlan_dev_create(struct net *net, const char *name,
u8 name_assign_type, struct vxlan_config *conf);
@@ -440,6 +453,22 @@ static inline __be32 vxlan_compute_rco(u
return vni_field;
}
+/*
+ * is_vxlan_dev()
+ * Check if it is a VxLAN netdevice.
+ */
+static inline bool is_vxlan_dev(const struct net_device *dev)
+{
+ if (!dev)
+ return false;
+
+ if ((dev->dev.type) &&
+ !strncmp(dev->dev.type->name, "vxlan", sizeof("vxlan"))) {
+ return true;
+ }
+ return false;
+}
+
static inline unsigned short vxlan_get_sk_family(struct vxlan_sock *vs)
{
return vs->sock->sk->sk_family;

View File

@@ -0,0 +1,111 @@
--- a/crypto/authenc.c
+++ b/crypto/authenc.c
@@ -415,6 +415,8 @@ static int crypto_authenc_create(struct
enc->base.cra_driver_name) >= CRYPTO_MAX_ALG_NAME)
goto err_free_inst;
+ inst->alg.base.cra_flags |= (auth_base->cra_flags |
+ enc->base.cra_flags) & CRYPTO_ALG_NOSUPP_SG;
inst->alg.base.cra_priority = enc->base.cra_priority * 10 +
auth_base->cra_priority;
inst->alg.base.cra_blocksize = enc->base.cra_blocksize;
--- a/include/linux/crypto.h
+++ b/include/linux/crypto.h
@@ -86,6 +86,11 @@
#define CRYPTO_NOLOAD 0x00008000
/*
+ * Set this flag if algorithm does not support SG list transforms
+ */
+#define CRYPTO_ALG_NOSUPP_SG 0x0000c000
+
+/*
* The algorithm may allocate memory during request processing, i.e. during
* encryption, decryption, or hashing. Users can request an algorithm with this
* flag unset if they can't handle memory allocation failures.
--- a/net/ipv4/esp4.c
+++ b/net/ipv4/esp4.c
@@ -657,6 +657,7 @@ static int esp_output(struct xfrm_state
struct ip_esp_hdr *esph;
struct crypto_aead *aead;
struct esp_info esp;
+ bool nosupp_sg;
esp.inplace = true;
@@ -668,6 +669,11 @@ static int esp_output(struct xfrm_state
aead = x->data;
alen = crypto_aead_authsize(aead);
+ nosupp_sg = crypto_tfm_alg_type(&aead->base) & CRYPTO_ALG_NOSUPP_SG;
+ if (nosupp_sg && skb_linearize(skb)) {
+ return -ENOMEM;
+ }
+
esp.tfclen = 0;
if (x->tfcpad) {
struct xfrm_dst *dst = (struct xfrm_dst *)skb_dst(skb);
@@ -889,6 +895,7 @@ static int esp_input(struct xfrm_state *
u8 *iv;
struct scatterlist *sg;
int err = -EINVAL;
+ bool nosupp_sg;
if (!pskb_may_pull(skb, sizeof(struct ip_esp_hdr) + ivlen))
goto out;
@@ -896,6 +903,12 @@ static int esp_input(struct xfrm_state *
if (elen <= 0)
goto out;
+ nosupp_sg = crypto_tfm_alg_type(&aead->base) & CRYPTO_ALG_NOSUPP_SG;
+ if (nosupp_sg && skb_linearize(skb)) {
+ err = -ENOMEM;
+ goto out;
+ }
+
assoclen = sizeof(struct ip_esp_hdr);
seqhilen = 0;
--- a/net/ipv6/esp6.c
+++ b/net/ipv6/esp6.c
@@ -695,6 +695,7 @@ static int esp6_output(struct xfrm_state
struct ip_esp_hdr *esph;
struct crypto_aead *aead;
struct esp_info esp;
+ bool nosupp_sg;
esp.inplace = true;
@@ -706,6 +707,11 @@ static int esp6_output(struct xfrm_state
aead = x->data;
alen = crypto_aead_authsize(aead);
+ nosupp_sg = crypto_tfm_alg_type(&aead->base) & CRYPTO_ALG_NOSUPP_SG;
+ if (nosupp_sg && skb_linearize(skb)) {
+ return -ENOMEM;
+ }
+
esp.tfclen = 0;
if (x->tfcpad) {
struct xfrm_dst *dst = (struct xfrm_dst *)skb_dst(skb);
@@ -933,6 +939,7 @@ static int esp6_input(struct xfrm_state
__be32 *seqhi;
u8 *iv;
struct scatterlist *sg;
+ bool nosupp_sg;
if (!pskb_may_pull(skb, sizeof(struct ip_esp_hdr) + ivlen)) {
ret = -EINVAL;
@@ -944,6 +951,12 @@ static int esp6_input(struct xfrm_state
goto out;
}
+ nosupp_sg = crypto_tfm_alg_type(&aead->base) & CRYPTO_ALG_NOSUPP_SG;
+ if (nosupp_sg && skb_linearize(skb)) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
assoclen = sizeof(struct ip_esp_hdr);
seqhilen = 0;

View File

@@ -0,0 +1,99 @@
From ed42112c77bfb68594f49e252ace2dd6b8c8e7ff Mon Sep 17 00:00:00 2001
From: Felix Fietkau <nbd@nbd.name>
Date: Thu, 16 Mar 2023 17:21:39 +0530
Subject: [PATCH 063/281] OpenWrt:
613-netfilter_optional_tcp_window_check.patch
netfilter: optional tcp window check
Signed-off-by: Felix Fietkau <nbd@nbd.name>
Signed-off-by: Christian 'Ansuel' Marangi <ansuelsmth@gmail.com>
Change-Id: I6f7a23b89062cca58c87554e75ae32b0e2aa2831
Signed-off-by: Ram Chandra Jangir <quic_rjangir@quicinc.com>
---
include/net/netns/conntrack.h | 1 +
net/netfilter/nf_conntrack_proto_tcp.c | 9 ++++++++-
net/netfilter/nf_conntrack_standalone.c | 10 ++++++++++
3 files changed, 19 insertions(+), 1 deletion(-)
--- a/include/net/netns/conntrack.h
+++ b/include/net/netns/conntrack.h
@@ -26,6 +26,7 @@ struct nf_tcp_net {
unsigned int timeouts[TCP_CONNTRACK_TIMEOUT_MAX];
u8 tcp_loose;
u8 tcp_be_liberal;
+ u8 tcp_no_window_check;
u8 tcp_max_retrans;
u8 tcp_ignore_invalid_rst;
#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
--- a/net/netfilter/nf_conntrack_proto_tcp.c
+++ b/net/netfilter/nf_conntrack_proto_tcp.c
@@ -515,11 +515,15 @@ tcp_in_window(struct nf_conn *ct, enum i
struct ip_ct_tcp *state = &ct->proto.tcp;
struct ip_ct_tcp_state *sender = &state->seen[dir];
struct ip_ct_tcp_state *receiver = &state->seen[!dir];
+ const struct nf_tcp_net *tn = nf_tcp_pernet(nf_ct_net(ct));
__u32 seq, ack, sack, end, win, swin;
bool in_recv_win, seq_ok;
s32 receiver_offset;
u16 win_raw;
+ if (tn->tcp_no_window_check)
+ return NFCT_TCP_ACCEPT;
+
/*
* Get the required data from the packet.
*/
@@ -1285,7 +1289,7 @@ int nf_conntrack_tcp_packet(struct nf_co
IP_CT_TCP_FLAG_DATA_UNACKNOWLEDGED &&
timeouts[new_state] > timeouts[TCP_CONNTRACK_UNACK])
timeout = timeouts[TCP_CONNTRACK_UNACK];
- else if (ct->proto.tcp.last_win == 0 &&
+ else if (!tn->tcp_no_window_check && ct->proto.tcp.last_win == 0 &&
timeouts[new_state] > timeouts[TCP_CONNTRACK_RETRANS])
timeout = timeouts[TCP_CONNTRACK_RETRANS];
else
@@ -1601,6 +1605,9 @@ void nf_conntrack_tcp_init_net(struct ne
*/
tn->tcp_be_liberal = 0;
+ /* Skip Windows Check */
+ tn->tcp_no_window_check = 0;
+
/* If it's non-zero, we turn off RST sequence number check */
tn->tcp_ignore_invalid_rst = 0;
--- a/net/netfilter/nf_conntrack_standalone.c
+++ b/net/netfilter/nf_conntrack_standalone.c
@@ -630,6 +630,7 @@ enum nf_ct_sysctl_index {
#endif
NF_SYSCTL_CT_PROTO_TCP_LOOSE,
NF_SYSCTL_CT_PROTO_TCP_LIBERAL,
+ NF_SYSCTL_CT_PROTO_TCP_NO_WINDOW_CHECK,
NF_SYSCTL_CT_PROTO_TCP_IGNORE_INVALID_RST,
NF_SYSCTL_CT_PROTO_TCP_MAX_RETRANS,
NF_SYSCTL_CT_PROTO_TIMEOUT_UDP,
@@ -834,6 +835,14 @@ static struct ctl_table nf_ct_sysctl_tab
.extra1 = SYSCTL_ZERO,
.extra2 = SYSCTL_ONE,
},
+ [NF_SYSCTL_CT_PROTO_TCP_NO_WINDOW_CHECK] = {
+ .procname = "nf_conntrack_tcp_no_window_check",
+ .maxlen = sizeof(u8),
+ .mode = 0644,
+ .proc_handler = proc_dou8vec_minmax,
+ .extra1 = SYSCTL_ZERO,
+ .extra2 = SYSCTL_ONE,
+ },
[NF_SYSCTL_CT_PROTO_TCP_IGNORE_INVALID_RST] = {
.procname = "nf_conntrack_tcp_ignore_invalid_rst",
.maxlen = sizeof(u8),
@@ -1035,6 +1044,7 @@ static void nf_conntrack_standalone_init
XASSIGN(LOOSE, &tn->tcp_loose);
XASSIGN(LIBERAL, &tn->tcp_be_liberal);
+ XASSIGN(NO_WINDOW_CHECK, &tn->tcp_no_window_check);
XASSIGN(MAX_RETRANS, &tn->tcp_max_retrans);
XASSIGN(IGNORE_INVALID_RST, &tn->tcp_ignore_invalid_rst);
#undef XASSIGN

View File

@@ -0,0 +1,44 @@
From 4746722090513b5ad66819a758004ac198ccc56f Mon Sep 17 00:00:00 2001
From: Ken Zhu <quic_guigenz@quicinc.com>
Date: Thu, 28 Sep 2023 10:44:56 -0700
Subject: [PATCH] linux: fix dscpremark extention doesn't set the type length
It needs to set up the type length for each extension.
Change-Id: Ia2087d7c4653045665c006ca9d637ff49d27fd92
Signed-off-by: Ken Zhu <quic_guigenz@quicinc.com>
---
net/netfilter/nf_conntrack_extend.c | 8 ++++++++
1 file changed, 8 insertions(+)
--- a/net/netfilter/nf_conntrack_extend.c
+++ b/net/netfilter/nf_conntrack_extend.c
@@ -24,6 +24,7 @@
#include <net/netfilter/nf_conntrack_synproxy.h>
#include <net/netfilter/nf_conntrack_act_ct.h>
#include <net/netfilter/nf_nat.h>
+#include <net/netfilter/nf_conntrack_dscpremark_ext.h>
#define NF_CT_EXT_PREALLOC 128u /* conntrack events are on by default */
@@ -54,6 +55,10 @@ static const u8 nf_ct_ext_type_len[NF_CT
#if IS_ENABLED(CONFIG_NET_ACT_CT)
[NF_CT_EXT_ACT_CT] = sizeof(struct nf_conn_act_ct_ext),
#endif
+#ifdef CONFIG_NF_CONNTRACK_DSCPREMARK_EXT
+ [NF_CT_EXT_DSCPREMARK] = sizeof(struct nf_ct_dscpremark_ext),
+#endif
+
};
static __always_inline unsigned int total_extension_size(void)
@@ -86,6 +91,9 @@ static __always_inline unsigned int tota
#if IS_ENABLED(CONFIG_NET_ACT_CT)
+ sizeof(struct nf_conn_act_ct_ext)
#endif
+#ifdef CONFIG_NF_CONNTRACK_DSCPREMARK_EXT
+ + sizeof(struct nf_ct_dscpremark_ext)
+#endif
;
}

View File

@@ -0,0 +1,170 @@
From 6f8beb8ec2047f645b488dd95be6f98ce0584165 Mon Sep 17 00:00:00 2001
From: Murat Sezgin <quic_msezgin@quicinc.com>
Date: Thu, 18 May 2023 08:47:34 -0700
Subject: [PATCH 271/281] net: Add extra priv_flag support in netdevice
This patch adds a flag in struct net_device which
is an extension to priv_flags and is used to
check the type of device.
Change-Id: Ibb5a3f0c706e1b169b848aed7004aa4ea6d57069
Signed-off-by: Pavithra R <pavir@codeaurora.org>
Add GRE std support in device tree and priv_flags
Added dts support and priv flags support for GRE and
to check the type of device
Change-Id: Ib05a32e9e5458c724c182187362116338d767169
Signed-off-by: ratheesh kannoth <rkannoth@codeaurora.org>
Signed-off-by: Pavithra R <pavir@codeaurora.org>
drivers: ifb: Add flag to identify the IFB interface.
Add IFB flag in netdevice's ext priv flags and define an API
to let other modules find out if the netdev is IFB or not.
Change-Id: I6dbdae521240b4a991069c2330d893ff38aec68d
Signed-off-by: Manish Verma <maniverm@codeaurora.org>
Signed-off-by: pavir <pavir@codeaurora.org>
net: add IFF_EXT_MAPT flag in net_device priv_flags_ext
Add IFF_EXT_MAPT flag in priv_flags_ext for MAP-T device.
Change-Id: I8aa1715c4b9c62b88eee1b40412cf4e734b2a337
Signed-off-by: Suruchi Agarwal <quic_suruchia@quicinc.com>
Signed-off-by: Murat Sezgin <quic_msezgin@quicinc.com>
---
drivers/net/ifb.c | 1 +
include/linux/netdevice.h | 36 ++++++++++++++++++++++++++++++++++--
net/ipv4/ip_gre.c | 2 +-
net/ipv6/ip6_gre.c | 4 +---
4 files changed, 37 insertions(+), 6 deletions(-)
--- a/drivers/net/ifb.c
+++ b/drivers/net/ifb.c
@@ -326,6 +326,7 @@ static void ifb_setup(struct net_device
dev->flags |= IFF_NOARP;
dev->flags &= ~IFF_MULTICAST;
dev->priv_flags &= ~IFF_TX_SKB_SHARING;
+ dev->priv_flags_ext |= IFF_EXT_IFB; /* Mark the device as an IFB device. */
netif_keep_dst(dev);
eth_hw_addr_random(dev);
dev->needs_free_netdev = true;
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1781,6 +1781,32 @@ enum netdev_priv_flags {
IFF_NO_IP_ALIGN = BIT_ULL(34),
};
+/**
+ * enum netdev_priv_flags_ext - &struct net_device priv_flags_ext
+ *
+ * These flags are used to check for device type and can be
+ * set and used by the drivers
+ *
+ * @IFF_EXT_TUN_TAP: device is a TUN/TAP device
+ * @IFF_EXT_PPP_L2TPV2: device is a L2TPV2 device
+ * @IFF_EXT_PPP_L2TPV3: device is a L2TPV3 device
+ * @IFF_EXT_PPP_PPTP: device is a PPTP device
+ * @IFF_EXT_GRE_V4_TAP: device is a GRE IPv4 TAP device
+ * @IFF_EXT_GRE_V6_TAP: device is a GRE IPv6 TAP device
+ * @IFF_EXT_IFB: device is an IFB device
+ * @IFF_EXT_MAPT: device is an MAPT device
+ */
+enum netdev_priv_flags_ext {
+ IFF_EXT_TUN_TAP = 1<<0,
+ IFF_EXT_PPP_L2TPV2 = 1<<1,
+ IFF_EXT_PPP_L2TPV3 = 1<<2,
+ IFF_EXT_PPP_PPTP = 1<<3,
+ IFF_EXT_GRE_V4_TAP = 1<<4,
+ IFF_EXT_GRE_V6_TAP = 1<<5,
+ IFF_EXT_IFB = 1<<6,
+ IFF_EXT_MAPT = 1<<7,
+};
+
#define IFF_802_1Q_VLAN IFF_802_1Q_VLAN
#define IFF_EBRIDGE IFF_EBRIDGE
#define IFF_BONDING IFF_BONDING
@@ -1901,6 +1927,8 @@ enum netdev_stat_type {
* @xdp_features: XDP capability supported by the device
* @priv_flags: Like 'flags' but invisible to userspace,
* see if.h for the definitions
+ * @priv_flags_ext: Extension for 'priv_flags'
+ *
* @gflags: Global flags ( kept as legacy )
* @padded: How much padding added by alloc_netdev()
* @operstate: RFC2863 operstate
@@ -2146,6 +2174,7 @@ struct net_device {
unsigned int flags;
xdp_features_t xdp_features;
unsigned long long priv_flags;
+ unsigned int priv_flags_ext;
const struct net_device_ops *netdev_ops;
const struct xdp_metadata_ops *xdp_metadata_ops;
int ifindex;
@@ -5245,6 +5274,11 @@ static inline bool netif_is_failover_sla
return dev->priv_flags & IFF_FAILOVER_SLAVE;
}
+static inline bool netif_is_ifb_dev(const struct net_device *dev)
+{
+ return dev->priv_flags_ext & IFF_EXT_IFB;
+}
+
/* This device needs to keep skb dst for qdisc enqueue or ndo_start_xmit() */
static inline void netif_keep_dst(struct net_device *dev)
{
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -828,7 +828,6 @@ static int ipgre_tunnel_ctl(struct net_d
It allows to construct virtual multiprotocol broadcast "LAN"
over the Internet, provided multicast routing is tuned.
-
I have no idea was this bicycle invented before me,
so that I had to set ARPHRD_IPGRE to a random value.
I have an impression, that Cisco could make something similar,
@@ -1337,6 +1336,7 @@ static void ipgre_tap_setup(struct net_d
dev->netdev_ops = &gre_tap_netdev_ops;
dev->priv_flags &= ~IFF_TX_SKB_SHARING;
dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
+ dev->priv_flags_ext |= IFF_EXT_GRE_V4_TAP;
ip_tunnel_setup(dev, gre_tap_net_id);
}
--- a/net/ipv6/ip6_gre.c
+++ b/net/ipv6/ip6_gre.c
@@ -53,7 +53,6 @@
#include <net/erspan.h>
#include <net/dst_metadata.h>
-
static bool log_ecn_error = true;
module_param(log_ecn_error, bool, 0644);
MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN");
@@ -414,7 +413,6 @@ static void ip6gre_tunnel_uninit(struct
netdev_put(dev, &t->dev_tracker);
}
-
static int ip6gre_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
u8 type, u8 code, int offset, __be32 info)
{
@@ -1618,7 +1616,6 @@ static int __net_init ip6gre_init_net(st
*/
ign->fb_tunnel_dev->features |= NETIF_F_NETNS_LOCAL;
-
ip6gre_fb_tunnel_init(ign->fb_tunnel_dev);
ign->fb_tunnel_dev->rtnl_link_ops = &ip6gre_link_ops;
@@ -1941,6 +1938,7 @@ static void ip6gre_tap_setup(struct net_
dev->priv_flags &= ~IFF_TX_SKB_SHARING;
dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
+ dev->priv_flags_ext |= IFF_EXT_GRE_V6_TAP;
netif_keep_dst(dev);
}

View File

@@ -0,0 +1,470 @@
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -762,6 +762,7 @@ typedef unsigned char *sk_buff_data_t;
* @offload_fwd_mark: Packet was L2-forwarded in hardware
* @offload_l3_fwd_mark: Packet was L3-forwarded in hardware
* @tc_skip_classify: do not classify packet. set by IFB device
+ * @tc_skip_classify_offload: do not classify packet set by offload IFB device
* @tc_at_ingress: used within tc_classify to distinguish in/egress
* @redirected: packet was redirected by packet classifier
* @from_ingress: packet was redirected from the ingress path
@@ -970,6 +971,12 @@ struct sk_buff {
__u8 offload_fwd_mark:1;
__u8 offload_l3_fwd_mark:1;
#endif
+#ifdef CONFIG_NET_CLS_ACT
+ __u8 tc_skip_classify:1;
+ __u8 tc_at_ingress:1;
+ __u8 tc_skip_classify_offload:1;
+ __u16 tc_verd_qca_nss;
+#endif
__u8 redirected:1;
#ifdef CONFIG_NET_REDIRECT
__u8 from_ingress:1;
--- a/include/uapi/linux/pkt_cls.h
+++ b/include/uapi/linux/pkt_cls.h
@@ -139,6 +139,7 @@ enum tca_id {
TCA_ID_MPLS,
TCA_ID_CT,
TCA_ID_GATE,
+ TCA_ID_MIRRED_NSS,
/* other actions go here */
__TCA_ID_MAX = 255
};
@@ -817,4 +818,14 @@ enum {
TCF_EM_OPND_LT
};
+
+#define _TC_MAKE32(x) ((x))
+#define _TC_MAKEMASK1(n) (_TC_MAKE32(1) << _TC_MAKE32(n))
+
+#define TC_NCLS _TC_MAKEMASK1(8)
+#define TC_NCLS_NSS _TC_MAKEMASK1(12)
+#define SET_TC_NCLS_NSS(v) ( TC_NCLS_NSS | ((v) & ~TC_NCLS_NSS))
+#define CLR_TC_NCLS_NSS(v) ( (v) & ~TC_NCLS_NSS)
+
+
#endif
--- a/include/linux/timer.h
+++ b/include/linux/timer.h
@@ -17,6 +17,7 @@ struct timer_list {
unsigned long expires;
void (*function)(struct timer_list *);
u32 flags;
+ unsigned long cust_data;
#ifdef CONFIG_LOCKDEP
struct lockdep_map lockdep_map;
--- a/drivers/net/ifb.c
+++ b/drivers/net/ifb.c
@@ -151,6 +151,31 @@ resched:
}
+void ifb_update_offload_stats(struct net_device *dev, struct pcpu_sw_netstats *offload_stats)
+{
+ struct ifb_dev_private *dp;
+ struct ifb_q_private *txp;
+
+ if (!dev || !offload_stats) {
+ return;
+ }
+
+ if (!(dev->priv_flags_ext & IFF_EXT_IFB)) {
+ return;
+ }
+
+ dp = netdev_priv(dev);
+ txp = dp->tx_private;
+
+ u64_stats_update_begin(&txp->rsync);
+ txp->rx_packets += offload_stats->rx_packets;
+ txp->rx_bytes += offload_stats->rx_bytes;
+ txp->tx_packets += offload_stats->tx_packets;
+ txp->tx_bytes += offload_stats->tx_bytes;
+ u64_stats_update_end(&txp->rsync);
+}
+EXPORT_SYMBOL(ifb_update_offload_stats);
+
static void ifb_stats64(struct net_device *dev,
struct rtnl_link_stats64 *stats)
{
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -4730,6 +4730,15 @@ void dev_uc_flush(struct net_device *dev
void dev_uc_init(struct net_device *dev);
/**
+ * ifb_update_offload_stats - Update the IFB interface stats
+ * @dev: IFB device to update the stats
+ * @offload_stats: per CPU stats structure
+ *
+ * Allows update of IFB stats when flows are offloaded to an accelerator.
+ **/
+void ifb_update_offload_stats(struct net_device *dev, struct pcpu_sw_netstats *offload_stats);
+
+/**
* __dev_uc_sync - Synchonize device's unicast list
* @dev: device to sync
* @sync: function to call if address should be added
--- a/include/uapi/linux/pkt_sched.h
+++ b/include/uapi/linux/pkt_sched.h
@@ -1306,4 +1306,248 @@ enum {
#define TCA_ETS_MAX (__TCA_ETS_MAX - 1)
+
+enum {
+ TCA_NSS_ACCEL_MODE_NSS_FW,
+ TCA_NSS_ACCEL_MODE_PPE,
+ TCA_NSS_ACCEL_MODE_MAX
+};
+
+/* NSSFIFO section */
+
+enum {
+ TCA_NSSFIFO_UNSPEC,
+ TCA_NSSFIFO_PARMS,
+ __TCA_NSSFIFO_MAX
+};
+
+#define TCA_NSSFIFO_MAX (__TCA_NSSFIFO_MAX - 1)
+
+struct tc_nssfifo_qopt {
+ __u32 limit; /* Queue length: bytes for bfifo, packets for pfifo */
+ __u8 set_default; /* Sets qdisc to be the default qdisc for enqueue */
+ __u8 accel_mode; /* Dictates which data plane offloads the qdisc */
+};
+
+/* NSSWRED section */
+
+enum {
+ TCA_NSSWRED_UNSPEC,
+ TCA_NSSWRED_PARMS,
+ __TCA_NSSWRED_MAX
+};
+
+#define TCA_NSSWRED_MAX (__TCA_NSSWRED_MAX - 1)
+#define NSSWRED_CLASS_MAX 6
+struct tc_red_alg_parameter {
+ __u32 min; /* qlen_avg < min: pkts are all enqueued */
+ __u32 max; /* qlen_avg > max: pkts are all dropped */
+ __u32 probability;/* Drop probability at qlen_avg = max */
+ __u32 exp_weight_factor;/* exp_weight_factor for calculate qlen_avg */
+};
+
+struct tc_nsswred_traffic_class {
+ __u32 limit; /* Queue length */
+ __u32 weight_mode_value; /* Weight mode value */
+ struct tc_red_alg_parameter rap;/* Parameters for RED alg */
+};
+
+/*
+ * Weight modes for WRED
+ */
+enum tc_nsswred_weight_modes {
+ TC_NSSWRED_WEIGHT_MODE_DSCP = 0,/* Weight mode is DSCP */
+ TC_NSSWRED_WEIGHT_MODES, /* Must be last */
+};
+
+struct tc_nsswred_qopt {
+ __u32 limit; /* Queue length */
+ enum tc_nsswred_weight_modes weight_mode;
+ /* Weight mode */
+ __u32 traffic_classes; /* How many traffic classes: DPs */
+ __u32 def_traffic_class; /* Default traffic if no match: def_DP */
+ __u32 traffic_id; /* The traffic id to be configured: DP */
+ __u32 weight_mode_value; /* Weight mode value */
+ struct tc_red_alg_parameter rap;/* RED algorithm parameters */
+ struct tc_nsswred_traffic_class tntc[NSSWRED_CLASS_MAX];
+ /* Traffic settings for dumpping */
+ __u8 ecn; /* Setting ECN bit or dropping */
+ __u8 set_default; /* Sets qdisc to be the default for enqueue */
+ __u8 accel_mode; /* Dictates which data plane offloads the qdisc */
+};
+
+/* NSSCODEL section */
+
+enum {
+ TCA_NSSCODEL_UNSPEC,
+ TCA_NSSCODEL_PARMS,
+ __TCA_NSSCODEL_MAX
+};
+
+#define TCA_NSSCODEL_MAX (__TCA_NSSCODEL_MAX - 1)
+
+struct tc_nsscodel_qopt {
+ __u32 target; /* Acceptable queueing delay */
+ __u32 limit; /* Max number of packets that can be held in the queue */
+ __u32 interval; /* Monitoring interval */
+ __u32 flows; /* Number of flow buckets */
+ __u32 quantum; /* Weight (in bytes) used for DRR of flow buckets */
+ __u8 ecn; /* 0 - disable ECN, 1 - enable ECN */
+ __u8 set_default; /* Sets qdisc to be the default qdisc for enqueue */
+ __u8 accel_mode; /* Dictates which data plane offloads the qdisc */
+};
+
+struct tc_nsscodel_xstats {
+ __u32 peak_queue_delay; /* Peak delay experienced by a dequeued packet */
+ __u32 peak_drop_delay; /* Peak delay experienced by a dropped packet */
+};
+
+/* NSSFQ_CODEL section */
+
+struct tc_nssfq_codel_xstats {
+ __u32 new_flow_count; /* Total number of new flows seen */
+ __u32 new_flows_len; /* Current number of new flows */
+ __u32 old_flows_len; /* Current number of old flows */
+ __u32 ecn_mark; /* Number of packets marked with ECN */
+ __u32 drop_overlimit; /* Number of packets dropped due to overlimit */
+ __u32 maxpacket; /* The largest packet seen so far in the queue */
+};
+
+/* NSSTBL section */
+
+enum {
+ TCA_NSSTBL_UNSPEC,
+ TCA_NSSTBL_PARMS,
+ __TCA_NSSTBL_MAX
+};
+
+#define TCA_NSSTBL_MAX (__TCA_NSSTBL_MAX - 1)
+
+struct tc_nsstbl_qopt {
+ __u32 burst; /* Maximum burst size */
+ __u32 rate; /* Limiting rate of TBF */
+ __u32 peakrate; /* Maximum rate at which TBF is allowed to send */
+ __u32 mtu; /* Max size of packet, or minumim burst size */
+ __u8 accel_mode; /* Dictates which data plane offloads the qdisc */
+};
+
+/* NSSPRIO section */
+
+#define TCA_NSSPRIO_MAX_BANDS 256
+
+enum {
+ TCA_NSSPRIO_UNSPEC,
+ TCA_NSSPRIO_PARMS,
+ __TCA_NSSPRIO_MAX
+};
+
+#define TCA_NSSPRIO_MAX (__TCA_NSSPRIO_MAX - 1)
+
+struct tc_nssprio_qopt {
+ __u32 bands; /* Number of bands */
+ __u8 accel_mode; /* Dictates which data plane offloads the qdisc */
+};
+
+/* NSSBF section */
+
+enum {
+ TCA_NSSBF_UNSPEC,
+ TCA_NSSBF_CLASS_PARMS,
+ TCA_NSSBF_QDISC_PARMS,
+ __TCA_NSSBF_MAX
+};
+
+#define TCA_NSSBF_MAX (__TCA_NSSBF_MAX - 1)
+
+struct tc_nssbf_class_qopt {
+ __u32 burst; /* Maximum burst size */
+ __u32 rate; /* Allowed bandwidth for this class */
+ __u32 mtu; /* MTU of the associated interface */
+ __u32 quantum; /* Quantum allocation for DRR */
+};
+
+struct tc_nssbf_qopt {
+ __u16 defcls; /* Default class value */
+ __u8 accel_mode; /* Dictates which data plane offloads the qdisc */
+};
+
+/* NSSWRR section */
+
+enum {
+ TCA_NSSWRR_UNSPEC,
+ TCA_NSSWRR_CLASS_PARMS,
+ TCA_NSSWRR_QDISC_PARMS,
+ __TCA_NSSWRR_MAX
+};
+
+#define TCA_NSSWRR_MAX (__TCA_NSSWRR_MAX - 1)
+
+struct tc_nsswrr_class_qopt {
+ __u32 quantum; /* Weight associated to this class */
+};
+
+struct tc_nsswrr_qopt {
+ __u8 accel_mode; /* Dictates which data plane offloads the qdisc */
+};
+
+/* NSSWFQ section */
+
+enum {
+ TCA_NSSWFQ_UNSPEC,
+ TCA_NSSWFQ_CLASS_PARMS,
+ TCA_NSSWFQ_QDISC_PARMS,
+ __TCA_NSSWFQ_MAX
+};
+
+#define TCA_NSSWFQ_MAX (__TCA_NSSWFQ_MAX - 1)
+
+struct tc_nsswfq_class_qopt {
+ __u32 quantum; /* Weight associated to this class */
+};
+
+struct tc_nsswfq_qopt {
+ __u8 accel_mode; /* Dictates which data plane offloads the qdisc */
+};
+
+/* NSSHTB section */
+
+enum {
+ TCA_NSSHTB_UNSPEC,
+ TCA_NSSHTB_CLASS_PARMS,
+ TCA_NSSHTB_QDISC_PARMS,
+ __TCA_NSSHTB_MAX
+};
+
+#define TCA_NSSHTB_MAX (__TCA_NSSHTB_MAX - 1)
+
+struct tc_nsshtb_class_qopt {
+ __u32 burst; /* Allowed burst size */
+ __u32 rate; /* Allowed bandwidth for this class */
+ __u32 cburst; /* Maximum burst size */
+ __u32 crate; /* Maximum bandwidth for this class */
+ __u32 quantum; /* Quantum allocation for DRR */
+ __u32 priority; /* Priority value associated with this class */
+ __u32 overhead; /* Overhead in bytes per packet */
+};
+
+struct tc_nsshtb_qopt {
+ __u32 r2q; /* Rate to quantum ratio */
+ __u8 accel_mode; /* Dictates which data plane offloads the qdisc */
+};
+
+/* NSSBLACKHOLE section */
+
+enum {
+ TCA_NSSBLACKHOLE_UNSPEC,
+ TCA_NSSBLACKHOLE_PARMS,
+ __TCA_NSSBLACKHOLE_MAX
+};
+
+#define TCA_NSSBLACKHOLE_MAX (__TCA_NSSBLACKHOLE_MAX - 1)
+
+struct tc_nssblackhole_qopt {
+ __u8 set_default; /* Sets qdisc to be the default qdisc for enqueue */
+ __u8 accel_mode; /* Dictates which data plane offloads the qdisc */
+};
+
#endif
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -2399,4 +2399,26 @@ static int __init pktsched_init(void)
return 0;
}
+
+bool tcf_destroy(struct tcf_proto *tp, bool force)
+{
+ tp->ops->destroy(tp, force, NULL);
+ module_put(tp->ops->owner);
+ kfree_rcu(tp, rcu);
+
+ return true;
+}
+
+void tcf_destroy_chain(struct tcf_proto __rcu **fl)
+{
+ struct tcf_proto *tp;
+
+ while ((tp = rtnl_dereference(*fl)) != NULL) {
+ RCU_INIT_POINTER(*fl, tp->next);
+ tcf_destroy(tp, true);
+ }
+}
+EXPORT_SYMBOL(tcf_destroy_chain);
+
+
subsys_initcall(pktsched_init);
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -1059,7 +1059,7 @@ static void qdisc_free_cb(struct rcu_hea
qdisc_free(q);
}
-static void __qdisc_destroy(struct Qdisc *qdisc)
+void __qdisc_destroy(struct Qdisc *qdisc)
{
const struct Qdisc_ops *ops = qdisc->ops;
@@ -1091,6 +1091,7 @@ void qdisc_destroy(struct Qdisc *qdisc)
__qdisc_destroy(qdisc);
}
+EXPORT_SYMBOL(__qdisc_destroy);
void qdisc_put(struct Qdisc *qdisc)
{
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -94,6 +94,7 @@ struct Qdisc {
#define TCQ_F_INVISIBLE 0x80 /* invisible by default in dump */
#define TCQ_F_NOLOCK 0x100 /* qdisc does not require locking */
#define TCQ_F_OFFLOADED 0x200 /* qdisc is offloaded to HW */
+#define TCQ_F_NSS 0x1000 /* NSS qdisc flag. */
u32 limit;
const struct Qdisc_ops *ops;
struct qdisc_size_table __rcu *stab;
@@ -752,6 +753,40 @@ static inline bool skb_skip_tc_classify(
return false;
}
+/*
+ * Set skb classify bit field.
+ */
+static inline void skb_set_tc_classify_offload(struct sk_buff *skb)
+{
+#ifdef CONFIG_NET_CLS_ACT
+ skb->tc_skip_classify_offload = 1;
+#endif
+}
+
+/*
+ * Clear skb classify bit field.
+ */
+static inline void skb_clear_tc_classify_offload(struct sk_buff *skb)
+{
+#ifdef CONFIG_NET_CLS_ACT
+ skb->tc_skip_classify_offload = 0;
+#endif
+}
+
+/*
+ * Skip skb processing if sent from ifb dev.
+ */
+static inline bool skb_skip_tc_classify_offload(struct sk_buff *skb)
+{
+#ifdef CONFIG_NET_CLS_ACT
+ if (skb->tc_skip_classify_offload) {
+ skb_clear_tc_classify_offload(skb);
+ return true;
+ }
+#endif
+ return false;
+}
+
/* Reset all TX qdiscs greater than index of a device. */
static inline void qdisc_reset_all_tx_gt(struct net_device *dev, unsigned int i)
{
@@ -1323,4 +1358,9 @@ static inline void qdisc_synchronize(con
msleep(1);
}
+
+void qdisc_destroy(struct Qdisc *qdisc);
+void tcf_destroy_chain(struct tcf_proto __rcu **fl);
+
+
#endif

View File

@@ -0,0 +1,25 @@
From 507188b4c93e2641fd271bd08d881136a1de2068 Mon Sep 17 00:00:00 2001
From: Ken Zhu <quic_guigenz@quicinc.com>
Date: Thu, 14 Oct 2021 08:50:03 -0700
Subject: [PATCH 260/281] net: fix potential memory leak
When A packets come from a disabled port, if it is not a accepted
EAPOL, it has no chance to get freed.
Change-Id: Ib2bddeb53f2117bcc803d11912471a8456a3148a
Signed-off-by: Ken Zhu <quic_guigenz@quicinc.com>
---
net/bridge/br_input.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -461,7 +461,7 @@ forward:
return RX_HANDLER_PASS;
}
}
- break;
+ goto drop;
case BR_STATE_FORWARDING:
case BR_STATE_LEARNING:

View File

@@ -0,0 +1,39 @@
From af7d2a61b63bdb996746d38288842624e662a447 Mon Sep 17 00:00:00 2001
From: Ratheesh Kannoth <quic_rkannoth@quicinc.com>
Date: Fri, 17 Dec 2021 19:17:58 +0530
Subject: [PATCH 261/281] net: Move skb_vlan_untag(skb) after sfe hook
Change-Id: I5a019761f363dd81bf5e52eea606b9076f22e6af
Signed-off-by: Ratheesh Kannoth <quic_rkannoth@quicinc.com>
---
net/core/dev.c | 19 ++++++-------------
1 file changed, 6 insertions(+), 13 deletions(-)
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -5455,12 +5455,6 @@ another_round:
}
}
- if (eth_type_vlan(skb->protocol)) {
- skb = skb_vlan_untag(skb);
- if (unlikely(!skb))
- goto out;
- }
-
fast_recv = rcu_dereference(athrs_fast_nat_recv);
if (fast_recv) {
if (fast_recv(skb)) {
@@ -5469,6 +5463,12 @@ another_round:
}
}
+ if (eth_type_vlan(skb->protocol)) {
+ skb = skb_vlan_untag(skb);
+ if (unlikely(!skb))
+ goto out;
+ }
+
if (skb_skip_tc_classify(skb))
goto skip_classify;

View File

@@ -0,0 +1,173 @@
From 120ae502af169310aa53359d4faf2494dcee6927 Mon Sep 17 00:00:00 2001
From: Tallapragada Kalyan <quic_ktallapr@quicinc.com>
Date: Thu, 9 Jun 2022 09:32:38 +0530
Subject: [PATCH 267/281] net: set skb's fast_xmit flag in dev_fast_xmit API
set skb's fast_xmit flag in dev_fast_xmit API for linear packets
WiFi tx path can avoid some overhead due to checks based on this flag
Change-Id: Ied29f9d615d0cf48dd9dcd7fcf0fb210eb259a8f
Signed-off-by: Tallapragada Kalyan <quic_ktallapr@quicinc.com>
---
include/linux/skbuff.h | 2 ++
net/core/dev.c | 4 ++++
2 files changed, 6 insertions(+)
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -992,6 +992,8 @@ struct sk_buff {
__u8 csum_not_inet:1;
#endif
__u8 fast_forwarded:1;
+ /* Linear packets processed by dev_fast_xmit() */
+ __u8 fast_xmit:1;
/* 1 or 3 bit hole */
#if defined(CONFIG_NET_SCHED) || defined(CONFIG_NET_XGRESS)
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -4305,6 +4305,144 @@ struct netdev_queue *netdev_core_pick_tx
}
/**
+ * dev_fast_xmit_vp - fast xmit the skb to a PPE virtual port
+ * @skb:buffer to transmit
+ * @dev: the device to be transmited to
+ * sucessful return true
+ * failed return false
+ */
+bool dev_fast_xmit_vp(struct sk_buff *skb,
+ struct net_device *dev)
+{
+ struct netdev_queue *txq;
+ int cpu;
+ netdev_tx_t rc;
+
+ if (unlikely(!(dev->flags & IFF_UP))) {
+ return false;
+ }
+
+ if (unlikely(skb_is_nonlinear(skb))) {
+ return false;
+ }
+
+ rcu_read_lock_bh();
+ cpu = smp_processor_id();
+
+ /*
+ * TODO: Skip this altogether and eventually move this call to ppe_vp
+ * this would avoid multiple function calls when giving packet to wifi VAP.
+ */
+ txq = netdev_core_pick_tx(dev, skb, NULL);
+
+ if (likely(txq->xmit_lock_owner != cpu)) {
+#define FAST_VP_HARD_TX_LOCK(txq, cpu) { \
+ __netif_tx_lock(txq, cpu); \
+}
+
+#define FAST_VP_HARD_TX_UNLOCK(txq) { \
+ __netif_tx_unlock(txq); \
+}
+ skb->fast_xmit = 1;
+ FAST_VP_HARD_TX_LOCK(txq, cpu);
+ if (likely(!netif_xmit_stopped(txq))) {
+ rc = netdev_start_xmit(skb, dev, txq, 0);
+ if (unlikely(!dev_xmit_complete(rc))) {
+ FAST_VP_HARD_TX_UNLOCK(txq);
+ goto q_xmit;
+ }
+ FAST_VP_HARD_TX_UNLOCK(txq);
+ rcu_read_unlock_bh();
+ return true;
+ }
+ FAST_VP_HARD_TX_UNLOCK(txq);
+ }
+q_xmit:
+ skb->fast_xmit = 0;
+ rcu_read_unlock_bh();
+ return false;
+}
+EXPORT_SYMBOL(dev_fast_xmit_vp);
+
+/**
+ * dev_fast_xmit - fast xmit the skb
+ * @skb:buffer to transmit
+ * @dev: the device to be transmited to
+ * @features: the skb features could bed used
+ * sucessful return true
+ * failed return false
+ */
+bool dev_fast_xmit(struct sk_buff *skb,
+ struct net_device *dev,
+ netdev_features_t features)
+{
+ struct netdev_queue *txq;
+ int cpu;
+ netdev_tx_t rc;
+
+ /* the fast_xmit flag will avoid multiple checks in wifi xmit path */
+ if (likely(!skb_is_nonlinear(skb)))
+ skb->fast_xmit = 1;
+
+ if (unlikely(!(dev->flags & IFF_UP))) {
+ return false;
+ }
+
+ if (unlikely(skb_needs_linearize(skb, features))) {
+ return false;
+ }
+
+ rcu_read_lock_bh();
+ cpu = smp_processor_id();
+
+ /* If device don't need the dst, release it now, otherwise make sure
+ * the refcount increased.
+ */
+ if (likely(dev->priv_flags & IFF_XMIT_DST_RELEASE)) {
+ skb_dst_drop(skb);
+ } else {
+ skb_dst_force(skb);
+ }
+
+ txq = netdev_core_pick_tx(dev, skb, NULL);
+
+ if (likely(txq->xmit_lock_owner != cpu)) {
+#define FAST_HARD_TX_LOCK(features, txq, cpu) { \
+ if ((features & NETIF_F_LLTX) == 0) { \
+ __netif_tx_lock(txq, cpu); \
+ } else { \
+ __netif_tx_acquire(txq); \
+ } \
+}
+
+#define FAST_HARD_TX_UNLOCK(features, txq) { \
+ if ((features & NETIF_F_LLTX) == 0) { \
+ __netif_tx_unlock(txq); \
+ } else { \
+ __netif_tx_release(txq); \
+ } \
+}
+ netdev_features_t dev_features = dev->features;
+ FAST_HARD_TX_LOCK(dev_features, txq, cpu);
+ if (likely(!netif_xmit_stopped(txq))) {
+ rc = netdev_start_xmit(skb, dev, txq, 0);
+ if (unlikely(!dev_xmit_complete(rc))) {
+ FAST_HARD_TX_UNLOCK(dev_features, txq);
+ goto fail;
+ }
+ FAST_HARD_TX_UNLOCK(dev_features, txq);
+ rcu_read_unlock_bh();
+ return true;
+ }
+ FAST_HARD_TX_UNLOCK(dev_features, txq);
+ }
+fail:
+ rcu_read_unlock_bh();
+ return false;
+}
+EXPORT_SYMBOL(dev_fast_xmit);
+
+/**
* __dev_queue_xmit() - transmit a buffer
* @skb: buffer to transmit
* @sb_dev: suboordinate device used for L2 forwarding offload

View File

@@ -0,0 +1,52 @@
From 246b87f0daff042ad215c9c55b411e70ae5406e2 Mon Sep 17 00:00:00 2001
From: Ken Zhu <quic_guigenz@quicinc.com>
Date: Mon, 25 Apr 2022 13:54:20 -0700
Subject: [PATCH 263/281] net: do time update rather than fully update in the
fdb
keep the fdb up to date when do refresh.
Change-Id: Ib0297f11920b66bb573ef41f8a09da9ac0d774af
Signed-off-by: Ken Zhu <quic_guigenz@quicinc.com>
---
include/linux/if_bridge.h | 1 +
net/bridge/br_fdb.c | 18 ++++++++++++++++++
2 files changed, 19 insertions(+)
--- a/include/linux/if_bridge.h
+++ b/include/linux/if_bridge.h
@@ -78,6 +78,7 @@ extern struct net_device *br_port_dev_ge
struct sk_buff *skb,
unsigned int cookie);
extern void br_refresh_fdb_entry(struct net_device *dev, const char *addr);
+extern void br_fdb_entry_refresh(struct net_device *dev, const char *addr, __u16 vid);
extern void br_dev_update_stats(struct net_device *dev,
struct rtnl_link_stats64 *nlstats);
extern struct net_bridge_fdb_entry *br_fdb_has_entry(struct net_device *dev,
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -1006,6 +1006,24 @@ void br_refresh_fdb_entry(struct net_dev
}
EXPORT_SYMBOL_GPL(br_refresh_fdb_entry);
+/* Update timestamp of FDB entries for bridge packets being forwarded by offload engines */
+void br_fdb_entry_refresh(struct net_device *dev, const char *addr, __u16 vid)
+{
+ struct net_bridge_fdb_entry *fdb;
+ struct net_bridge_port *p = br_port_get_rcu(dev);
+
+ if (!p || p->state == BR_STATE_DISABLED)
+ return;
+
+ rcu_read_lock();
+ fdb = fdb_find_rcu(&p->br->fdb_hash_tbl, addr, vid);
+ if (likely(fdb)) {
+ fdb->updated = jiffies;
+ }
+ rcu_read_unlock();
+}
+EXPORT_SYMBOL_GPL(br_fdb_entry_refresh);
+
/* Look up the MAC address in the device's bridge fdb table */
struct net_bridge_fdb_entry *br_fdb_has_entry(struct net_device *dev,
const char *addr, __u16 vid)

View File

@@ -0,0 +1,31 @@
From 782c8dfcfeff6115a857ca9299df35cffaf8d476 Mon Sep 17 00:00:00 2001
From: Tushar Ganatra <quic_tganatra@quicinc.com>
Date: Wed, 6 Dec 2023 12:45:26 +0530
Subject: [PATCH] dev_queue_xmit: Reset skb->fast_xmit flag in slow path
transmit
Reset skb->fast_xmit flag in "dev_queue_xmit". This avoids a combination
scenarios like PPPoE with DS-Lite or other tunnels where one rule is matched
with sfe and was transmitted in fast path and the inner is transmitted through
slow path.
Change-Id: Ia12907f459c15747daf00a216672e903c924332a
Signed-off-by: Tushar Ganatra <quic_tganatra@quicinc.com>
---
net/core/dev.c | 5 +++++
1 file changed, 5 insertions(+)
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -4474,6 +4474,11 @@ int __dev_queue_xmit(struct sk_buff *skb
skb_reset_mac_header(skb);
skb_assert_len(skb);
+ /*
+ * if the skb landed in dev_queue_xmit then its not fast transmitted
+ * reset this flag for further processing.
+ */
+ skb->fast_xmit = 0;
if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_SCHED_TSTAMP))
__skb_tstamp_tx(skb, NULL, NULL, skb->sk, SCM_TSTAMP_SCHED);

View File

@@ -0,0 +1,37 @@
--- a/net/bridge/br_forward.c
+++ b/net/bridge/br_forward.c
@@ -24,11 +24,29 @@ static inline int should_deliver(const s
struct net_bridge_vlan_group *vg;
vg = nbp_vlan_group_rcu(p);
- return (((p->flags & BR_HAIRPIN_MODE) && !is_multicast_ether_addr(eth_hdr(skb)->h_dest))
- || skb->dev != p->dev) &&
- (br_mst_is_enabled(p->br) || p->state == BR_STATE_FORWARDING) &&
- br_allowed_egress(vg, skb) && nbp_switchdev_allowed_egress(p, skb) &&
- !br_skb_isolated(p, skb);
+
+ if ((skb->dev != p->dev) &&
+ br_allowed_egress(vg, skb) && p->state == BR_STATE_FORWARDING &&
+ nbp_switchdev_allowed_egress(p, skb) &&
+ !br_skb_isolated(p, skb)) {
+ return true;
+ }
+
+ if ((skb->dev == p->dev) &&
+ (p->flags & BR_HAIRPIN_MODE) &&
+ br_allowed_egress(vg, skb) && p->state == BR_STATE_FORWARDING) {
+
+ /* Allow hairpin only on WLAN netdevices.
+ * For ethernet interfaces, hairpin not allowed
+ * due to issue with switchdevs. */
+ if ( skb->dev->ieee80211_ptr == NULL) {
+ return false;
+ }
+
+ return true;
+ }
+
+ return false;
}
int br_dev_queue_push_xmit(struct net *net, struct sock *sk, struct sk_buff *skb)

View File

@@ -0,0 +1,56 @@
From d34da78089af855bf1406cea24342b0cc4c8225d Mon Sep 17 00:00:00 2001
From: Ken Zhu <quic_guigenz@quicinc.com>
Date: Thu, 4 Apr 2024 16:01:38 -0700
Subject: [PATCH] [net] [bridge] Allow unicast loop back when hairpin enabled
disable multicast go back to the original device for non wireless
device.
Change-Id: Ia5124d2c3d602f71d444f4ac800ddae4b608e4c2
Signed-off-by: Ken Zhu <quic_guigenz@quicinc.com>
---
net/bridge/br_forward.c | 33 +++++++++++----------------------
1 file changed, 11 insertions(+), 22 deletions(-)
--- a/net/bridge/br_forward.c
+++ b/net/bridge/br_forward.c
@@ -25,28 +25,17 @@ static inline int should_deliver(const s
vg = nbp_vlan_group_rcu(p);
- if ((skb->dev != p->dev) &&
- br_allowed_egress(vg, skb) && p->state == BR_STATE_FORWARDING &&
- nbp_switchdev_allowed_egress(p, skb) &&
- !br_skb_isolated(p, skb)) {
- return true;
- }
-
- if ((skb->dev == p->dev) &&
- (p->flags & BR_HAIRPIN_MODE) &&
- br_allowed_egress(vg, skb) && p->state == BR_STATE_FORWARDING) {
-
- /* Allow hairpin only on WLAN netdevices.
- * For ethernet interfaces, hairpin not allowed
- * due to issue with switchdevs. */
- if ( skb->dev->ieee80211_ptr == NULL) {
- return false;
- }
-
- return true;
- }
-
- return false;
+ /*
+ * When hairpin enabled, don't allow multicast go back
+ * to the original non-wireless device.
+ * it could cause fdb learning issue to connected switch.
+ */
+ return (((p->flags & BR_HAIRPIN_MODE)
+ && (skb->dev->ieee80211_ptr != NULL || !is_multicast_ether_addr(eth_hdr(skb)->h_dest)))
+ || (skb->dev != p->dev)) &&
+ br_allowed_egress(vg, skb) && (p->state == BR_STATE_FORWARDING) &&
+ nbp_switchdev_allowed_egress(p, skb) &&
+ !br_skb_isolated(p, skb);
}
int br_dev_queue_push_xmit(struct net *net, struct sock *sk, struct sk_buff *skb)

View File

@@ -0,0 +1,16 @@
--- a/arch/arm/boot/dts/qcom/qcom-ipq8064.dtsi
+++ b/arch/arm/boot/dts/qcom/qcom-ipq8064.dtsi
@@ -917,12 +917,10 @@
qcom,vlan-enabled;
qcom,wlan-dataplane-offload-enabled;
qcom,wlanredirect-enabled;
- qcom,pxvlan-enabled;
qcom,vxlan-enabled;
qcom,match-enabled;
qcom,mirror-enabled;
- qcom,rmnet-enabled;
- qcom,clmap-enabled;
+ qcom,tstamp-enabled;
};
nss1: nss@40800000 {