mirror of
https://github.com/Ysurac/openmptcprouter.git
synced 2025-02-14 12:21:53 +00:00
Add NSS Acceleration Support on Qualcomm devices
This commit is contained in:
parent
359074adc6
commit
e9d1e0219b
54 changed files with 12395 additions and 0 deletions
|
@ -0,0 +1,311 @@
|
|||
From 6504bc9edeb1a2a54d813f4bb5d0267e7bf827f9 Mon Sep 17 00:00:00 2001
|
||||
From: Praveenkumar I <ipkumar@codeaurora.org>
|
||||
Date: Thu, 6 Feb 2020 17:35:42 +0530
|
||||
Subject: [PATCH 4/8] clk: ipq8074: Support added for necessary clocks and
|
||||
reset
|
||||
|
||||
Change-Id: I21a76a44185f766e9b6dcba274392ea8e599718b
|
||||
Signed-off-by: Praveenkumar I <ipkumar@codeaurora.org>
|
||||
Signed-off-by: Rajkumar Ayyasamy <arajkuma@codeaurora.org>
|
||||
---
|
||||
drivers/clk/qcom/gcc-ipq8074.c | 238 ++++++++++++++++++-
|
||||
include/dt-bindings/clock/qcom,gcc-ipq8074.h | 35 ++-
|
||||
2 files changed, 258 insertions(+), 15 deletions(-)
|
||||
|
||||
--- a/drivers/clk/qcom/gcc-ipq8074.c
|
||||
+++ b/drivers/clk/qcom/gcc-ipq8074.c
|
||||
@@ -49,6 +49,22 @@ enum {
|
||||
P_UNIPHY2_TX,
|
||||
};
|
||||
|
||||
+static const char * const gcc_xo_gpll4_gpll0_gpll6_gpll0_div2[] = {
|
||||
+ "xo",
|
||||
+ "gpll4",
|
||||
+ "gpll0",
|
||||
+ "gpll6",
|
||||
+ "gpll0_out_main_div2",
|
||||
+};
|
||||
+
|
||||
+static const struct parent_map gcc_xo_gpll4_gpll0_gpll6_gpll0_div2_map[] = {
|
||||
+ { P_XO, 0 },
|
||||
+ { P_GPLL4, 1 },
|
||||
+ { P_GPLL0, 2 },
|
||||
+ { P_GPLL6, 3 },
|
||||
+ { P_GPLL0_DIV2, 4 },
|
||||
+};
|
||||
+
|
||||
static struct clk_alpha_pll gpll0_main = {
|
||||
.offset = 0x21000,
|
||||
.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
|
||||
@@ -630,6 +646,12 @@ static const struct freq_tbl ftbl_pcie_a
|
||||
{ }
|
||||
};
|
||||
|
||||
+struct freq_tbl ftbl_pcie_rchng_clk_src[] = {
|
||||
+ F(19200000, P_XO, 1, 0, 0),
|
||||
+ F(100000000, P_GPLL0, 8, 0, 0),
|
||||
+ { }
|
||||
+};
|
||||
+
|
||||
static struct clk_rcg2 pcie0_axi_clk_src = {
|
||||
.cmd_rcgr = 0x75054,
|
||||
.freq_tbl = ftbl_pcie_axi_clk_src,
|
||||
@@ -2030,6 +2052,78 @@ static struct clk_rcg2 gp3_clk_src = {
|
||||
},
|
||||
};
|
||||
|
||||
+struct freq_tbl ftbl_qdss_tsctr_clk_src[] = {
|
||||
+ F(160000000, P_GPLL0_DIV2, 2.5, 0, 0),
|
||||
+ F(320000000, P_GPLL0, 2.5, 0, 0),
|
||||
+ F(600000000, P_GPLL6, 2, 0, 0),
|
||||
+ { }
|
||||
+};
|
||||
+
|
||||
+struct clk_rcg2 qdss_tsctr_clk_src = {
|
||||
+ .cmd_rcgr = 0x29064,
|
||||
+ .freq_tbl = ftbl_qdss_tsctr_clk_src,
|
||||
+ .hid_width = 5,
|
||||
+ .parent_map = gcc_xo_gpll4_gpll0_gpll6_gpll0_div2_map,
|
||||
+ .clkr.hw.init = &(struct clk_init_data){
|
||||
+ .name = "qdss_tsctr_clk_src",
|
||||
+ .parent_names = gcc_xo_gpll4_gpll0_gpll6_gpll0_div2,
|
||||
+ .num_parents = 5,
|
||||
+ .ops = &clk_rcg2_ops,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+static struct clk_fixed_factor qdss_dap_sync_clk_src = {
|
||||
+ .mult = 1,
|
||||
+ .div = 4,
|
||||
+ .hw.init = &(struct clk_init_data){
|
||||
+ .name = "qdss_dap_sync_clk_src",
|
||||
+ .parent_names = (const char *[]){
|
||||
+ "qdss_tsctr_clk_src"
|
||||
+ },
|
||||
+ .num_parents = 1,
|
||||
+ .ops = &clk_fixed_factor_ops,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+struct freq_tbl ftbl_qdss_at_clk_src[] = {
|
||||
+ F(66670000, P_GPLL0_DIV2, 6, 0, 0),
|
||||
+ F(240000000, P_GPLL6, 6, 0, 0),
|
||||
+ { }
|
||||
+};
|
||||
+
|
||||
+struct clk_rcg2 qdss_at_clk_src = {
|
||||
+ .cmd_rcgr = 0x2900c,
|
||||
+ .freq_tbl = ftbl_qdss_at_clk_src,
|
||||
+ .hid_width = 5,
|
||||
+ .parent_map = gcc_xo_gpll4_gpll0_gpll6_gpll0_div2_map,
|
||||
+ .clkr.hw.init = &(struct clk_init_data){
|
||||
+ .name = "qdss_at_clk_src",
|
||||
+ .parent_names = gcc_xo_gpll4_gpll0_gpll6_gpll0_div2,
|
||||
+ .num_parents = 5,
|
||||
+ .ops = &clk_rcg2_ops,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+
|
||||
+struct freq_tbl ftbl_adss_pwm_clk_src[] = {
|
||||
+ F(19200000, P_XO, 1, 0, 0),
|
||||
+ F(200000000, P_GPLL0, 4, 0, 0),
|
||||
+ { }
|
||||
+};
|
||||
+
|
||||
+struct clk_rcg2 adss_pwm_clk_src = {
|
||||
+ .cmd_rcgr = 0x1c008,
|
||||
+ .freq_tbl = ftbl_adss_pwm_clk_src,
|
||||
+ .hid_width = 5,
|
||||
+ .parent_map = gcc_xo_gpll0_map,
|
||||
+ .clkr.hw.init = &(struct clk_init_data){
|
||||
+ .name = "adss_pwm_clk_src",
|
||||
+ .parent_data = gcc_xo_gpll0,
|
||||
+ .num_parents = 2,
|
||||
+ .ops = &clk_rcg2_ops,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
static struct clk_branch gcc_blsp1_ahb_clk = {
|
||||
.halt_reg = 0x01008,
|
||||
.clkr = {
|
||||
@@ -4225,13 +4319,7 @@ static struct clk_branch gcc_gp3_clk = {
|
||||
},
|
||||
};
|
||||
|
||||
-static const struct freq_tbl ftbl_pcie_rchng_clk_src[] = {
|
||||
- F(19200000, P_XO, 1, 0, 0),
|
||||
- F(100000000, P_GPLL0, 8, 0, 0),
|
||||
- { }
|
||||
-};
|
||||
-
|
||||
-static struct clk_rcg2 pcie0_rchng_clk_src = {
|
||||
+struct clk_rcg2 pcie0_rchng_clk_src = {
|
||||
.cmd_rcgr = 0x75070,
|
||||
.freq_tbl = ftbl_pcie_rchng_clk_src,
|
||||
.hid_width = 5,
|
||||
@@ -4323,6 +4411,114 @@ static const struct alpha_pll_config nss
|
||||
.alpha_en_mask = BIT(24),
|
||||
};
|
||||
|
||||
+static struct clk_branch gcc_snoc_bus_timeout2_ahb_clk = {
|
||||
+ .halt_reg = 0x4700c,
|
||||
+ .halt_bit = 31,
|
||||
+ .clkr = {
|
||||
+ .enable_reg = 0x4700c,
|
||||
+ .enable_mask = BIT(0),
|
||||
+ .hw.init = &(struct clk_init_data){
|
||||
+ .name = "gcc_snoc_bus_timeout2_ahb_clk",
|
||||
+ .parent_names = (const char *[]){
|
||||
+ "usb0_master_clk_src"
|
||||
+ },
|
||||
+ .num_parents = 1,
|
||||
+ .flags = CLK_SET_RATE_PARENT,
|
||||
+ .ops = &clk_branch2_ops,
|
||||
+ },
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+static struct clk_branch gcc_snoc_bus_timeout3_ahb_clk = {
|
||||
+ .halt_reg = 0x47014,
|
||||
+ .halt_bit = 31,
|
||||
+ .clkr = {
|
||||
+ .enable_reg = 0x47014,
|
||||
+ .enable_mask = BIT(0),
|
||||
+ .hw.init = &(struct clk_init_data){
|
||||
+ .name = "gcc_snoc_bus_timeout3_ahb_clk",
|
||||
+ .parent_names = (const char *[]){
|
||||
+ "usb1_master_clk_src"
|
||||
+ },
|
||||
+ .num_parents = 1,
|
||||
+ .flags = CLK_SET_RATE_PARENT,
|
||||
+ .ops = &clk_branch2_ops,
|
||||
+ },
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+static struct clk_branch gcc_dcc_clk = {
|
||||
+ .halt_reg = 0x77004,
|
||||
+ .halt_bit = 31,
|
||||
+ .clkr = {
|
||||
+ .enable_reg = 0x77004,
|
||||
+ .enable_mask = BIT(0),
|
||||
+ .hw.init = &(struct clk_init_data){
|
||||
+ .name = "gcc_dcc_clk",
|
||||
+ .parent_names = (const char *[]){
|
||||
+ "pcnoc_clk_src"
|
||||
+ },
|
||||
+ .num_parents = 1,
|
||||
+ .flags = CLK_SET_RATE_PARENT,
|
||||
+ .ops = &clk_branch2_ops,
|
||||
+ },
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+static struct clk_branch gcc_qdss_at_clk = {
|
||||
+ .halt_reg = 0x29024,
|
||||
+ .halt_bit = 31,
|
||||
+ .clkr = {
|
||||
+ .enable_reg = 0x29024,
|
||||
+ .enable_mask = BIT(0),
|
||||
+ .hw.init = &(struct clk_init_data){
|
||||
+ .name = "gcc_qdss_at_clk",
|
||||
+ .parent_names = (const char *[]){
|
||||
+ "qdss_at_clk_src"
|
||||
+ },
|
||||
+ .num_parents = 1,
|
||||
+ .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
|
||||
+ .ops = &clk_branch2_ops,
|
||||
+ },
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+static struct clk_branch gcc_qdss_dap_clk = {
|
||||
+ .halt_reg = 0x29084,
|
||||
+ .halt_bit = 31,
|
||||
+ .clkr = {
|
||||
+ .enable_reg = 0x29084,
|
||||
+ .enable_mask = BIT(0),
|
||||
+ .hw.init = &(struct clk_init_data){
|
||||
+ .name = "gcc_qdss_dap_clk",
|
||||
+ .parent_names = (const char *[]){
|
||||
+ "qdss_dap_sync_clk_src"
|
||||
+ },
|
||||
+ .num_parents = 1,
|
||||
+ .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
|
||||
+ .ops = &clk_branch2_ops,
|
||||
+ },
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+static struct clk_branch gcc_adss_pwm_clk = {
|
||||
+ .halt_reg = 0x1c020,
|
||||
+ .halt_bit = 31,
|
||||
+ .clkr = {
|
||||
+ .enable_reg = 0x1c020,
|
||||
+ .enable_mask = BIT(0),
|
||||
+ .hw.init = &(struct clk_init_data){
|
||||
+ .name = "gcc_adss_pwm_clk",
|
||||
+ .parent_names = (const char *[]){
|
||||
+ "adss_pwm_clk_src"
|
||||
+ },
|
||||
+ .num_parents = 1,
|
||||
+ .flags = CLK_SET_RATE_PARENT,
|
||||
+ .ops = &clk_branch2_ops,
|
||||
+ },
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
static struct clk_hw *gcc_ipq8074_hws[] = {
|
||||
&gpll0_out_main_div2.hw,
|
||||
&gpll6_out_main_div2.hw,
|
||||
@@ -4331,6 +4527,7 @@ static struct clk_hw *gcc_ipq8074_hws[]
|
||||
&gcc_xo_div4_clk_src.hw,
|
||||
&nss_noc_clk_src.hw,
|
||||
&nss_ppe_cdiv_clk_src.hw,
|
||||
+ &qdss_dap_sync_clk_src.hw,
|
||||
};
|
||||
|
||||
static struct clk_regmap *gcc_ipq8074_clks[] = {
|
||||
@@ -4562,6 +4759,15 @@ static struct clk_regmap *gcc_ipq8074_cl
|
||||
[GCC_PCIE0_RCHNG_CLK] = &gcc_pcie0_rchng_clk.clkr,
|
||||
[GCC_PCIE0_AXI_S_BRIDGE_CLK] = &gcc_pcie0_axi_s_bridge_clk.clkr,
|
||||
[GCC_CRYPTO_PPE_CLK] = &gcc_crypto_ppe_clk.clkr,
|
||||
+ [GCC_SNOC_BUS_TIMEOUT2_AHB_CLK] = &gcc_snoc_bus_timeout2_ahb_clk.clkr,
|
||||
+ [GCC_SNOC_BUS_TIMEOUT3_AHB_CLK] = &gcc_snoc_bus_timeout3_ahb_clk.clkr,
|
||||
+ [GCC_DCC_CLK] = &gcc_dcc_clk.clkr,
|
||||
+ [QDSS_TSCTR_CLK_SRC] = &qdss_tsctr_clk_src.clkr,
|
||||
+ [QDSS_AT_CLK_SRC] = &qdss_at_clk_src.clkr,
|
||||
+ [GCC_QDSS_AT_CLK] = &gcc_qdss_at_clk.clkr,
|
||||
+ [GCC_QDSS_DAP_CLK] = &gcc_qdss_dap_clk.clkr,
|
||||
+ [ADSS_PWM_CLK_SRC] = &adss_pwm_clk_src.clkr,
|
||||
+ [GCC_ADSS_PWM_CLK] = &gcc_adss_pwm_clk.clkr,
|
||||
};
|
||||
|
||||
static const struct qcom_reset_map gcc_ipq8074_resets[] = {
|
||||
--- a/include/dt-bindings/clock/qcom,gcc-ipq8074.h
|
||||
+++ b/include/dt-bindings/clock/qcom,gcc-ipq8074.h
|
||||
@@ -230,10 +230,19 @@
|
||||
#define GCC_GP1_CLK 221
|
||||
#define GCC_GP2_CLK 222
|
||||
#define GCC_GP3_CLK 223
|
||||
-#define GCC_PCIE0_AXI_S_BRIDGE_CLK 224
|
||||
-#define GCC_PCIE0_RCHNG_CLK_SRC 225
|
||||
-#define GCC_PCIE0_RCHNG_CLK 226
|
||||
-#define GCC_CRYPTO_PPE_CLK 227
|
||||
+#define GCC_CRYPTO_PPE_CLK 224
|
||||
+#define GCC_PCIE0_RCHNG_CLK_SRC 225
|
||||
+#define GCC_PCIE0_RCHNG_CLK 226
|
||||
+#define GCC_PCIE0_AXI_S_BRIDGE_CLK 227
|
||||
+#define GCC_SNOC_BUS_TIMEOUT2_AHB_CLK 228
|
||||
+#define GCC_SNOC_BUS_TIMEOUT3_AHB_CLK 229
|
||||
+#define GCC_DCC_CLK 230
|
||||
+#define ADSS_PWM_CLK_SRC 231
|
||||
+#define GCC_ADSS_PWM_CLK 232
|
||||
+#define QDSS_TSCTR_CLK_SRC 233
|
||||
+#define QDSS_AT_CLK_SRC 234
|
||||
+#define GCC_QDSS_AT_CLK 235
|
||||
+#define GCC_QDSS_DAP_CLK 236
|
||||
|
||||
#define GCC_BLSP1_BCR 0
|
||||
#define GCC_BLSP1_QUP1_BCR 1
|
|
@ -0,0 +1,44 @@
|
|||
From 462aa0c53397ec5bf78e3e7f68aa8a3ca300f4ba Mon Sep 17 00:00:00 2001
|
||||
From: Selvam Sathappan Periakaruppan <speriaka@codeaurora.org>
|
||||
Date: Tue, 24 Mar 2020 19:09:38 +0530
|
||||
Subject: [PATCH 5/8] clk: qcom: ipq8074: Fix gcc_snoc_bus_timeout_ahb_clk
|
||||
offset
|
||||
|
||||
By default, the ipq8074 V2 clks are provided in the gcc driver.
|
||||
Updating the gcc_snoc_bus_timeout_ahb_clk offsets also as needed
|
||||
in ipq8074 V2.
|
||||
|
||||
Change-Id: I5a6e98d002f5c3354a804e55dd9ebb1f83f7f974
|
||||
Signed-off-by: Selvam Sathappan Periakaruppan <speriaka@codeaurora.org>
|
||||
---
|
||||
drivers/clk/qcom/gcc-ipq8074.c | 8 ++++----
|
||||
1 file changed, 4 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/drivers/clk/qcom/gcc-ipq8074.c
|
||||
+++ b/drivers/clk/qcom/gcc-ipq8074.c
|
||||
@@ -4412,10 +4412,10 @@ static const struct alpha_pll_config nss
|
||||
};
|
||||
|
||||
static struct clk_branch gcc_snoc_bus_timeout2_ahb_clk = {
|
||||
- .halt_reg = 0x4700c,
|
||||
+ .halt_reg = 0x47014,
|
||||
.halt_bit = 31,
|
||||
.clkr = {
|
||||
- .enable_reg = 0x4700c,
|
||||
+ .enable_reg = 0x47014,
|
||||
.enable_mask = BIT(0),
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "gcc_snoc_bus_timeout2_ahb_clk",
|
||||
@@ -4430,10 +4430,10 @@ static struct clk_branch gcc_snoc_bus_ti
|
||||
};
|
||||
|
||||
static struct clk_branch gcc_snoc_bus_timeout3_ahb_clk = {
|
||||
- .halt_reg = 0x47014,
|
||||
+ .halt_reg = 0x4701C,
|
||||
.halt_bit = 31,
|
||||
.clkr = {
|
||||
- .enable_reg = 0x47014,
|
||||
+ .enable_reg = 0x4701C,
|
||||
.enable_mask = BIT(0),
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "gcc_snoc_bus_timeout3_ahb_clk",
|
|
@ -0,0 +1,41 @@
|
|||
From 52315bec6ed633b6a71f28b746029602f8bd70b9 Mon Sep 17 00:00:00 2001
|
||||
From: Balaji Prakash J <bjagadee@codeaurora.org>
|
||||
Date: Wed, 22 Apr 2020 20:35:30 +0530
|
||||
Subject: [PATCH] clk: ipq8074: fix gcc_blsp1_ahb_clk properties
|
||||
|
||||
All the voting enabled clocks does not support the enable
|
||||
from CBCR register. So, updated gcc_blsp1_ahb_clk enable
|
||||
register and mask to enable bit in APCS_CLOCK_BRANCH_ENA_VOTE.
|
||||
|
||||
Also, the voting controlled clocks are shared among multiple
|
||||
components like APSS, RPM, NSS, TZ, etc. So, turning the
|
||||
voting off from APSS does not make the clock off if it has
|
||||
been voted from another component. Added the flag
|
||||
BRANCH_HALT_VOTED in order to skip checking the clock
|
||||
disable status.
|
||||
|
||||
This change is referred from the below commits,
|
||||
1. 246b4fb3af9bd65d8af794aac2f0e7b1ed9cc2dd
|
||||
2. c8374157d5ae91d3b3e0d513d62808a798b32d3a
|
||||
|
||||
Signed-off-by: Balaji Prakash J <bjagadee@codeaurora.org>
|
||||
Change-Id: I505cb560b31ad27a02c165fbe13bb33a2fc7d230
|
||||
---
|
||||
drivers/clk/qcom/gcc-ipq8074.c | 5 +++--
|
||||
1 file changed, 3 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/clk/qcom/gcc-ipq8074.c
|
||||
+++ b/drivers/clk/qcom/gcc-ipq8074.c
|
||||
@@ -2126,9 +2126,10 @@ struct clk_rcg2 adss_pwm_clk_src = {
|
||||
|
||||
static struct clk_branch gcc_blsp1_ahb_clk = {
|
||||
.halt_reg = 0x01008,
|
||||
+ .halt_check = BRANCH_HALT_VOTED,
|
||||
.clkr = {
|
||||
- .enable_reg = 0x01008,
|
||||
- .enable_mask = BIT(0),
|
||||
+ .enable_reg = 0x0b004,
|
||||
+ .enable_mask = BIT(10),
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "gcc_blsp1_ahb_clk",
|
||||
.parent_hws = (const struct clk_hw *[]){
|
|
@ -0,0 +1,878 @@
|
|||
--- a/include/linux/if_bridge.h
|
||||
+++ b/include/linux/if_bridge.h
|
||||
@@ -69,6 +69,9 @@ 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 void br_dev_update_stats(struct net_device *dev,
|
||||
+ struct rtnl_link_stats64 *nlstats);
|
||||
+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,
|
||||
@@ -211,4 +214,42 @@ static inline clock_t br_get_ageing_time
|
||||
}
|
||||
#endif
|
||||
|
||||
+/* QCA NSS ECM support - Start */
|
||||
+extern struct net_device *br_port_dev_get(struct net_device *dev,
|
||||
+ unsigned char *addr,
|
||||
+ 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 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);
|
||||
+
|
||||
+typedef struct net_bridge_port *br_port_dev_get_hook_t(struct net_device *dev,
|
||||
+ struct sk_buff *skb,
|
||||
+ unsigned char *addr,
|
||||
+ unsigned int cookie);
|
||||
+extern br_port_dev_get_hook_t __rcu *br_port_dev_get_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;
|
||||
+ 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);
|
||||
+
|
||||
+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;
|
||||
+/* QCA NSS ECM support - End */
|
||||
+
|
||||
#endif
|
||||
--- a/include/linux/if_vlan.h
|
||||
+++ b/include/linux/if_vlan.h
|
||||
@@ -143,7 +143,10 @@ 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); /* QCA NSS ECM support */
|
||||
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); /* QCA NSS ECM support */
|
||||
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)
|
||||
+{
|
||||
+
|
||||
+} /* QCA NSS ECM support - End */
|
||||
+
|
||||
static inline struct net_device *
|
||||
__vlan_find_dev_deep_rcu(struct net_device *real_dev,
|
||||
__be16 vlan_proto, u16 vlan_id)
|
||||
--- a/include/linux/netdevice.h
|
||||
+++ b/include/linux/netdevice.h
|
||||
@@ -2855,6 +2855,10 @@ enum netdev_cmd {
|
||||
NETDEV_OFFLOAD_XSTATS_DISABLE,
|
||||
NETDEV_OFFLOAD_XSTATS_REPORT_USED,
|
||||
NETDEV_OFFLOAD_XSTATS_REPORT_DELTA,
|
||||
+ /* QCA NSS ECM Support - Start */
|
||||
+ NETDEV_BR_JOIN,
|
||||
+ NETDEV_BR_LEAVE,
|
||||
+ /* QCA NSS ECM Support - End */
|
||||
};
|
||||
const char *netdev_cmd_to_name(enum netdev_cmd cmd);
|
||||
|
||||
--- a/include/net/ip6_route.h
|
||||
+++ b/include/net/ip6_route.h
|
||||
@@ -211,6 +211,11 @@ void rt6_multipath_rebalance(struct fib6
|
||||
void rt6_uncached_list_add(struct rt6_info *rt);
|
||||
void rt6_uncached_list_del(struct rt6_info *rt);
|
||||
|
||||
+/* QCA NSS ECM support - Start */
|
||||
+int rt6_register_notifier(struct notifier_block *nb);
|
||||
+int rt6_unregister_notifier(struct notifier_block *nb);
|
||||
+/* QCA NSS ECM support - End */
|
||||
+
|
||||
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/neighbour.h
|
||||
+++ b/include/net/neighbour.h
|
||||
@@ -249,6 +249,13 @@ static inline int neigh_parms_family(str
|
||||
return p->tbl->family;
|
||||
}
|
||||
|
||||
+/* QCA NSS ECM support - Start */
|
||||
+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))];
|
||||
+};
|
||||
+/* QCA NSS ECM support - End */
|
||||
+
|
||||
#define NEIGH_PRIV_ALIGN sizeof(long long)
|
||||
#define NEIGH_ENTRY_SIZE(size) ALIGN((size), NEIGH_PRIV_ALIGN)
|
||||
|
||||
@@ -397,6 +404,11 @@ int neigh_xmit(int fam, struct net_devic
|
||||
void pneigh_for_each(struct neigh_table *tbl,
|
||||
void (*cb)(struct pneigh_entry *));
|
||||
|
||||
+/* QCA NSS ECM support - Start */
|
||||
+extern void neigh_mac_update_register_notify(struct notifier_block *nb);
|
||||
+extern void neigh_mac_update_unregister_notify(struct notifier_block *nb);
|
||||
+/* QCA NSS ECM support - End */
|
||||
+
|
||||
struct neigh_seq_state {
|
||||
struct seq_net_private p;
|
||||
struct neigh_table *tbl;
|
||||
@@ -602,4 +614,5 @@ static inline void neigh_update_is_route
|
||||
*notify = 1;
|
||||
}
|
||||
}
|
||||
+
|
||||
#endif
|
||||
--- a/include/net/route.h
|
||||
+++ b/include/net/route.h
|
||||
@@ -240,6 +240,11 @@ 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);
|
||||
|
||||
+/* QCA NSS ECM support - Start */
|
||||
+int ip_rt_register_notifier(struct notifier_block *nb);
|
||||
+int ip_rt_unregister_notifier(struct notifier_block *nb);
|
||||
+/* QCA NSS ECM support - End */
|
||||
+
|
||||
struct in_ifaddr;
|
||||
void fib_add_ifaddr(struct in_ifaddr *);
|
||||
void fib_del_ifaddr(struct in_ifaddr *, struct in_ifaddr *);
|
||||
--- a/net/bridge/br_private.h
|
||||
+++ b/net/bridge/br_private.h
|
||||
@@ -2172,4 +2172,9 @@ void br_do_proxy_suppress_arp(struct sk_
|
||||
void br_do_suppress_nd(struct sk_buff *skb, struct net_bridge *br,
|
||||
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);
|
||||
+
|
||||
+/* QCA NSS ECM support - Start */
|
||||
+#define __br_get(__hook, __default, __args ...) \
|
||||
+ (__hook ? (__hook(__args)) : (__default))
|
||||
+/* QCA NSS ECM support - End */
|
||||
#endif
|
||||
--- a/net/8021q/vlan_core.c
|
||||
+++ b/net/8021q/vlan_core.c
|
||||
@@ -72,6 +72,28 @@ bool vlan_do_receive(struct sk_buff **sk
|
||||
return true;
|
||||
}
|
||||
|
||||
+/* QCA NSS ECM support - Start */
|
||||
+/* 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 = per_cpu_ptr(vlan_dev_priv(dev)->vlan_pcpu_stats, 0);
|
||||
+
|
||||
+ 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);
|
||||
+/* QCA NSS ECM support - End */
|
||||
+
|
||||
/* 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)
|
||||
@@ -110,6 +132,15 @@ struct net_device *vlan_dev_real_dev(con
|
||||
}
|
||||
EXPORT_SYMBOL(vlan_dev_real_dev);
|
||||
|
||||
+/* QCA NSS ECM support - Start */
|
||||
+/* 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);
|
||||
+/* QCA NSS ECM support - End */
|
||||
+
|
||||
u16 vlan_dev_vlan_id(const struct net_device *dev)
|
||||
{
|
||||
return vlan_dev_priv(dev)->vlan_id;
|
||||
--- 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",
|
||||
@@ -188,6 +202,25 @@ static void fdb_notify(struct net_bridge
|
||||
if (swdev_notify)
|
||||
br_switchdev_fdb_notify(br, fdb, type);
|
||||
|
||||
+ /* QCA NSS ECM support - Start */
|
||||
+ 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);
|
||||
+ }
|
||||
+ /* QCA NSS ECM support - End */
|
||||
+
|
||||
skb = nlmsg_new(fdb_nlmsg_size(), GFP_ATOMIC);
|
||||
if (skb == NULL)
|
||||
goto errout;
|
||||
@@ -512,6 +545,22 @@ out:
|
||||
spin_unlock_bh(&br->hash_lock);
|
||||
}
|
||||
|
||||
+/* QCA NSS ECM support - Start */
|
||||
+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);
|
||||
+/* QCA NSS ECM support - End */
|
||||
+
|
||||
void br_fdb_cleanup(struct work_struct *work)
|
||||
{
|
||||
struct net_bridge *br = container_of(work, struct net_bridge,
|
||||
@@ -520,6 +569,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]; /* QCA NSS ECM support */
|
||||
|
||||
/* this part is tricky, in order to avoid blocking learning and
|
||||
* consequently forwarding, we rely on rcu to delete objects with
|
||||
@@ -546,8 +596,15 @@ 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))
|
||||
+ if (!hlist_unhashed(&f->fdb_node)) {
|
||||
+ ether_addr_copy(mac_addr, f->key.addr.addr);
|
||||
fdb_delete(br, f, true);
|
||||
+ /* QCA NSS ECM support - Start */
|
||||
+ atomic_notifier_call_chain(
|
||||
+ &br_fdb_update_notifier_list, 0,
|
||||
+ (void *)mac_addr);
|
||||
+ /* QCA NSS ECM support - End */
|
||||
+ }
|
||||
spin_unlock_bh(&br->hash_lock);
|
||||
}
|
||||
}
|
||||
@@ -879,6 +936,12 @@ void br_fdb_update(struct net_bridge *br
|
||||
&fdb->flags)))
|
||||
clear_bit(BR_FDB_ADDED_BY_EXT_LEARN,
|
||||
&fdb->flags);
|
||||
+
|
||||
+ /* QCA NSS ECM support - Start */
|
||||
+ atomic_notifier_call_chain(
|
||||
+ &br_fdb_update_notifier_list,
|
||||
+ 0, (void *)addr);
|
||||
+ /* QCA NSS ECM support - End */
|
||||
}
|
||||
|
||||
if (unlikely(test_bit(BR_FDB_ADDED_BY_USER, &flags)))
|
||||
@@ -902,6 +965,64 @@ void br_fdb_update(struct net_bridge *br
|
||||
}
|
||||
}
|
||||
|
||||
+/* QCA NSS ECM support - Start */
|
||||
+/* 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);
|
||||
+
|
||||
+/* 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)
|
||||
+{
|
||||
+ 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);
|
||||
+
|
||||
+/* QCA NSS ECM support - End */
|
||||
/* 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
|
||||
@@ -26,6 +26,12 @@
|
||||
|
||||
#include "br_private.h"
|
||||
|
||||
+/* QCA NSS ECM support - Start */
|
||||
+/* 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);
|
||||
+/* QCA NSS ECM support - End */
|
||||
+
|
||||
/*
|
||||
* Determine initial path cost based on speed.
|
||||
* using recommendations from 802.1d standard
|
||||
@@ -697,6 +703,8 @@ int br_add_if(struct net_bridge *br, str
|
||||
|
||||
kobject_uevent(&p->kobj, KOBJ_ADD);
|
||||
|
||||
+ call_netdevice_notifiers(NETDEV_BR_JOIN, dev); /* QCA NSS ECM support */
|
||||
+
|
||||
return 0;
|
||||
|
||||
err6:
|
||||
@@ -732,6 +740,8 @@ int br_del_if(struct net_bridge *br, str
|
||||
if (!p || p->br != br)
|
||||
return -EINVAL;
|
||||
|
||||
+ call_netdevice_notifiers(NETDEV_BR_LEAVE, dev); /* QCA NSS ECM support */
|
||||
+
|
||||
/* 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.
|
||||
@@ -775,3 +785,97 @@ 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()
|
||||
+ * 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 sk_buff *skb,
|
||||
+ unsigned int cookie)
|
||||
+{
|
||||
+ 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;
|
||||
+
|
||||
+ 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,
|
||||
+ addr, cookie);
|
||||
+ 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 */
|
||||
+ 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;
|
||||
+}
|
||||
+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 pcpu_sw_netstats *tstats;
|
||||
+
|
||||
+ /* Is this a bridge? */
|
||||
+ if (!(dev->priv_flags & IFF_EBRIDGE))
|
||||
+ return;
|
||||
+
|
||||
+ tstats = this_cpu_ptr(dev->tstats);
|
||||
+
|
||||
+ u64_stats_update_begin(&tstats->syncp);
|
||||
+ u64_stats_add(&tstats->rx_packets, nlstats->rx_packets);
|
||||
+ u64_stats_add(&tstats->rx_bytes, nlstats->rx_bytes);
|
||||
+ u64_stats_add(&tstats->tx_packets, nlstats->tx_packets);
|
||||
+ u64_stats_add(&tstats->tx_bytes, nlstats->tx_bytes);
|
||||
+ u64_stats_update_end(&tstats->syncp);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(br_dev_update_stats);
|
||||
+
|
||||
+/* QCA NSS ECM support - Start */
|
||||
+/* 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);
|
||||
+
|
||||
+/* QCA NSS ECM support - End */
|
||||
--- a/net/core/neighbour.c
|
||||
+++ b/net/core/neighbour.c
|
||||
@@ -1275,6 +1275,22 @@ static void neigh_update_hhs(struct neig
|
||||
}
|
||||
}
|
||||
|
||||
+/* QCA NSS ECM support - Start */
|
||||
+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);
|
||||
+/* QCA NSS ECM support - End */
|
||||
+
|
||||
/* Generic update routine.
|
||||
-- lladdr is new lladdr or NULL, if it is not supplied.
|
||||
-- new is new state.
|
||||
@@ -1303,6 +1319,7 @@ static int __neigh_update(struct neighbo
|
||||
struct net_device *dev;
|
||||
int err, notify = 0;
|
||||
u8 old;
|
||||
+ struct neigh_mac_update nmu; /* QCA NSS ECM support */
|
||||
|
||||
trace_neigh_update(neigh, lladdr, new, flags, nlmsg_pid);
|
||||
|
||||
@@ -1317,7 +1334,10 @@ static int __neigh_update(struct neighbo
|
||||
new = old;
|
||||
goto out;
|
||||
}
|
||||
- if (!(flags & NEIGH_UPDATE_F_ADMIN) &&
|
||||
+
|
||||
+ memset(&nmu, 0, sizeof(struct neigh_mac_update)); /* QCA NSS ECM support */
|
||||
+
|
||||
+ if (!(flags & NEIGH_UPDATE_F_ADMIN) &&
|
||||
(old & (NUD_NOARP | NUD_PERMANENT)))
|
||||
goto out;
|
||||
|
||||
@@ -1354,7 +1374,12 @@ static int __neigh_update(struct neighbo
|
||||
- compare new & old
|
||||
- if they are different, check override flag
|
||||
*/
|
||||
- if ((old & NUD_VALID) &&
|
||||
+ /* QCA NSS ECM update - Start */
|
||||
+ memcpy(nmu.old_mac, neigh->ha, dev->addr_len);
|
||||
+ memcpy(nmu.update_mac, lladdr, dev->addr_len);
|
||||
+ /* QCA NSS ECM update - End */
|
||||
+
|
||||
+ if ((old & NUD_VALID) &&
|
||||
!memcmp(lladdr, neigh->ha, dev->addr_len))
|
||||
lladdr = neigh->ha;
|
||||
} else {
|
||||
@@ -1476,8 +1501,11 @@ 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); /* QCA NSS ECM support */
|
||||
+ }
|
||||
trace_neigh_update_done(neigh, err);
|
||||
return err;
|
||||
}
|
||||
--- 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); /* QCA NSS ECM support */
|
||||
+
|
||||
/* 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,9 @@ 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:
|
||||
@@ -1775,6 +1781,9 @@ 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;
|
||||
@@ -2407,6 +2416,20 @@ void __init fib_trie_init(void)
|
||||
0, SLAB_PANIC | SLAB_ACCOUNT, NULL);
|
||||
}
|
||||
|
||||
+/* QCA NSS ECM support - Start */
|
||||
+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);
|
||||
+/* QCA NSS ECM support - End */
|
||||
+
|
||||
struct fib_table *fib_trie_table(u32 id, struct fib_table *alias)
|
||||
{
|
||||
struct fib_table *tb;
|
||||
--- a/net/ipv6/ndisc.c
|
||||
+++ b/net/ipv6/ndisc.c
|
||||
@@ -666,6 +666,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)
|
||||
--- a/net/ipv6/route.c
|
||||
+++ b/net/ipv6/route.c
|
||||
@@ -197,6 +197,9 @@ static void rt6_uncached_list_flush_dev(
|
||||
}
|
||||
}
|
||||
|
||||
+/* Define route change notification chain. */
|
||||
+ATOMIC_NOTIFIER_HEAD(ip6route_chain); /* QCA NSS ECM support */
|
||||
+
|
||||
static inline const void *choose_neigh_daddr(const struct in6_addr *p,
|
||||
struct sk_buff *skb,
|
||||
const void *daddr)
|
||||
@@ -3865,6 +3868,10 @@ 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;
|
||||
@@ -3886,6 +3893,9 @@ static int __ip6_del_rt(struct fib6_info
|
||||
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;
|
||||
@@ -6339,6 +6349,20 @@ static int ip6_route_dev_notify(struct n
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
+/* QCA NSS ECM support - Start */
|
||||
+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);
|
||||
+/* QCA NSS ECM support - End */
|
||||
+
|
||||
/*
|
||||
* /proc
|
||||
*/
|
||||
--- a/net/core/dev.c
|
||||
+++ b/net/core/dev.c
|
||||
@@ -1639,6 +1639,7 @@ const char *netdev_cmd_to_name(enum netd
|
||||
N(SVLAN_FILTER_PUSH_INFO) N(SVLAN_FILTER_DROP_INFO)
|
||||
N(PRE_CHANGEADDR) N(OFFLOAD_XSTATS_ENABLE) N(OFFLOAD_XSTATS_DISABLE)
|
||||
N(OFFLOAD_XSTATS_REPORT_USED) N(OFFLOAD_XSTATS_REPORT_DELTA)
|
||||
+ N(BR_JOIN) N(BR_LEAVE)
|
||||
}
|
||||
#undef N
|
||||
return "UNKNOWN_NETDEV_EVENT";
|
||||
--- a/net/ipv6/addrconf.c
|
||||
+++ b/net/ipv6/addrconf.c
|
||||
@@ -1002,6 +1002,7 @@ void inet6_ifa_finish_destroy(struct ine
|
||||
|
||||
kfree_rcu(ifp, rcu);
|
||||
}
|
||||
+EXPORT_SYMBOL(inet6_ifa_finish_destroy);
|
||||
|
||||
static void
|
||||
ipv6_link_dev_addr(struct inet6_dev *idev, struct inet6_ifaddr *ifp)
|
||||
--- a/include/net/vxlan.h
|
||||
+++ b/include/net/vxlan.h
|
||||
@@ -432,6 +432,15 @@ static inline __be32 vxlan_compute_rco(u
|
||||
return vni_field;
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * vxlan_get_vni()
|
||||
+ * Returns the vni corresponding to tunnel
|
||||
+ */
|
||||
+static inline u32 vxlan_get_vni(struct vxlan_dev *vxlan_tun)
|
||||
+{
|
||||
+ return be32_to_cpu(vxlan_tun->cfg.vni);
|
||||
+}
|
||||
+
|
||||
static inline unsigned short vxlan_get_sk_family(struct vxlan_sock *vs)
|
||||
{
|
||||
return vs->sock->sk->sk_family;
|
||||
--- a/include/uapi/linux/in.h
|
||||
+++ b/include/uapi/linux/in.h
|
||||
@@ -63,6 +63,8 @@ enum {
|
||||
#define IPPROTO_MTP IPPROTO_MTP
|
||||
IPPROTO_BEETPH = 94, /* IP option pseudo header for BEET */
|
||||
#define IPPROTO_BEETPH IPPROTO_BEETPH
|
||||
+ IPPROTO_ETHERIP = 97, /* ETHERIP protocol number */
|
||||
+#define IPPROTO_ETHERIP IPPROTO_ETHERIP
|
||||
IPPROTO_ENCAP = 98, /* Encapsulation Header */
|
||||
#define IPPROTO_ENCAP IPPROTO_ENCAP
|
||||
IPPROTO_PIM = 103, /* Protocol Independent Multicast */
|
||||
@@ -327,7 +329,7 @@ struct sockaddr_in {
|
||||
#endif
|
||||
|
||||
/* <asm/byteorder.h> contains the htonl type stuff.. */
|
||||
-#include <asm/byteorder.h>
|
||||
+#include <asm/byteorder.h>
|
||||
|
||||
|
||||
#endif /* _UAPI_LINUX_IN_H */
|
||||
--- a/tools/include/uapi/linux/in.h
|
||||
+++ b/tools/include/uapi/linux/in.h
|
||||
@@ -63,6 +63,8 @@ enum {
|
||||
#define IPPROTO_MTP IPPROTO_MTP
|
||||
IPPROTO_BEETPH = 94, /* IP option pseudo header for BEET */
|
||||
#define IPPROTO_BEETPH IPPROTO_BEETPH
|
||||
+ IPPROTO_ETHERIP = 97, /* ETHERIP protocol number */
|
||||
+#define IPPROTO_ETHERIP IPPROTO_ETHERIP
|
||||
IPPROTO_ENCAP = 98, /* Encapsulation Header */
|
||||
#define IPPROTO_ENCAP IPPROTO_ENCAP
|
||||
IPPROTO_PIM = 103, /* Protocol Independent Multicast */
|
||||
@@ -327,7 +329,7 @@ struct sockaddr_in {
|
||||
#endif
|
||||
|
||||
/* <asm/byteorder.h> contains the htonl type stuff.. */
|
||||
-#include <asm/byteorder.h>
|
||||
+#include <asm/byteorder.h>
|
||||
|
||||
|
||||
#endif /* _UAPI_LINUX_IN_H */
|
||||
--- a/net/netfilter/nf_conntrack_ecache.c
|
||||
+++ b/net/netfilter/nf_conntrack_ecache.c
|
||||
@@ -266,7 +266,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);
|
||||
}
|
||||
--- 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
|
||||
@@ -513,11 +513,15 @@ tcp_in_window(struct nf_conn *ct, enum ip_conntrack_dir dir,
|
||||
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.
|
||||
*/
|
||||
@@ -1257,7 +1261,7 @@ int nf_conntrack_tcp_packet(struct nf_conn *ct,
|
||||
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
|
||||
@@ -1573,6 +1577,9 @@ void nf_conntrack_tcp_init_net(struct net *net)
|
||||
*/
|
||||
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
|
||||
@@ -637,6 +637,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,
|
||||
@@ -844,6 +845,14 @@ static struct ctl_table nf_ct_sysctl_table[] = {
|
||||
.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),
|
||||
@@ -1054,6 +1063,7 @@ static void nf_conntrack_standalone_init_tcp_sysctl(struct net *net,
|
||||
|
||||
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
|
|
@ -0,0 +1,600 @@
|
|||
--- a/drivers/net/ppp/ppp_generic.c
|
||||
+++ b/drivers/net/ppp/ppp_generic.c
|
||||
@@ -48,6 +48,7 @@
|
||||
#include <net/slhc_vj.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/refcount.h>
|
||||
+#include <linux/if_pppox.h>
|
||||
|
||||
#include <linux/nsproxy.h>
|
||||
#include <net/net_namespace.h>
|
||||
@@ -254,6 +255,25 @@ struct ppp_net {
|
||||
#define seq_before(a, b) ((s32)((a) - (b)) < 0)
|
||||
#define seq_after(a, b) ((s32)((a) - (b)) > 0)
|
||||
|
||||
+
|
||||
+/*
|
||||
+ * Registration/Unregistration methods
|
||||
+ * for PPP channel connect and disconnect event notifications.
|
||||
+ */
|
||||
+RAW_NOTIFIER_HEAD(ppp_channel_connection_notifier_list);
|
||||
+
|
||||
+void ppp_channel_connection_register_notify(struct notifier_block *nb)
|
||||
+{
|
||||
+ raw_notifier_chain_register(&ppp_channel_connection_notifier_list, nb);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(ppp_channel_connection_register_notify);
|
||||
+
|
||||
+void ppp_channel_connection_unregister_notify(struct notifier_block *nb)
|
||||
+{
|
||||
+ raw_notifier_chain_unregister(&ppp_channel_connection_notifier_list, nb);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(ppp_channel_connection_unregister_notify);
|
||||
+
|
||||
/* Prototypes. */
|
||||
static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf,
|
||||
struct file *file, unsigned int cmd, unsigned long arg);
|
||||
@@ -3453,7 +3473,10 @@ ppp_connect_channel(struct channel *pch,
|
||||
struct ppp_net *pn;
|
||||
int ret = -ENXIO;
|
||||
int hdrlen;
|
||||
+ int ppp_proto;
|
||||
+ int version;
|
||||
|
||||
+ int notify = 0;
|
||||
pn = ppp_pernet(pch->chan_net);
|
||||
|
||||
mutex_lock(&pn->all_ppp_mutex);
|
||||
@@ -3485,13 +3508,40 @@ ppp_connect_channel(struct channel *pch,
|
||||
++ppp->n_channels;
|
||||
pch->ppp = ppp;
|
||||
refcount_inc(&ppp->file.refcnt);
|
||||
+
|
||||
+ /* Set the netdev priv flag if the prototype
|
||||
+ * is L2TP or PPTP. Return success in all cases
|
||||
+ */
|
||||
+ if (!pch->chan)
|
||||
+ goto out2;
|
||||
+
|
||||
+ ppp_proto = ppp_channel_get_protocol(pch->chan);
|
||||
+ if (ppp_proto == PX_PROTO_PPTP) {
|
||||
+ ppp->dev->priv_flags_ext |= IFF_EXT_PPP_PPTP;
|
||||
+ } else if (ppp_proto == PX_PROTO_OL2TP) {
|
||||
+ version = ppp_channel_get_proto_version(pch->chan);
|
||||
+ if (version == 2)
|
||||
+ ppp->dev->priv_flags_ext |= IFF_EXT_PPP_L2TPV2;
|
||||
+ else if (version == 3)
|
||||
+ ppp->dev->priv_flags_ext |= IFF_EXT_PPP_L2TPV3;
|
||||
+ }
|
||||
+ notify = 1;
|
||||
+
|
||||
+ out2:
|
||||
ppp_unlock(ppp);
|
||||
ret = 0;
|
||||
-
|
||||
outl:
|
||||
write_unlock_bh(&pch->upl);
|
||||
out:
|
||||
mutex_unlock(&pn->all_ppp_mutex);
|
||||
+
|
||||
+ if (notify && ppp && ppp->dev) {
|
||||
+ dev_hold(ppp->dev);
|
||||
+ raw_notifier_call_chain(&ppp_channel_connection_notifier_list,
|
||||
+ PPP_CHANNEL_CONNECT, ppp->dev);
|
||||
+ dev_put(ppp->dev);
|
||||
+ }
|
||||
+
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -3509,6 +3559,13 @@ ppp_disconnect_channel(struct channel *p
|
||||
pch->ppp = NULL;
|
||||
write_unlock_bh(&pch->upl);
|
||||
if (ppp) {
|
||||
+ if (ppp->dev) {
|
||||
+ dev_hold(ppp->dev);
|
||||
+ raw_notifier_call_chain(&ppp_channel_connection_notifier_list,
|
||||
+ PPP_CHANNEL_DISCONNECT, ppp->dev);
|
||||
+ dev_put(ppp->dev);
|
||||
+ }
|
||||
+
|
||||
/* remove it from the ppp unit's list */
|
||||
ppp_lock(ppp);
|
||||
list_del(&pch->clist);
|
||||
@@ -3588,6 +3645,222 @@ static void *unit_find(struct idr *p, in
|
||||
return idr_find(p, n);
|
||||
}
|
||||
|
||||
+/* Updates the PPP interface statistics. */
|
||||
+void ppp_update_stats(struct net_device *dev, unsigned long rx_packets,
|
||||
+ unsigned long rx_bytes, unsigned long tx_packets,
|
||||
+ unsigned long tx_bytes, unsigned long rx_errors,
|
||||
+ unsigned long tx_errors, unsigned long rx_dropped,
|
||||
+ unsigned long tx_dropped)
|
||||
+{
|
||||
+ struct ppp *ppp;
|
||||
+
|
||||
+ if (!dev)
|
||||
+ return;
|
||||
+
|
||||
+ if (dev->type != ARPHRD_PPP)
|
||||
+ return;
|
||||
+
|
||||
+ ppp = netdev_priv(dev);
|
||||
+
|
||||
+ ppp_xmit_lock(ppp);
|
||||
+ ppp->stats64.tx_packets += tx_packets;
|
||||
+ ppp->stats64.tx_bytes += tx_bytes;
|
||||
+ ppp->dev->stats.tx_errors += tx_errors;
|
||||
+ ppp->dev->stats.tx_dropped += tx_dropped;
|
||||
+ if (tx_packets)
|
||||
+ ppp->last_xmit = jiffies;
|
||||
+ ppp_xmit_unlock(ppp);
|
||||
+
|
||||
+ ppp_recv_lock(ppp);
|
||||
+ ppp->stats64.rx_packets += rx_packets;
|
||||
+ ppp->stats64.rx_bytes += rx_bytes;
|
||||
+ ppp->dev->stats.rx_errors += rx_errors;
|
||||
+ ppp->dev->stats.rx_dropped += rx_dropped;
|
||||
+ if (rx_packets)
|
||||
+ ppp->last_recv = jiffies;
|
||||
+ ppp_recv_unlock(ppp);
|
||||
+}
|
||||
+
|
||||
+/* Returns >0 if the device is a multilink PPP netdevice, 0 if not or < 0 if
|
||||
+ * the device is not PPP.
|
||||
+ */
|
||||
+int ppp_is_multilink(struct net_device *dev)
|
||||
+{
|
||||
+ struct ppp *ppp;
|
||||
+ unsigned int flags;
|
||||
+
|
||||
+ if (!dev)
|
||||
+ return -1;
|
||||
+
|
||||
+ if (dev->type != ARPHRD_PPP)
|
||||
+ return -1;
|
||||
+
|
||||
+ ppp = netdev_priv(dev);
|
||||
+ ppp_lock(ppp);
|
||||
+ flags = ppp->flags;
|
||||
+ ppp_unlock(ppp);
|
||||
+
|
||||
+ if (flags & SC_MULTILINK)
|
||||
+ return 1;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+EXPORT_SYMBOL(ppp_is_multilink);
|
||||
+
|
||||
+/* ppp_channel_get_protocol()
|
||||
+ * Call this to obtain the underlying protocol of the PPP channel,
|
||||
+ * e.g. PX_PROTO_OE
|
||||
+ *
|
||||
+ * NOTE: Some channels do not use PX sockets so the protocol value may be very
|
||||
+ * different for them.
|
||||
+ * NOTE: -1 indicates failure.
|
||||
+ * NOTE: Once you know the channel protocol you may then either cast 'chan' to
|
||||
+ * its sub-class or use the channel protocol specific API's as provided by that
|
||||
+ * channel sub type.
|
||||
+ */
|
||||
+int ppp_channel_get_protocol(struct ppp_channel *chan)
|
||||
+{
|
||||
+ if (!chan->ops->get_channel_protocol)
|
||||
+ return -1;
|
||||
+
|
||||
+ return chan->ops->get_channel_protocol(chan);
|
||||
+}
|
||||
+EXPORT_SYMBOL(ppp_channel_get_protocol);
|
||||
+
|
||||
+/* ppp_channel_get_proto_version()
|
||||
+ * Call this to get channel protocol version
|
||||
+ */
|
||||
+int ppp_channel_get_proto_version(struct ppp_channel *chan)
|
||||
+{
|
||||
+ if (!chan->ops->get_channel_protocol_ver)
|
||||
+ return -1;
|
||||
+
|
||||
+ return chan->ops->get_channel_protocol_ver(chan);
|
||||
+}
|
||||
+EXPORT_SYMBOL(ppp_channel_get_proto_version);
|
||||
+
|
||||
+/* ppp_channel_hold()
|
||||
+ * Call this to hold a channel.
|
||||
+ *
|
||||
+ * Returns true on success or false if the hold could not happen.
|
||||
+ *
|
||||
+ * NOTE: chan must be protected against destruction during this call -
|
||||
+ * either by correct locking etc. or because you already have an implicit
|
||||
+ * or explicit hold to the channel already and this is an additional hold.
|
||||
+ */
|
||||
+bool ppp_channel_hold(struct ppp_channel *chan)
|
||||
+{
|
||||
+ if (!chan->ops->hold)
|
||||
+ return false;
|
||||
+
|
||||
+ chan->ops->hold(chan);
|
||||
+ return true;
|
||||
+}
|
||||
+EXPORT_SYMBOL(ppp_channel_hold);
|
||||
+
|
||||
+/* ppp_channel_release()
|
||||
+ * Call this to release a hold you have upon a channel
|
||||
+ */
|
||||
+void ppp_channel_release(struct ppp_channel *chan)
|
||||
+{
|
||||
+ chan->ops->release(chan);
|
||||
+}
|
||||
+EXPORT_SYMBOL(ppp_channel_release);
|
||||
+
|
||||
+/* Check if ppp xmit lock is on hold */
|
||||
+bool ppp_is_xmit_locked(struct net_device *dev)
|
||||
+{
|
||||
+ struct ppp *ppp;
|
||||
+
|
||||
+ if (!dev)
|
||||
+ return false;
|
||||
+
|
||||
+ if (dev->type != ARPHRD_PPP)
|
||||
+ return false;
|
||||
+
|
||||
+ ppp = netdev_priv(dev);
|
||||
+ if (!ppp)
|
||||
+ return false;
|
||||
+
|
||||
+ if (spin_is_locked(&(ppp)->wlock))
|
||||
+ return true;
|
||||
+
|
||||
+ return false;
|
||||
+}
|
||||
+EXPORT_SYMBOL(ppp_is_xmit_locked);
|
||||
+
|
||||
+/* ppp_hold_channels()
|
||||
+ * Returns the PPP channels of the PPP device, storing each one into
|
||||
+ * channels[].
|
||||
+ *
|
||||
+ * channels[] has chan_sz elements.
|
||||
+ * This function returns the number of channels stored, up to chan_sz.
|
||||
+ * It will return < 0 if the device is not PPP.
|
||||
+ *
|
||||
+ * You MUST release the channels using ppp_release_channels().
|
||||
+ */
|
||||
+int ppp_hold_channels(struct net_device *dev, struct ppp_channel *channels[],
|
||||
+ unsigned int chan_sz)
|
||||
+{
|
||||
+ struct ppp *ppp;
|
||||
+ int c;
|
||||
+ struct channel *pch;
|
||||
+
|
||||
+ if (!dev)
|
||||
+ return -1;
|
||||
+
|
||||
+ if (dev->type != ARPHRD_PPP)
|
||||
+ return -1;
|
||||
+
|
||||
+ ppp = netdev_priv(dev);
|
||||
+
|
||||
+ c = 0;
|
||||
+ ppp_lock(ppp);
|
||||
+ list_for_each_entry(pch, &ppp->channels, clist) {
|
||||
+ struct ppp_channel *chan;
|
||||
+
|
||||
+ if (!pch->chan) {
|
||||
+ /* Channel is going / gone away */
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (c == chan_sz) {
|
||||
+ /* No space to record channel */
|
||||
+ ppp_unlock(ppp);
|
||||
+ return c;
|
||||
+ }
|
||||
+
|
||||
+ /* Hold the channel, if supported */
|
||||
+ chan = pch->chan;
|
||||
+ if (!chan->ops->hold)
|
||||
+ continue;
|
||||
+
|
||||
+ chan->ops->hold(chan);
|
||||
+
|
||||
+ /* Record the channel */
|
||||
+ channels[c++] = chan;
|
||||
+ }
|
||||
+ ppp_unlock(ppp);
|
||||
+ return c;
|
||||
+}
|
||||
+EXPORT_SYMBOL(ppp_hold_channels);
|
||||
+
|
||||
+/* ppp_release_channels()
|
||||
+ * Releases channels
|
||||
+ */
|
||||
+void ppp_release_channels(struct ppp_channel *channels[], unsigned int chan_sz)
|
||||
+{
|
||||
+ unsigned int c;
|
||||
+
|
||||
+ for (c = 0; c < chan_sz; ++c) {
|
||||
+ struct ppp_channel *chan;
|
||||
+
|
||||
+ chan = channels[c];
|
||||
+ chan->ops->release(chan);
|
||||
+ }
|
||||
+}
|
||||
+EXPORT_SYMBOL(ppp_release_channels);
|
||||
+
|
||||
/* Module/initialization stuff */
|
||||
|
||||
module_init(ppp_init);
|
||||
@@ -3604,6 +3877,7 @@ EXPORT_SYMBOL(ppp_input_error);
|
||||
EXPORT_SYMBOL(ppp_output_wakeup);
|
||||
EXPORT_SYMBOL(ppp_register_compressor);
|
||||
EXPORT_SYMBOL(ppp_unregister_compressor);
|
||||
+EXPORT_SYMBOL(ppp_update_stats);
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS_CHARDEV(PPP_MAJOR, 0);
|
||||
MODULE_ALIAS_RTNL_LINK("ppp");
|
||||
--- a/drivers/net/ppp/pppoe.c
|
||||
+++ b/drivers/net/ppp/pppoe.c
|
||||
@@ -62,6 +62,7 @@
|
||||
#include <linux/inetdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/skbuff.h>
|
||||
+#include <linux/if_arp.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/if_pppox.h>
|
||||
@@ -87,7 +88,7 @@
|
||||
static int __pppoe_xmit(struct sock *sk, struct sk_buff *skb);
|
||||
|
||||
static const struct proto_ops pppoe_ops;
|
||||
-static const struct ppp_channel_ops pppoe_chan_ops;
|
||||
+static const struct pppoe_channel_ops pppoe_chan_ops;
|
||||
|
||||
/* per-net private data for this module */
|
||||
static unsigned int pppoe_net_id __read_mostly;
|
||||
@@ -692,7 +693,7 @@ static int pppoe_connect(struct socket *
|
||||
|
||||
po->chan.mtu = dev->mtu - sizeof(struct pppoe_hdr) - 2;
|
||||
po->chan.private = sk;
|
||||
- po->chan.ops = &pppoe_chan_ops;
|
||||
+ po->chan.ops = (struct ppp_channel_ops *)&pppoe_chan_ops;
|
||||
|
||||
error = ppp_register_net_channel(dev_net(dev), &po->chan);
|
||||
if (error) {
|
||||
@@ -995,9 +996,80 @@ static int pppoe_fill_forward_path(struc
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static const struct ppp_channel_ops pppoe_chan_ops = {
|
||||
- .start_xmit = pppoe_xmit,
|
||||
- .fill_forward_path = pppoe_fill_forward_path,
|
||||
+/************************************************************************
|
||||
+ *
|
||||
+ * function called by generic PPP driver to hold channel
|
||||
+ *
|
||||
+ ***********************************************************************/
|
||||
+static void pppoe_hold_chan(struct ppp_channel *chan)
|
||||
+{
|
||||
+ struct sock *sk = (struct sock *)chan->private;
|
||||
+
|
||||
+ sock_hold(sk);
|
||||
+}
|
||||
+
|
||||
+/************************************************************************
|
||||
+ *
|
||||
+ * function called by generic PPP driver to release channel
|
||||
+ *
|
||||
+ ***********************************************************************/
|
||||
+static void pppoe_release_chan(struct ppp_channel *chan)
|
||||
+{
|
||||
+ struct sock *sk = (struct sock *)chan->private;
|
||||
+
|
||||
+ sock_put(sk);
|
||||
+}
|
||||
+
|
||||
+/************************************************************************
|
||||
+ *
|
||||
+ * function called to get the channel protocol type
|
||||
+ *
|
||||
+ ***********************************************************************/
|
||||
+static int pppoe_get_channel_protocol(struct ppp_channel *chan)
|
||||
+{
|
||||
+ return PX_PROTO_OE;
|
||||
+}
|
||||
+
|
||||
+/************************************************************************
|
||||
+ *
|
||||
+ * function called to get the PPPoE channel addressing
|
||||
+ * NOTE: This function returns a HOLD to the netdevice
|
||||
+ *
|
||||
+ ***********************************************************************/
|
||||
+static int pppoe_get_addressing(struct ppp_channel *chan,
|
||||
+ struct pppoe_opt *addressing)
|
||||
+{
|
||||
+ struct sock *sk = (struct sock *)chan->private;
|
||||
+ struct pppox_sock *po = pppox_sk(sk);
|
||||
+ int err = 0;
|
||||
+
|
||||
+ *addressing = po->proto.pppoe;
|
||||
+ if (!addressing->dev)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ dev_hold(addressing->dev);
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+/* pppoe_channel_addressing_get()
|
||||
+ * Return PPPoE channel specific addressing information.
|
||||
+ */
|
||||
+int pppoe_channel_addressing_get(struct ppp_channel *chan,
|
||||
+ struct pppoe_opt *addressing)
|
||||
+{
|
||||
+ return pppoe_get_addressing(chan, addressing);
|
||||
+}
|
||||
+EXPORT_SYMBOL(pppoe_channel_addressing_get);
|
||||
+
|
||||
+static const struct pppoe_channel_ops pppoe_chan_ops = {
|
||||
+ /* PPPoE specific channel ops */
|
||||
+ .get_addressing = pppoe_get_addressing,
|
||||
+ /* General ppp channel ops */
|
||||
+ .ops.start_xmit = pppoe_xmit,
|
||||
+ .ops.get_channel_protocol = pppoe_get_channel_protocol,
|
||||
+ .ops.hold = pppoe_hold_chan,
|
||||
+ .ops.release = pppoe_release_chan,
|
||||
+ .ops.fill_forward_path = pppoe_fill_forward_path,
|
||||
};
|
||||
|
||||
static int pppoe_recvmsg(struct socket *sock, struct msghdr *m,
|
||||
--- a/include/linux/if_pppox.h
|
||||
+++ b/include/linux/if_pppox.h
|
||||
@@ -91,4 +91,17 @@ enum {
|
||||
PPPOX_DEAD = 16 /* dead, useless, please clean me up!*/
|
||||
};
|
||||
|
||||
+/*
|
||||
+ * PPPoE Channel specific operations
|
||||
+ */
|
||||
+struct pppoe_channel_ops {
|
||||
+ /* Must be first - general to all PPP channels */
|
||||
+ struct ppp_channel_ops ops;
|
||||
+ int (*get_addressing)(struct ppp_channel *, struct pppoe_opt *);
|
||||
+};
|
||||
+
|
||||
+/* Return PPPoE channel specific addressing information */
|
||||
+extern int pppoe_channel_addressing_get(struct ppp_channel *chan,
|
||||
+ struct pppoe_opt *addressing);
|
||||
+
|
||||
#endif /* !(__LINUX_IF_PPPOX_H) */
|
||||
--- a/include/linux/netdevice.h
|
||||
+++ b/include/linux/netdevice.h
|
||||
@@ -1762,6 +1762,36 @@ 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
|
||||
+ * @IFF_EXT_HW_NO_OFFLOAD: device is an NON Offload device
|
||||
+ * @IFF_EXT_L2TPV3: device is a L2TPV3 Ethernet 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,
|
||||
+ IFF_EXT_HW_NO_OFFLOAD = 1<<8,
|
||||
+ IFF_EXT_ETH_L2TPV3 = 1<<9,
|
||||
+};
|
||||
+
|
||||
#define IFF_802_1Q_VLAN IFF_802_1Q_VLAN
|
||||
#define IFF_EBRIDGE IFF_EBRIDGE
|
||||
#define IFF_BONDING IFF_BONDING
|
||||
@@ -2075,6 +2103,7 @@ struct net_device {
|
||||
/* Read-mostly cache-line for fast-path access */
|
||||
unsigned int flags;
|
||||
unsigned long long priv_flags;
|
||||
+ unsigned int priv_flags_ext;
|
||||
const struct net_device_ops *netdev_ops;
|
||||
int ifindex;
|
||||
unsigned short gflags;
|
||||
--- a/include/linux/ppp_channel.h
|
||||
+++ b/include/linux/ppp_channel.h
|
||||
@@ -19,6 +19,10 @@
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/poll.h>
|
||||
#include <net/net_namespace.h>
|
||||
+#include <linux/notifier.h>
|
||||
+
|
||||
+#define PPP_CHANNEL_DISCONNECT 0
|
||||
+#define PPP_CHANNEL_CONNECT 1
|
||||
|
||||
struct net_device_path;
|
||||
struct net_device_path_ctx;
|
||||
@@ -30,9 +34,19 @@ struct ppp_channel_ops {
|
||||
int (*start_xmit)(struct ppp_channel *, struct sk_buff *);
|
||||
/* Handle an ioctl call that has come in via /dev/ppp. */
|
||||
int (*ioctl)(struct ppp_channel *, unsigned int, unsigned long);
|
||||
+ /* Get channel protocol type, one of PX_PROTO_XYZ or specific to
|
||||
+ * the channel subtype
|
||||
+ */
|
||||
+ int (*get_channel_protocol)(struct ppp_channel *);
|
||||
+ /* Get channel protocol version */
|
||||
+ int (*get_channel_protocol_ver)(struct ppp_channel *);
|
||||
+ /* Hold the channel from being destroyed */
|
||||
+ void (*hold)(struct ppp_channel *);
|
||||
+ /* Release hold on the channel */
|
||||
+ void (*release)(struct ppp_channel *);
|
||||
int (*fill_forward_path)(struct net_device_path_ctx *,
|
||||
- struct net_device_path *,
|
||||
- const struct ppp_channel *);
|
||||
+ struct net_device_path *,
|
||||
+ const struct ppp_channel *);
|
||||
};
|
||||
|
||||
struct ppp_channel {
|
||||
@@ -76,6 +90,51 @@ extern int ppp_unit_number(struct ppp_ch
|
||||
/* Get the device name associated with a channel, or NULL if none */
|
||||
extern char *ppp_dev_name(struct ppp_channel *);
|
||||
|
||||
+/* Call this to obtain the underlying protocol of the PPP channel,
|
||||
+ * e.g. PX_PROTO_OE
|
||||
+ */
|
||||
+extern int ppp_channel_get_protocol(struct ppp_channel *);
|
||||
+
|
||||
+/* Call this get protocol version */
|
||||
+extern int ppp_channel_get_proto_version(struct ppp_channel *);
|
||||
+
|
||||
+/* Call this to hold a channel */
|
||||
+extern bool ppp_channel_hold(struct ppp_channel *);
|
||||
+
|
||||
+/* Call this to release a hold you have upon a channel */
|
||||
+extern void ppp_channel_release(struct ppp_channel *);
|
||||
+
|
||||
+/* Release hold on PPP channels */
|
||||
+extern void ppp_release_channels(struct ppp_channel *channels[],
|
||||
+ unsigned int chan_sz);
|
||||
+
|
||||
+/* Hold PPP channels for the PPP device */
|
||||
+extern int ppp_hold_channels(struct net_device *dev,
|
||||
+ struct ppp_channel *channels[],
|
||||
+ unsigned int chan_sz);
|
||||
+
|
||||
+/* Test if ppp xmit lock is locked */
|
||||
+extern bool ppp_is_xmit_locked(struct net_device *dev);
|
||||
+
|
||||
+/* Test if the ppp device is a multi-link ppp device */
|
||||
+extern int ppp_is_multilink(struct net_device *dev);
|
||||
+
|
||||
+/* Register the PPP channel connect notifier */
|
||||
+extern void ppp_channel_connection_register_notify(struct notifier_block *nb);
|
||||
+
|
||||
+/* Unregister the PPP channel connect notifier */
|
||||
+extern void ppp_channel_connection_unregister_notify(struct notifier_block *nb);
|
||||
+
|
||||
+/* Update statistics of the PPP net_device by incrementing related
|
||||
+ * statistics field value with corresponding parameter
|
||||
+ */
|
||||
+extern void ppp_update_stats(struct net_device *dev, unsigned long rx_packets,
|
||||
+ unsigned long rx_bytes, unsigned long tx_packets,
|
||||
+ unsigned long tx_bytes, unsigned long rx_errors,
|
||||
+ unsigned long tx_errors, unsigned long rx_dropped,
|
||||
+ unsigned long tx_dropped);
|
||||
+
|
||||
+
|
||||
/*
|
||||
* SMP locking notes:
|
||||
* The channel code must ensure that when it calls ppp_unregister_channel,
|
|
@ -0,0 +1,49 @@
|
|||
--- a/drivers/net/bonding/bond_main.c
|
||||
+++ b/drivers/net/bonding/bond_main.c
|
||||
@@ -208,6 +208,7 @@ atomic_t netpoll_block_tx = ATOMIC_INIT(
|
||||
#endif
|
||||
|
||||
unsigned int bond_net_id __read_mostly;
|
||||
+static unsigned long bond_id_mask = 0xFFFFFFF0; /* QCA NSS ECM bonding support */
|
||||
|
||||
static const struct flow_dissector_key flow_keys_bonding_keys[] = {
|
||||
{
|
||||
@@ -5793,8 +5794,14 @@ static void bond_destructor(struct net_d
|
||||
if (bond->wq)
|
||||
destroy_workqueue(bond->wq);
|
||||
|
||||
+ /* QCA NSS ECM bonding support - Start */
|
||||
+ if (bond->id != (~0U))
|
||||
+ clear_bit(bond->id, &bond_id_mask);
|
||||
+ /* QCA NSS ECM bonding support - End */
|
||||
+
|
||||
if (bond->rr_tx_counter)
|
||||
free_percpu(bond->rr_tx_counter);
|
||||
+
|
||||
}
|
||||
|
||||
void bond_setup(struct net_device *bond_dev)
|
||||
@@ -6358,6 +6365,13 @@ int bond_create(struct net *net, const c
|
||||
|
||||
bond_work_init_all(bond);
|
||||
|
||||
+ /* QCA NSS ECM bonding support - Start */
|
||||
+ bond->id = ~0U;
|
||||
+ if (bond_id_mask != (~0UL)) {
|
||||
+ bond->id = (u32)ffz(bond_id_mask);
|
||||
+ set_bit(bond->id, &bond_id_mask);
|
||||
+ }
|
||||
+ /* QCA NSS ECM bonding support - End */
|
||||
out:
|
||||
rtnl_unlock();
|
||||
return res;
|
||||
--- a/include/net/bonding.h
|
||||
+++ b/include/net/bonding.h
|
||||
@@ -265,6 +265,7 @@ struct bonding {
|
||||
spinlock_t ipsec_lock;
|
||||
#endif /* CONFIG_XFRM_OFFLOAD */
|
||||
struct bpf_prog *xdp_prog;
|
||||
+ u32 id;/* QCA NSS ECM bonding support */
|
||||
};
|
||||
|
||||
#define bond_slave_get_rcu(dev) \
|
|
@ -0,0 +1,685 @@
|
|||
--- a/drivers/net/bonding/bond_3ad.c
|
||||
+++ b/drivers/net/bonding/bond_3ad.c
|
||||
@@ -115,6 +115,40 @@ static void ad_marker_response_received(
|
||||
struct port *port);
|
||||
static void ad_update_actor_keys(struct port *port, bool reset);
|
||||
|
||||
+/* QCA NSS ECM bonding support - Start */
|
||||
+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);
|
||||
+/* QCA NSS ECM bonding support - End */
|
||||
|
||||
/* ================= api to bonding and kernel code ================== */
|
||||
|
||||
@@ -1064,7 +1098,31 @@ static void ad_mux_machine(struct port *
|
||||
ad_disable_collecting_distributing(port,
|
||||
update_slave_arr);
|
||||
port->ntt = true;
|
||||
+
|
||||
+ /* QCA NSS ECM bonding support - Start */
|
||||
+ /* 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;
|
||||
+ /* QCA NSS ECM bonding support - End */
|
||||
case AD_MUX_COLLECTING_DISTRIBUTING:
|
||||
port->actor_oper_port_state |= LACP_STATE_COLLECTING;
|
||||
port->actor_oper_port_state |= LACP_STATE_DISTRIBUTING;
|
||||
@@ -1908,6 +1966,7 @@ static void ad_enable_collecting_distrib
|
||||
bool *update_slave_arr)
|
||||
{
|
||||
if (port->aggregator->is_active) {
|
||||
+ struct bond_cb *lag_cb_main; /* QCA NSS ECM bonding support */
|
||||
slave_dbg(port->slave->bond->dev, port->slave->dev,
|
||||
"Enabling port %d (LAG %d)\n",
|
||||
port->actor_port_number,
|
||||
@@ -1915,6 +1974,16 @@ static void ad_enable_collecting_distrib
|
||||
__enable_port(port);
|
||||
/* Slave array needs update */
|
||||
*update_slave_arr = true;
|
||||
+
|
||||
+ /* QCA NSS ECM bonding support - Start */
|
||||
+ 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();
|
||||
+ /* QCA NSS ECM bonding support - End */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2674,6 +2743,104 @@ int bond_3ad_get_active_agg_info(struct
|
||||
return ret;
|
||||
}
|
||||
|
||||
+/* QCA NSS ECM bonding support - Start */
|
||||
+/* 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;
|
||||
+}
|
||||
+/* QCA NSS ECM bonding support - End */
|
||||
+
|
||||
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
|
||||
@@ -286,6 +286,21 @@ const char *bond_mode_name(int mode)
|
||||
return names[mode];
|
||||
}
|
||||
|
||||
+/* QCA NSS ECM bonding support */
|
||||
+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);
|
||||
+/* QCA NSS ECM bonding support */
|
||||
+
|
||||
/**
|
||||
* bond_dev_queue_xmit - Prepare skb for xmit.
|
||||
*
|
||||
@@ -1185,6 +1200,23 @@ void bond_change_active_slave(struct bon
|
||||
if (BOND_MODE(bond) == BOND_MODE_8023AD)
|
||||
bond_3ad_handle_link_change(new_active, BOND_LINK_UP);
|
||||
|
||||
+ /* QCA NSS ECM bonding support - Start */
|
||||
+ 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();
|
||||
+ }
|
||||
+ /* QCA NSS ECM bonding support - End */
|
||||
+
|
||||
if (bond_is_lb(bond))
|
||||
bond_alb_handle_link_change(bond, new_active, BOND_LINK_UP);
|
||||
} else {
|
||||
@@ -1808,6 +1840,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; /* QCA NSS ECM bonding support */
|
||||
int link_reporting;
|
||||
int res = 0, i;
|
||||
|
||||
@@ -2251,6 +2284,15 @@ 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");
|
||||
|
||||
+ /* QCA NSS ECM bonding support - Start */
|
||||
+ 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();
|
||||
+ /* QCA NSS ECM bonding support - End */
|
||||
+
|
||||
/* enslave is successful */
|
||||
bond_queue_slave_event(new_slave);
|
||||
return 0;
|
||||
@@ -2316,6 +2358,15 @@ err_undo_flags:
|
||||
}
|
||||
}
|
||||
|
||||
+ /* QCA NSS ECM bonding support - Start */
|
||||
+ 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();
|
||||
+ /* QCA NSS ECM bonding support - End */
|
||||
+
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -2337,6 +2388,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; /* QCA NSS ECM bonding support */
|
||||
int old_flags = bond_dev->flags;
|
||||
netdev_features_t old_features = bond_dev->features;
|
||||
|
||||
@@ -2359,6 +2411,15 @@ static int __bond_release_one(struct net
|
||||
|
||||
bond_set_slave_inactive_flags(slave, BOND_SLAVE_NOTIFY_NOW);
|
||||
|
||||
+ /* QCA NSS ECM bonding support - Start */
|
||||
+ 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();
|
||||
+ /* QCA NSS ECM bonding support - End */
|
||||
+
|
||||
bond_sysfs_slave_del(slave);
|
||||
|
||||
/* recompute stats just before removing the slave */
|
||||
@@ -2678,6 +2739,8 @@ static void bond_miimon_commit(struct bo
|
||||
struct slave *slave, *primary, *active;
|
||||
bool do_failover = false;
|
||||
struct list_head *iter;
|
||||
+ struct net_device *slave_dev = NULL; /* QCA NSS ECM bonding support */
|
||||
+ struct bond_cb *lag_cb_main; /* QCA NSS ECM bonding support */
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
@@ -2717,6 +2780,12 @@ static void bond_miimon_commit(struct bo
|
||||
bond_set_active_slave(slave);
|
||||
}
|
||||
|
||||
+ /* QCA NSS ECM bonding support - Start */
|
||||
+ if ((bond->params.mode == BOND_MODE_XOR) &&
|
||||
+ (!slave_dev))
|
||||
+ slave_dev = slave->dev;
|
||||
+ /* QCA NSS ECM bonding support - End */
|
||||
+
|
||||
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");
|
||||
@@ -2765,6 +2834,16 @@ static void bond_miimon_commit(struct bo
|
||||
unblock_netpoll_tx();
|
||||
}
|
||||
|
||||
+ /* QCA NSS ECM bonding support - Start */
|
||||
+ 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();
|
||||
+ /* QCA NSS ECM bonding support - End */
|
||||
+
|
||||
bond_set_carrier(bond);
|
||||
}
|
||||
|
||||
@@ -4012,8 +4091,219 @@ 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]; /* QCA NSS ECM bonding support */
|
||||
+}
|
||||
+
|
||||
+/* QCA NSS ECM bonding support - Start */
|
||||
+/* 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;
|
||||
+}
|
||||
+/* QCA NSS ECM bonding support - End */
|
||||
|
||||
static bool bond_flow_ip(struct sk_buff *skb, struct flow_keys *fk, const void *data,
|
||||
int hlen, __be16 l2_proto, int *nhoff, int *ip_proto, bool l34)
|
||||
@@ -5192,15 +5482,18 @@ 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;
|
||||
+ /* QCA NSS ECM bonding support - Start */
|
||||
+ 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);
|
||||
+ /* QCA NSS ECM bonding support - End */
|
||||
}
|
||||
|
||||
/* in broadcast mode, we send everything to all usable interfaces. */
|
||||
@@ -5450,8 +5743,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); /* QCA NSS ECM bonding support */
|
||||
+ case BOND_MODE_8023AD:
|
||||
return bond_3ad_xor_xmit(skb, dev);
|
||||
case BOND_MODE_BROADCAST:
|
||||
return bond_xmit_broadcast(skb, dev);
|
||||
--- a/include/net/bond_3ad.h
|
||||
+++ b/include/net/bond_3ad.h
|
||||
@@ -303,8 +303,15 @@ int bond_3ad_lacpdu_recv(const struct sk
|
||||
int bond_3ad_set_carrier(struct bonding *bond);
|
||||
void bond_3ad_update_lacp_active(struct bonding *bond);
|
||||
void bond_3ad_update_lacp_rate(struct bonding *bond);
|
||||
+/* QCA NSS ECM bonding support */
|
||||
+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);
|
||||
+/* QCA NSS ECM bonding support */
|
||||
+
|
||||
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);
|
||||
#endif /* _NET_BOND_3AD_H */
|
||||
-
|
||||
--- a/include/net/bonding.h
|
||||
+++ b/include/net/bonding.h
|
||||
@@ -94,6 +94,8 @@
|
||||
|
||||
#define BOND_TLS_FEATURES (NETIF_F_HW_TLS_TX | NETIF_F_HW_TLS_RX)
|
||||
|
||||
+extern struct bond_cb __rcu *bond_cb; /* QCA NSS ECM bonding support */
|
||||
+
|
||||
#ifdef CONFIG_NET_POLL_CONTROLLER
|
||||
extern atomic_t netpoll_block_tx;
|
||||
|
||||
@@ -659,6 +661,7 @@ struct bond_net {
|
||||
|
||||
int bond_rcv_validate(const struct sk_buff *skb, struct bonding *bond, struct slave *slave);
|
||||
netdev_tx_t bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_device *slave_dev);
|
||||
+int bond_get_id(struct net_device *bond_dev); /* QCA NSS ECM bonding support */
|
||||
int bond_create(struct net *net, const char *name);
|
||||
int bond_create_sysfs(struct bond_net *net);
|
||||
void bond_destroy_sysfs(struct bond_net *net);
|
||||
@@ -689,6 +692,13 @@ 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);
|
||||
+/* QCA NSS ECM bonding support - Start */
|
||||
+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);
|
||||
+/* QCA NSS ECM bonding support - End */
|
||||
+
|
||||
void bond_work_init_all(struct bonding *bond);
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
@@ -793,4 +803,18 @@ static inline netdev_tx_t bond_tx_drop(s
|
||||
return NET_XMIT_DROP;
|
||||
}
|
||||
|
||||
+/* QCA NSS ECM bonding support - Start */
|
||||
+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);
|
||||
+/* QCA NSS ECM bonding support - End */
|
||||
+
|
||||
#endif /* _NET_BONDING_H */
|
|
@ -0,0 +1,96 @@
|
|||
--- a/include/linux/if_macvlan.h
|
||||
+++ b/include/linux/if_macvlan.h
|
||||
@@ -15,6 +15,13 @@ struct macvlan_port;
|
||||
#define MACVLAN_MC_FILTER_BITS 8
|
||||
#define MACVLAN_MC_FILTER_SZ (1 << MACVLAN_MC_FILTER_BITS)
|
||||
|
||||
+/* QCA NSS ECM Support - Start */
|
||||
+/*
|
||||
+ * 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);
|
||||
+/* QCA NSS ECM Support - End */
|
||||
+
|
||||
struct macvlan_dev {
|
||||
struct net_device *dev;
|
||||
struct list_head list;
|
||||
@@ -35,6 +42,7 @@ struct macvlan_dev {
|
||||
#ifdef CONFIG_NET_POLL_CONTROLLER
|
||||
struct netpoll *netpoll;
|
||||
#endif
|
||||
+ macvlan_offload_stats_update_cb_t offload_stats_update; /* QCA NSS ECM support */
|
||||
};
|
||||
|
||||
static inline void macvlan_count_rx(const struct macvlan_dev *vlan,
|
||||
@@ -107,4 +115,26 @@ static inline int macvlan_release_l2fw_o
|
||||
macvlan->accel_priv = NULL;
|
||||
return dev_uc_add(macvlan->lowerdev, dev->dev_addr);
|
||||
}
|
||||
+
|
||||
+/* QCA NSS ECM Support - Start */
|
||||
+#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;
|
||||
+}
|
||||
+#endif
|
||||
+/* QCA NSS ECM Support - End */
|
||||
#endif /* _LINUX_IF_MACVLAN_H */
|
||||
--- a/drivers/net/macvlan.c
|
||||
+++ b/drivers/net/macvlan.c
|
||||
@@ -933,6 +933,34 @@ static void macvlan_uninit(struct net_de
|
||||
macvlan_port_destroy(port->dev);
|
||||
}
|
||||
|
||||
+/* QCA NSS ECM Support - Start */
|
||||
+/* 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);
|
||||
+}
|
||||
+/* QCA NSS ECM Support - End */
|
||||
+
|
||||
static void macvlan_dev_get_stats64(struct net_device *dev,
|
||||
struct rtnl_link_stats64 *stats)
|
||||
{
|
||||
@@ -1477,6 +1505,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; /* QCA NSS ECM Support */
|
||||
|
||||
vlan->mode = MACVLAN_MODE_VEPA;
|
||||
if (data && data[IFLA_MACVLAN_MODE])
|
|
@ -0,0 +1,154 @@
|
|||
--- a/net/netfilter/Kconfig
|
||||
+++ b/net/netfilter/Kconfig
|
||||
@@ -175,6 +175,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/include/net/netfilter/nf_conntrack_extend.h
|
||||
+++ b/include/net/netfilter/nf_conntrack_extend.h
|
||||
@@ -31,6 +31,10 @@ 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, /* QCA NSS ECM support */
|
||||
+#endif
|
||||
+
|
||||
NF_CT_EXT_NUM,
|
||||
};
|
||||
|
||||
--- a/net/netfilter/nf_conntrack_extend.c
|
||||
+++ b/net/netfilter/nf_conntrack_extend.c
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <net/netfilter/nf_conntrack_labels.h>
|
||||
#include <net/netfilter/nf_conntrack_synproxy.h>
|
||||
#include <net/netfilter/nf_conntrack_act_ct.h>
|
||||
+#include <net/netfilter/nf_conntrack_dscpremark_ext.h>
|
||||
#include <net/netfilter/nf_nat.h>
|
||||
|
||||
#define NF_CT_EXT_PREALLOC 128u /* conntrack events are on by default */
|
||||
@@ -54,6 +55,9 @@ 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 +90,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
|
||||
;
|
||||
}
|
||||
|
||||
--- a/net/netfilter/Makefile
|
||||
+++ b/net/netfilter/Makefile
|
||||
@@ -14,6 +14,7 @@ nf_conntrack-$(CONFIG_NF_CONNTRACK_LABEL
|
||||
nf_conntrack-$(CONFIG_NF_CT_PROTO_DCCP) += nf_conntrack_proto_dccp.o
|
||||
nf_conntrack-$(CONFIG_NF_CT_PROTO_SCTP) += nf_conntrack_proto_sctp.o
|
||||
nf_conntrack-$(CONFIG_NF_CT_PROTO_GRE) += nf_conntrack_proto_gre.o
|
||||
+nf_conntrack-$(CONFIG_NF_CONNTRACK_DSCPREMARK_EXT) += nf_conntrack_dscpremark_ext.o
|
||||
ifeq ($(CONFIG_NF_CONNTRACK),m)
|
||||
nf_conntrack-$(CONFIG_DEBUG_INFO_BTF_MODULES) += nf_conntrack_bpf.o
|
||||
else ifeq ($(CONFIG_NF_CONNTRACK),y)
|
||||
--- 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>
|
||||
@@ -1781,6 +1784,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;
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
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(-)
|
||||
|
||||
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
|
||||
index df82117..4fb8247 100644
|
||||
--- a/net/ipv6/route.c
|
||||
+++ b/net/ipv6/route.c
|
||||
@@ -3868,10 +3868,6 @@ int ip6_route_add(struct fib6_config *cfg, gfp_t gfp_flags,
|
||||
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,9 +3889,6 @@ static int __ip6_del_rt(struct fib6_info *rt, struct nl_info *info)
|
||||
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;
|
||||
@@ -4501,6 +4494,10 @@ int ipv6_route_ioctl(struct net *net, unsigned int cmd, struct in6_rtmsg *rtmsg)
|
||||
break;
|
||||
}
|
||||
rtnl_unlock();
|
||||
+ if (!err)
|
||||
+ atomic_notifier_call_chain(&ip6route_chain,
|
||||
+ (cmd == SIOCADDRT) ? RTM_NEWROUTE : RTM_DELROUTE, &cfg);
|
||||
+
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -5528,11 +5525,17 @@ static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh,
|
||||
}
|
||||
|
||||
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,
|
||||
@@ -5549,9 +5552,15 @@ static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh,
|
||||
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 */
|
|
@ -0,0 +1,92 @@
|
|||
From 3c17a0e1112be70071e98d5208da5b55dcec20a6 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Casey <simon501098c@gmail.com>
|
||||
Date: Wed, 2 Feb 2022 19:37:29 +0100
|
||||
Subject: [PATCH] Update 607-qca-add-add-nss-bridge-mgr-support.patch for kernel 5.15
|
||||
|
||||
---
|
||||
include/linux/if_bridge.h | 4 ++++
|
||||
net/bridge/br_fdb.c | 25 +++++++++++++++++++++----
|
||||
2 files changed, 25 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/include/linux/if_bridge.h
|
||||
+++ b/include/linux/if_bridge.h
|
||||
@@ -252,4 +252,8 @@ typedef struct net_bridge_port *br_get_d
|
||||
extern br_get_dst_hook_t __rcu *br_get_dst_hook;
|
||||
/* QCA NSS ECM support - End */
|
||||
|
||||
+/* QCA NSS bridge-mgr support - Start */
|
||||
+extern struct net_device *br_fdb_bridge_dev_get_and_hold(struct net_bridge *br);
|
||||
+/* QCA NSS bridge-mgr support - End */
|
||||
+
|
||||
#endif
|
||||
--- a/net/bridge/br_fdb.c
|
||||
+++ b/net/bridge/br_fdb.c
|
||||
@@ -569,7 +569,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]; /* QCA NSS ECM support */
|
||||
+ struct br_fdb_event fdb_event; /* QCA NSS bridge-mgr support */
|
||||
|
||||
/* this part is tricky, in order to avoid blocking learning and
|
||||
* consequently forwarding, we rely on rcu to delete objects with
|
||||
@@ -597,12 +597,13 @@ 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);
|
||||
/* QCA NSS ECM support - Start */
|
||||
atomic_notifier_call_chain(
|
||||
&br_fdb_update_notifier_list, 0,
|
||||
- (void *)mac_addr);
|
||||
+ (void *)&fdb_event);
|
||||
/* QCA NSS ECM support - End */
|
||||
}
|
||||
spin_unlock_bh(&br->hash_lock);
|
||||
@@ -900,10 +901,21 @@ static bool __fdb_mark_active(struct net
|
||||
test_and_clear_bit(BR_FDB_NOTIFY_INACTIVE, &fdb->flags));
|
||||
}
|
||||
|
||||
+/* QCA NSS bridge-mgr support - Start */
|
||||
+/* 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);
|
||||
+/* QCA NSS bridge-mgr support - End */
|
||||
+
|
||||
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; /* QCA NSS bridge-mgr support */
|
||||
|
||||
/* some users want to always flood. */
|
||||
if (hold_time(br) == 0)
|
||||
@@ -929,6 +941,12 @@ 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);
|
||||
+ /* QCA NSS bridge-mgr support - Start */
|
||||
+ ether_addr_copy(fdb_event.addr, addr);
|
||||
+ fdb_event.br = br;
|
||||
+ fdb_event.orig_dev = fdb->dst->dev;
|
||||
+ fdb_event.dev = source->dev;
|
||||
+ /* QCA NSS bridge-mgr support - End */
|
||||
WRITE_ONCE(fdb->dst, source);
|
||||
fdb_modified = true;
|
||||
/* Take over HW learned entry */
|
||||
@@ -940,7 +958,7 @@ void br_fdb_update(struct net_bridge *br
|
||||
/* QCA NSS ECM support - Start */
|
||||
atomic_notifier_call_chain(
|
||||
&br_fdb_update_notifier_list,
|
||||
- 0, (void *)addr);
|
||||
+ 0, (void *)&fdb_event);
|
||||
/* QCA NSS ECM support - End */
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
--- a/include/linux/skbuff.h
|
||||
+++ b/include/linux/skbuff.h
|
||||
@@ -773,6 +773,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
|
||||
@@ -968,6 +969,8 @@ struct sk_buff {
|
||||
#ifdef CONFIG_NET_CLS_ACT
|
||||
__u8 tc_skip_classify:1;
|
||||
__u8 tc_at_ingress:1; /* See TC_AT_INGRESS_MASK */
|
||||
+ __u8 tc_skip_classify_offload:1;
|
||||
+ __u16 tc_verd_qca_nss; /* QCA NSS Qdisc Support */
|
||||
#endif
|
||||
#ifdef CONFIG_IPV6_NDISC_NODETYPE
|
||||
__u8 ndisc_nodetype:2;
|
||||
--- 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, /* QCA NSS Qdisc IGS Support */
|
||||
/* other actions go here */
|
||||
__TCA_ID_MAX = 255
|
||||
};
|
||||
@@ -801,4 +802,14 @@ enum {
|
||||
TCF_EM_OPND_LT
|
||||
};
|
||||
|
||||
+/* QCA NSS Qdisc Support - Start */
|
||||
+#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)
|
||||
+/* QCA NSS Qdisc Support - End */
|
||||
+
|
||||
#endif
|
|
@ -0,0 +1,441 @@
|
|||
--- 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->rx_stats.sync);
|
||||
+ txp->rx_stats.packets += u64_stats_read(&offload_stats->rx_packets);
|
||||
+ txp->rx_stats.bytes += u64_stats_read(&offload_stats->rx_bytes);
|
||||
+ txp->tx_stats.packets += u64_stats_read(&offload_stats->tx_packets);
|
||||
+ txp->tx_stats.bytes += u64_stats_read(&offload_stats->tx_bytes);
|
||||
+ u64_stats_update_end(&txp->rx_stats.sync);
|
||||
+}
|
||||
+EXPORT_SYMBOL(ifb_update_offload_stats);
|
||||
+
|
||||
static void ifb_stats64(struct net_device *dev,
|
||||
struct rtnl_link_stats64 *stats)
|
||||
{
|
||||
@@ -326,6 +351,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
|
||||
@@ -4588,6 +4588,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
|
||||
@@ -5133,6 +5142,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/include/uapi/linux/pkt_sched.h
|
||||
+++ b/include/uapi/linux/pkt_sched.h
|
||||
@@ -1278,4 +1278,248 @@ enum {
|
||||
|
||||
#define TCA_ETS_MAX (__TCA_ETS_MAX - 1)
|
||||
|
||||
+/* QCA NSS Clients Support - Start */
|
||||
+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 */
|
||||
+};
|
||||
+/* QCA NSS Clients Support - End */
|
||||
#endif
|
||||
--- a/net/sched/sch_api.c
|
||||
+++ b/net/sched/sch_api.c
|
||||
@@ -313,6 +313,7 @@ struct Qdisc *qdisc_lookup(struct net_de
|
||||
out:
|
||||
return q;
|
||||
}
|
||||
+EXPORT_SYMBOL(qdisc_lookup);
|
||||
|
||||
struct Qdisc *qdisc_lookup_rcu(struct net_device *dev, u32 handle)
|
||||
{
|
||||
@@ -2386,4 +2387,26 @@ static int __init pktsched_init(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
+/* QCA NSS Qdisc Support - Start */
|
||||
+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);
|
||||
+/* QCA NSS Qdisc Support - End */
|
||||
+
|
||||
subsys_initcall(pktsched_init);
|
||||
--- a/net/sched/sch_generic.c
|
||||
+++ b/net/sched/sch_generic.c
|
||||
@@ -1069,6 +1069,7 @@ static void __qdisc_destroy(struct Qdisc
|
||||
|
||||
call_rcu(&qdisc->rcu, qdisc_free_cb);
|
||||
}
|
||||
+EXPORT_SYMBOL(qdisc_destroy);
|
||||
|
||||
void qdisc_destroy(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;
|
||||
@@ -719,6 +720,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)
|
||||
{
|
||||
@@ -1305,4 +1340,9 @@ static inline void qdisc_synchronize(con
|
||||
msleep(1);
|
||||
}
|
||||
|
||||
+/* QCA NSS Qdisc Support - Start */
|
||||
+void qdisc_destroy(struct Qdisc *qdisc);
|
||||
+void tcf_destroy_chain(struct tcf_proto __rcu **fl);
|
||||
+/* QCA NSS Qdisc Support - End */
|
||||
+
|
||||
#endif
|
|
@ -0,0 +1,46 @@
|
|||
--- a/net/l2tp/l2tp_core.c
|
||||
+++ b/net/l2tp/l2tp_core.c
|
||||
@@ -398,6 +398,31 @@ err_tlock:
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(l2tp_session_register);
|
||||
|
||||
+void l2tp_stats_update(struct l2tp_tunnel *tunnel,
|
||||
+ struct l2tp_session *session,
|
||||
+ struct l2tp_stats *stats)
|
||||
+{
|
||||
+ atomic_long_add(atomic_long_read(&stats->rx_packets),
|
||||
+ &tunnel->stats.rx_packets);
|
||||
+ atomic_long_add(atomic_long_read(&stats->rx_bytes),
|
||||
+ &tunnel->stats.rx_bytes);
|
||||
+ atomic_long_add(atomic_long_read(&stats->tx_packets),
|
||||
+ &tunnel->stats.tx_packets);
|
||||
+ atomic_long_add(atomic_long_read(&stats->tx_bytes),
|
||||
+ &tunnel->stats.tx_bytes);
|
||||
+
|
||||
+ atomic_long_add(atomic_long_read(&stats->rx_packets),
|
||||
+ &session->stats.rx_packets);
|
||||
+ atomic_long_add(atomic_long_read(&stats->rx_bytes),
|
||||
+ &session->stats.rx_bytes);
|
||||
+ atomic_long_add(atomic_long_read(&stats->tx_packets),
|
||||
+ &session->stats.tx_packets);
|
||||
+ atomic_long_add(atomic_long_read(&stats->tx_bytes),
|
||||
+ &session->stats.tx_bytes);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(l2tp_stats_update);
|
||||
+
|
||||
+
|
||||
/*****************************************************************************
|
||||
* Receive data handling
|
||||
*****************************************************************************/
|
||||
--- a/net/l2tp/l2tp_core.h
|
||||
+++ b/net/l2tp/l2tp_core.h
|
||||
@@ -232,6 +232,9 @@ struct l2tp_session *l2tp_session_get_nt
|
||||
struct l2tp_session *l2tp_session_get_by_ifname(const struct net *net,
|
||||
const char *ifname);
|
||||
|
||||
+void l2tp_stats_update(struct l2tp_tunnel *tunnel, struct l2tp_session *session,
|
||||
+ struct l2tp_stats *stats);
|
||||
+
|
||||
/* Tunnel and session lifetime management.
|
||||
* Creation of a new instance is a two-step process: create, then register.
|
||||
* Destruction is triggered using the *_delete functions, and completes asynchronously.
|
|
@ -0,0 +1,478 @@
|
|||
--- a/include/linux/if_pppox.h
|
||||
+++ b/include/linux/if_pppox.h
|
||||
@@ -36,6 +36,7 @@ struct pptp_opt {
|
||||
u32 ack_sent, ack_recv;
|
||||
u32 seq_sent, seq_recv;
|
||||
int ppp_flags;
|
||||
+ bool pptp_offload_mode;
|
||||
};
|
||||
#include <net/sock.h>
|
||||
|
||||
@@ -100,8 +101,40 @@ struct pppoe_channel_ops {
|
||||
int (*get_addressing)(struct ppp_channel *, struct pppoe_opt *);
|
||||
};
|
||||
|
||||
+/* PPTP client callback */
|
||||
+typedef int (*pptp_gre_seq_offload_callback_t)(struct sk_buff *skb,
|
||||
+ struct net_device *pptp_dev);
|
||||
+
|
||||
/* Return PPPoE channel specific addressing information */
|
||||
extern int pppoe_channel_addressing_get(struct ppp_channel *chan,
|
||||
struct pppoe_opt *addressing);
|
||||
|
||||
+/* Lookup PPTP session info and return PPTP session using sip, dip and local call id */
|
||||
+extern int pptp_session_find_by_src_callid(struct pptp_opt *opt, __be16 src_call_id,
|
||||
+ __be32 daddr, __be32 saddr);
|
||||
+
|
||||
+/* Lookup PPTP session info and return PPTP session using dip and peer call id */
|
||||
+extern int pptp_session_find(struct pptp_opt *opt, __be16 peer_call_id,
|
||||
+ __be32 peer_ip_addr);
|
||||
+
|
||||
+/* Return PPTP session information given the channel */
|
||||
+extern void pptp_channel_addressing_get(struct pptp_opt *opt,
|
||||
+ struct ppp_channel *chan);
|
||||
+
|
||||
+/* Enable the PPTP session offload flag */
|
||||
+extern int pptp_session_enable_offload_mode(__be16 peer_call_id,
|
||||
+ __be32 peer_ip_addr);
|
||||
+
|
||||
+/* Disable the PPTP session offload flag */
|
||||
+extern int pptp_session_disable_offload_mode(__be16 peer_call_id,
|
||||
+ __be32 peer_ip_addr);
|
||||
+
|
||||
+/* Register the PPTP GRE packets sequence number offload callback */
|
||||
+extern int
|
||||
+pptp_register_gre_seq_offload_callback(pptp_gre_seq_offload_callback_t
|
||||
+ pptp_client_cb);
|
||||
+
|
||||
+/* Unregister the PPTP GRE packets sequence number offload callback */
|
||||
+extern void pptp_unregister_gre_seq_offload_callback(void);
|
||||
+
|
||||
#endif /* !(__LINUX_IF_PPPOX_H) */
|
||||
--- a/drivers/net/ppp/ppp_generic.c
|
||||
+++ b/drivers/net/ppp/ppp_generic.c
|
||||
@@ -2973,6 +2973,20 @@ char *ppp_dev_name(struct ppp_channel *c
|
||||
return name;
|
||||
}
|
||||
|
||||
+/* Return the PPP net device index */
|
||||
+int ppp_dev_index(struct ppp_channel *chan)
|
||||
+{
|
||||
+ struct channel *pch = chan->ppp;
|
||||
+ int ifindex = 0;
|
||||
+
|
||||
+ if (pch) {
|
||||
+ read_lock_bh(&pch->upl);
|
||||
+ if (pch->ppp && pch->ppp->dev)
|
||||
+ ifindex = pch->ppp->dev->ifindex;
|
||||
+ read_unlock_bh(&pch->upl);
|
||||
+ }
|
||||
+ return ifindex;
|
||||
+}
|
||||
|
||||
/*
|
||||
* Disconnect a channel from the generic layer.
|
||||
@@ -3681,6 +3695,28 @@ void ppp_update_stats(struct net_device
|
||||
ppp_recv_unlock(ppp);
|
||||
}
|
||||
|
||||
+/* Returns true if Compression is enabled on PPP device
|
||||
+ */
|
||||
+bool ppp_is_cp_enabled(struct net_device *dev)
|
||||
+{
|
||||
+ struct ppp *ppp;
|
||||
+ bool flag = false;
|
||||
+
|
||||
+ if (!dev)
|
||||
+ return false;
|
||||
+
|
||||
+ if (dev->type != ARPHRD_PPP)
|
||||
+ return false;
|
||||
+
|
||||
+ ppp = netdev_priv(dev);
|
||||
+ ppp_lock(ppp);
|
||||
+ flag = !!(ppp->xstate & SC_COMP_RUN) || !!(ppp->rstate & SC_DECOMP_RUN);
|
||||
+ ppp_unlock(ppp);
|
||||
+
|
||||
+ return flag;
|
||||
+}
|
||||
+EXPORT_SYMBOL(ppp_is_cp_enabled);
|
||||
+
|
||||
/* Returns >0 if the device is a multilink PPP netdevice, 0 if not or < 0 if
|
||||
* the device is not PPP.
|
||||
*/
|
||||
@@ -3872,6 +3908,7 @@ EXPORT_SYMBOL(ppp_unregister_channel);
|
||||
EXPORT_SYMBOL(ppp_channel_index);
|
||||
EXPORT_SYMBOL(ppp_unit_number);
|
||||
EXPORT_SYMBOL(ppp_dev_name);
|
||||
+EXPORT_SYMBOL(ppp_dev_index);
|
||||
EXPORT_SYMBOL(ppp_input);
|
||||
EXPORT_SYMBOL(ppp_input_error);
|
||||
EXPORT_SYMBOL(ppp_output_wakeup);
|
||||
--- a/include/linux/ppp_channel.h
|
||||
+++ b/include/linux/ppp_channel.h
|
||||
@@ -84,6 +84,9 @@ extern void ppp_unregister_channel(struc
|
||||
/* Get the channel number for a channel */
|
||||
extern int ppp_channel_index(struct ppp_channel *);
|
||||
|
||||
+/* Get the device index associated with a channel, or 0, if none */
|
||||
+extern int ppp_dev_index(struct ppp_channel *);
|
||||
+
|
||||
/* Get the unit number associated with a channel, or -1 if none */
|
||||
extern int ppp_unit_number(struct ppp_channel *);
|
||||
|
||||
@@ -116,6 +119,7 @@ extern int ppp_hold_channels(struct net_
|
||||
/* Test if ppp xmit lock is locked */
|
||||
extern bool ppp_is_xmit_locked(struct net_device *dev);
|
||||
|
||||
+bool ppp_is_cp_enabled(struct net_device *dev);
|
||||
/* Test if the ppp device is a multi-link ppp device */
|
||||
extern int ppp_is_multilink(struct net_device *dev);
|
||||
|
||||
--- a/drivers/net/ppp/pptp.c
|
||||
+++ b/drivers/net/ppp/pptp.c
|
||||
@@ -50,6 +50,8 @@ static struct proto pptp_sk_proto __read
|
||||
static const struct ppp_channel_ops pptp_chan_ops;
|
||||
static const struct proto_ops pptp_ops;
|
||||
|
||||
+static pptp_gre_seq_offload_callback_t __rcu pptp_gre_offload_xmit_cb;
|
||||
+
|
||||
static struct pppox_sock *lookup_chan(u16 call_id, __be32 s_addr)
|
||||
{
|
||||
struct pppox_sock *sock;
|
||||
@@ -91,6 +93,79 @@ static int lookup_chan_dst(u16 call_id,
|
||||
return i < MAX_CALLID;
|
||||
}
|
||||
|
||||
+/* Search a pptp session based on local call id, local and remote ip address */
|
||||
+static int lookup_session_src(struct pptp_opt *opt, u16 call_id, __be32 daddr, __be32 saddr)
|
||||
+{
|
||||
+ struct pppox_sock *sock;
|
||||
+ int i = 1;
|
||||
+
|
||||
+ rcu_read_lock();
|
||||
+ for_each_set_bit_from(i, callid_bitmap, MAX_CALLID) {
|
||||
+ sock = rcu_dereference(callid_sock[i]);
|
||||
+ if (!sock)
|
||||
+ continue;
|
||||
+
|
||||
+ if (sock->proto.pptp.src_addr.call_id == call_id &&
|
||||
+ sock->proto.pptp.dst_addr.sin_addr.s_addr == daddr &&
|
||||
+ sock->proto.pptp.src_addr.sin_addr.s_addr == saddr) {
|
||||
+ sock_hold(sk_pppox(sock));
|
||||
+ memcpy(opt, &sock->proto.pptp, sizeof(struct pptp_opt));
|
||||
+ sock_put(sk_pppox(sock));
|
||||
+ rcu_read_unlock();
|
||||
+ return 0;
|
||||
+ }
|
||||
+ }
|
||||
+ rcu_read_unlock();
|
||||
+ return -EINVAL;
|
||||
+}
|
||||
+
|
||||
+/* Search a pptp session based on peer call id and peer ip address */
|
||||
+static int lookup_session_dst(struct pptp_opt *opt, u16 call_id, __be32 d_addr)
|
||||
+{
|
||||
+ struct pppox_sock *sock;
|
||||
+ int i = 1;
|
||||
+
|
||||
+ rcu_read_lock();
|
||||
+ for_each_set_bit_from(i, callid_bitmap, MAX_CALLID) {
|
||||
+ sock = rcu_dereference(callid_sock[i]);
|
||||
+ if (!sock)
|
||||
+ continue;
|
||||
+
|
||||
+ if (sock->proto.pptp.dst_addr.call_id == call_id &&
|
||||
+ sock->proto.pptp.dst_addr.sin_addr.s_addr == d_addr) {
|
||||
+ sock_hold(sk_pppox(sock));
|
||||
+ memcpy(opt, &sock->proto.pptp, sizeof(struct pptp_opt));
|
||||
+ sock_put(sk_pppox(sock));
|
||||
+ rcu_read_unlock();
|
||||
+ return 0;
|
||||
+ }
|
||||
+ }
|
||||
+ rcu_read_unlock();
|
||||
+ return -EINVAL;
|
||||
+}
|
||||
+
|
||||
+/* If offload mode set then this function sends all packets to
|
||||
+ * offload module instead of network stack
|
||||
+ */
|
||||
+static int pptp_client_skb_xmit(struct sk_buff *skb,
|
||||
+ struct net_device *pptp_dev)
|
||||
+{
|
||||
+ pptp_gre_seq_offload_callback_t pptp_gre_offload_cb_f;
|
||||
+ int ret;
|
||||
+
|
||||
+ rcu_read_lock();
|
||||
+ pptp_gre_offload_cb_f = rcu_dereference(pptp_gre_offload_xmit_cb);
|
||||
+
|
||||
+ if (!pptp_gre_offload_cb_f) {
|
||||
+ rcu_read_unlock();
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ ret = pptp_gre_offload_cb_f(skb, pptp_dev);
|
||||
+ rcu_read_unlock();
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
static int add_chan(struct pppox_sock *sock,
|
||||
struct pptp_addr *sa)
|
||||
{
|
||||
@@ -136,7 +211,7 @@ static struct rtable *pptp_route_output(
|
||||
struct net *net;
|
||||
|
||||
net = sock_net(sk);
|
||||
- flowi4_init_output(fl4, sk->sk_bound_dev_if, sk->sk_mark, 0,
|
||||
+ flowi4_init_output(fl4, 0, sk->sk_mark, 0,
|
||||
RT_SCOPE_UNIVERSE, IPPROTO_GRE, 0,
|
||||
po->proto.pptp.dst_addr.sin_addr.s_addr,
|
||||
po->proto.pptp.src_addr.sin_addr.s_addr,
|
||||
@@ -163,8 +238,11 @@ static int pptp_xmit(struct ppp_channel
|
||||
|
||||
struct rtable *rt;
|
||||
struct net_device *tdev;
|
||||
+ struct net_device *pptp_dev;
|
||||
struct iphdr *iph;
|
||||
int max_headroom;
|
||||
+ int pptp_ifindex;
|
||||
+ int ret;
|
||||
|
||||
if (sk_pppox(po)->sk_state & PPPOX_DEAD)
|
||||
goto tx_error;
|
||||
@@ -258,7 +336,32 @@ static int pptp_xmit(struct ppp_channel
|
||||
ip_select_ident(net, skb, NULL);
|
||||
ip_send_check(iph);
|
||||
|
||||
- ip_local_out(net, skb->sk, skb);
|
||||
+ pptp_ifindex = ppp_dev_index(chan);
|
||||
+
|
||||
+ /* set incoming interface as the ppp interface */
|
||||
+ if (skb->skb_iif)
|
||||
+ skb->skb_iif = pptp_ifindex;
|
||||
+
|
||||
+ /* If the PPTP GRE seq number offload module is not enabled yet
|
||||
+ * then sends all PPTP GRE packets through linux network stack
|
||||
+ */
|
||||
+ if (!opt->pptp_offload_mode) {
|
||||
+ ip_local_out(net, skb->sk, skb);
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ pptp_dev = dev_get_by_index(&init_net, pptp_ifindex);
|
||||
+ if (!pptp_dev)
|
||||
+ goto tx_error;
|
||||
+
|
||||
+ /* If PPTP offload module is enabled then forward all PPTP GRE
|
||||
+ * packets to PPTP GRE offload module
|
||||
+ */
|
||||
+ ret = pptp_client_skb_xmit(skb, pptp_dev);
|
||||
+ dev_put(pptp_dev);
|
||||
+ if (ret < 0)
|
||||
+ goto tx_error;
|
||||
+
|
||||
return 1;
|
||||
|
||||
tx_error:
|
||||
@@ -314,6 +417,13 @@ static int pptp_rcv_core(struct sock *sk
|
||||
goto drop;
|
||||
|
||||
payload = skb->data + headersize;
|
||||
+
|
||||
+ /* If offload is enabled, we expect the offload module
|
||||
+ * to handle PPTP GRE sequence number checks
|
||||
+ */
|
||||
+ if (opt->pptp_offload_mode)
|
||||
+ goto allow_packet;
|
||||
+
|
||||
/* check for expected sequence number */
|
||||
if (seq < opt->seq_recv + 1 || WRAPPED(opt->seq_recv, seq)) {
|
||||
if ((payload[0] == PPP_ALLSTATIONS) && (payload[1] == PPP_UI) &&
|
||||
@@ -371,6 +481,7 @@ static int pptp_rcv(struct sk_buff *skb)
|
||||
if (po) {
|
||||
skb_dst_drop(skb);
|
||||
nf_reset_ct(skb);
|
||||
+ skb->skb_iif = ppp_dev_index(&po->chan);
|
||||
return sk_receive_skb(sk_pppox(po), skb, 0);
|
||||
}
|
||||
drop:
|
||||
@@ -473,7 +584,7 @@ static int pptp_connect(struct socket *s
|
||||
|
||||
opt->dst_addr = sp->sa_addr.pptp;
|
||||
sk->sk_state |= PPPOX_CONNECTED;
|
||||
-
|
||||
+ opt->pptp_offload_mode = false;
|
||||
end:
|
||||
release_sock(sk);
|
||||
return error;
|
||||
@@ -603,9 +714,169 @@ static int pptp_ppp_ioctl(struct ppp_cha
|
||||
return err;
|
||||
}
|
||||
|
||||
+/* pptp_channel_addressing_get()
|
||||
+ * Return PPTP channel specific addressing information.
|
||||
+ */
|
||||
+void pptp_channel_addressing_get(struct pptp_opt *opt, struct ppp_channel *chan)
|
||||
+{
|
||||
+ struct sock *sk;
|
||||
+ struct pppox_sock *po;
|
||||
+
|
||||
+ if (!opt)
|
||||
+ return;
|
||||
+
|
||||
+ sk = (struct sock *)chan->private;
|
||||
+ if (!sk)
|
||||
+ return;
|
||||
+
|
||||
+ sock_hold(sk);
|
||||
+
|
||||
+ /* This is very unlikely, but check the socket is connected state */
|
||||
+ if (unlikely(sock_flag(sk, SOCK_DEAD) ||
|
||||
+ !(sk->sk_state & PPPOX_CONNECTED))) {
|
||||
+ sock_put(sk);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ po = pppox_sk(sk);
|
||||
+ memcpy(opt, &po->proto.pptp, sizeof(struct pptp_opt));
|
||||
+ sock_put(sk);
|
||||
+}
|
||||
+EXPORT_SYMBOL(pptp_channel_addressing_get);
|
||||
+
|
||||
+/* pptp_session_find()
|
||||
+ * Search and return a PPTP session info based on peer callid and IP
|
||||
+ * address. The function accepts the parameters in network byte order.
|
||||
+ */
|
||||
+int pptp_session_find(struct pptp_opt *opt, __be16 peer_call_id,
|
||||
+ __be32 peer_ip_addr)
|
||||
+{
|
||||
+ if (!opt)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ return lookup_session_dst(opt, ntohs(peer_call_id), peer_ip_addr);
|
||||
+}
|
||||
+EXPORT_SYMBOL(pptp_session_find);
|
||||
+
|
||||
+/* pptp_session_find_by_src_callid()
|
||||
+ * Search and return a PPTP session info based on src callid and IP
|
||||
+ * address. The function accepts the parameters in network byte order.
|
||||
+ */
|
||||
+int pptp_session_find_by_src_callid(struct pptp_opt *opt, __be16 src_call_id,
|
||||
+ __be32 daddr, __be32 saddr)
|
||||
+{
|
||||
+ if (!opt)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ return lookup_session_src(opt, ntohs(src_call_id), daddr, saddr);
|
||||
+}
|
||||
+EXPORT_SYMBOL(pptp_session_find_by_src_callid);
|
||||
+
|
||||
+ /* Function to change the offload mode true/false for a PPTP session */
|
||||
+static int pptp_set_offload_mode(bool accel_mode,
|
||||
+ __be16 peer_call_id, __be32 peer_ip_addr)
|
||||
+{
|
||||
+ struct pppox_sock *sock;
|
||||
+ int i = 1;
|
||||
+
|
||||
+ rcu_read_lock();
|
||||
+ for_each_set_bit_from(i, callid_bitmap, MAX_CALLID) {
|
||||
+ sock = rcu_dereference(callid_sock[i]);
|
||||
+ if (!sock)
|
||||
+ continue;
|
||||
+
|
||||
+ if (sock->proto.pptp.dst_addr.call_id == peer_call_id &&
|
||||
+ sock->proto.pptp.dst_addr.sin_addr.s_addr == peer_ip_addr) {
|
||||
+ sock_hold(sk_pppox(sock));
|
||||
+ sock->proto.pptp.pptp_offload_mode = accel_mode;
|
||||
+ sock_put(sk_pppox(sock));
|
||||
+ rcu_read_unlock();
|
||||
+ return 0;
|
||||
+ }
|
||||
+ }
|
||||
+ rcu_read_unlock();
|
||||
+ return -EINVAL;
|
||||
+}
|
||||
+
|
||||
+/* Enable the PPTP session offload flag */
|
||||
+int pptp_session_enable_offload_mode(__be16 peer_call_id, __be32 peer_ip_addr)
|
||||
+{
|
||||
+ return pptp_set_offload_mode(true, peer_call_id, peer_ip_addr);
|
||||
+}
|
||||
+EXPORT_SYMBOL(pptp_session_enable_offload_mode);
|
||||
+
|
||||
+/* Disable the PPTP session offload flag */
|
||||
+int pptp_session_disable_offload_mode(__be16 peer_call_id, __be32 peer_ip_addr)
|
||||
+{
|
||||
+ return pptp_set_offload_mode(false, peer_call_id, peer_ip_addr);
|
||||
+}
|
||||
+EXPORT_SYMBOL(pptp_session_disable_offload_mode);
|
||||
+
|
||||
+/* Register the offload callback function on behalf of the module which
|
||||
+ * will own the sequence and acknowledgment number updates for all
|
||||
+ * PPTP GRE packets. All PPTP GRE packets are then transmitted to this
|
||||
+ * module after encapsulation in order to ensure the correct seq/ack
|
||||
+ * fields are set in the packets before transmission. This is required
|
||||
+ * when PPTP flows are offloaded to acceleration engines, in-order to
|
||||
+ * ensure consistency in sequence and ack numbers between PPTP control
|
||||
+ * (PPP LCP) and data packets
|
||||
+ */
|
||||
+int pptp_register_gre_seq_offload_callback(pptp_gre_seq_offload_callback_t
|
||||
+ pptp_gre_offload_cb)
|
||||
+{
|
||||
+ pptp_gre_seq_offload_callback_t pptp_gre_offload_cb_f;
|
||||
+
|
||||
+ rcu_read_lock();
|
||||
+ pptp_gre_offload_cb_f = rcu_dereference(pptp_gre_offload_xmit_cb);
|
||||
+
|
||||
+ if (pptp_gre_offload_cb_f) {
|
||||
+ rcu_read_unlock();
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ rcu_assign_pointer(pptp_gre_offload_xmit_cb, pptp_gre_offload_cb);
|
||||
+ rcu_read_unlock();
|
||||
+ return 0;
|
||||
+}
|
||||
+EXPORT_SYMBOL(pptp_register_gre_seq_offload_callback);
|
||||
+
|
||||
+/* Unregister the PPTP GRE packets sequence number offload callback */
|
||||
+void pptp_unregister_gre_seq_offload_callback(void)
|
||||
+{
|
||||
+ rcu_assign_pointer(pptp_gre_offload_xmit_cb, NULL);
|
||||
+}
|
||||
+EXPORT_SYMBOL(pptp_unregister_gre_seq_offload_callback);
|
||||
+
|
||||
+/* pptp_hold_chan() */
|
||||
+static void pptp_hold_chan(struct ppp_channel *chan)
|
||||
+{
|
||||
+ struct sock *sk = (struct sock *)chan->private;
|
||||
+
|
||||
+ sock_hold(sk);
|
||||
+}
|
||||
+
|
||||
+/* pptp_release_chan() */
|
||||
+static void pptp_release_chan(struct ppp_channel *chan)
|
||||
+{
|
||||
+ struct sock *sk = (struct sock *)chan->private;
|
||||
+
|
||||
+ sock_put(sk);
|
||||
+}
|
||||
+
|
||||
+/* pptp_get_channel_protocol()
|
||||
+ * Return the protocol type of the PPTP over PPP protocol
|
||||
+ */
|
||||
+static int pptp_get_channel_protocol(struct ppp_channel *chan)
|
||||
+{
|
||||
+ return PX_PROTO_PPTP;
|
||||
+}
|
||||
+
|
||||
static const struct ppp_channel_ops pptp_chan_ops = {
|
||||
.start_xmit = pptp_xmit,
|
||||
.ioctl = pptp_ppp_ioctl,
|
||||
+ .get_channel_protocol = pptp_get_channel_protocol,
|
||||
+ .hold = pptp_hold_chan,
|
||||
+ .release = pptp_release_chan,
|
||||
};
|
||||
|
||||
static struct proto pptp_sk_proto __read_mostly = {
|
|
@ -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
|
||||
@@ -553,4 +553,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
|
||||
@@ -2398,6 +2398,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
|
||||
@@ -1733,6 +1733,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 },
|
|
@ -0,0 +1,103 @@
|
|||
--- a/drivers/net/vxlan/vxlan_core.c
|
||||
+++ b/drivers/net/vxlan/vxlan_core.c
|
||||
@@ -71,6 +71,20 @@ static inline bool vxlan_collect_metadat
|
||||
ip_tunnel_collect_metadata();
|
||||
}
|
||||
|
||||
+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);
|
||||
+
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
static int vxlan_nla_get_addr(union vxlan_addr *ip, struct nlattr *nla)
|
||||
{
|
||||
@@ -307,6 +321,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);
|
||||
@@ -322,6 +337,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)
|
||||
@@ -488,6 +507,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,
|
||||
@@ -2658,6 +2689,9 @@ static void vxlan_xmit_one(struct sk_buf
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
+ /* Reset the skb_iif to Tunnels interface index */
|
||||
+ skb->skb_iif = dev->ifindex;
|
||||
+
|
||||
tos = ip_tunnel_ecn_encap(tos, old_iph, skb);
|
||||
ttl = ttl ? : ip4_dst_hoplimit(&rt->dst);
|
||||
err = vxlan_build_skb(skb, ndst, sizeof(struct iphdr),
|
||||
@@ -2729,6 +2763,9 @@ static void vxlan_xmit_one(struct sk_buf
|
||||
if (err < 0)
|
||||
goto tx_error;
|
||||
|
||||
+ /* Reset the skb_iif to Tunnels interface index */
|
||||
+ skb->skb_iif = dev->ifindex;
|
||||
+
|
||||
udp_tunnel6_xmit_skb(ndst, sock6->sock->sk, skb, dev,
|
||||
&local_ip.sin6.sin6_addr,
|
||||
&dst->sin6.sin6_addr, tos, ttl,
|
||||
--- a/include/net/vxlan.h
|
||||
+++ b/include/net/vxlan.h
|
||||
@@ -344,6 +344,19 @@ struct vxlan_dev {
|
||||
VXLAN_F_COLLECT_METADATA | \
|
||||
VXLAN_F_VNIFILTER)
|
||||
|
||||
+/*
|
||||
+ * 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);
|
||||
|
|
@ -0,0 +1,368 @@
|
|||
--- a/include/linux/ppp_channel.h
|
||||
+++ b/include/linux/ppp_channel.h
|
||||
@@ -61,6 +61,51 @@ struct ppp_channel {
|
||||
};
|
||||
|
||||
#ifdef __KERNEL__
|
||||
+/* Call this to obtain the underlying protocol of the PPP channel,
|
||||
+ * e.g. PX_PROTO_OE
|
||||
+ */
|
||||
+extern int ppp_channel_get_protocol(struct ppp_channel *);
|
||||
+
|
||||
+/* Call this to hold a channel */
|
||||
+extern bool ppp_channel_hold(struct ppp_channel *);
|
||||
+
|
||||
+/* Call this to release a hold you have upon a channel */
|
||||
+extern void ppp_channel_release(struct ppp_channel *);
|
||||
+
|
||||
+/* Release hold on PPP channels */
|
||||
+extern void ppp_release_channels(struct ppp_channel *channels[],
|
||||
+ unsigned int chan_sz);
|
||||
+
|
||||
+/* Test if ppp xmit lock is locked */
|
||||
+extern bool ppp_is_xmit_locked(struct net_device *dev);
|
||||
+
|
||||
+/* Call this get protocol version */
|
||||
+extern int ppp_channel_get_proto_version(struct ppp_channel *);
|
||||
+
|
||||
+/* Get the device index associated with a channel, or 0, if none */
|
||||
+extern int ppp_dev_index(struct ppp_channel *);
|
||||
+
|
||||
+/* Hold PPP channels for the PPP device */
|
||||
+extern int ppp_hold_channels(struct net_device *dev,
|
||||
+ struct ppp_channel *channels[],
|
||||
+ unsigned int chan_sz);
|
||||
+extern int __ppp_hold_channels(struct net_device *dev,
|
||||
+ struct ppp_channel *channels[],
|
||||
+ unsigned int chan_sz);
|
||||
+
|
||||
+/* Test if the ppp device is a multi-link ppp device */
|
||||
+extern int ppp_is_multilink(struct net_device *dev);
|
||||
+extern int __ppp_is_multilink(struct net_device *dev);
|
||||
+
|
||||
+/* Update statistics of the PPP net_device by incrementing related
|
||||
+ * statistics field value with corresponding parameter
|
||||
+ */
|
||||
+extern void ppp_update_stats(struct net_device *dev, unsigned long rx_packets,
|
||||
+ unsigned long rx_bytes, unsigned long tx_packets,
|
||||
+ unsigned long tx_bytes, unsigned long rx_errors,
|
||||
+ unsigned long tx_errors, unsigned long rx_dropped,
|
||||
+ unsigned long tx_dropped);
|
||||
+
|
||||
/* Called by the channel when it can send some more data. */
|
||||
extern void ppp_output_wakeup(struct ppp_channel *);
|
||||
|
||||
@@ -148,5 +193,17 @@ extern void ppp_update_stats(struct net_
|
||||
* that ppp_unregister_channel returns.
|
||||
*/
|
||||
|
||||
+/* QCA NSS Clients Support - Start */
|
||||
+/* PPP channel connection event types */
|
||||
+#define PPP_CHANNEL_DISCONNECT 0
|
||||
+#define PPP_CHANNEL_CONNECT 1
|
||||
+
|
||||
+/* Register the PPP channel connect notifier */
|
||||
+extern void ppp_channel_connection_register_notify(struct notifier_block *nb);
|
||||
+
|
||||
+/* Unregister the PPP channel connect notifier */
|
||||
+extern void ppp_channel_connection_unregister_notify(struct notifier_block *nb);
|
||||
+/* QCA NSS Clients Support - End */
|
||||
+
|
||||
#endif /* __KERNEL__ */
|
||||
#endif
|
||||
--- a/include/linux/if_pppol2tp.h
|
||||
+++ b/include/linux/if_pppol2tp.h
|
||||
@@ -12,4 +12,30 @@
|
||||
#include <linux/in6.h>
|
||||
#include <uapi/linux/if_pppol2tp.h>
|
||||
|
||||
+/* QCA NSS ECM support - Start */
|
||||
+/*
|
||||
+ * Holds L2TP channel info
|
||||
+ */
|
||||
+struct pppol2tp_common_addr {
|
||||
+ int tunnel_version; /* v2 or v3 */
|
||||
+ __u32 local_tunnel_id, remote_tunnel_id; /* tunnel id */
|
||||
+ __u32 local_session_id, remote_session_id; /* session id */
|
||||
+ struct sockaddr_in local_addr, remote_addr; /* ip address and port */
|
||||
+};
|
||||
+
|
||||
+/*
|
||||
+ * L2TP channel operations
|
||||
+ */
|
||||
+struct pppol2tp_channel_ops {
|
||||
+ struct ppp_channel_ops ops; /* ppp channel ops */
|
||||
+};
|
||||
+
|
||||
+/*
|
||||
+ * exported function which calls pppol2tp channel's get addressing
|
||||
+ * function
|
||||
+ */
|
||||
+extern int pppol2tp_channel_addressing_get(struct ppp_channel *,
|
||||
+ struct pppol2tp_common_addr *);
|
||||
+/* QCA NSS ECM support - End */
|
||||
+
|
||||
#endif
|
||||
--- a/net/l2tp/l2tp_ppp.c
|
||||
+++ b/net/l2tp/l2tp_ppp.c
|
||||
@@ -123,9 +123,17 @@ struct pppol2tp_session {
|
||||
};
|
||||
|
||||
static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb);
|
||||
-
|
||||
-static const struct ppp_channel_ops pppol2tp_chan_ops = {
|
||||
- .start_xmit = pppol2tp_xmit,
|
||||
+static int pppol2tp_get_channel_protocol(struct ppp_channel *);
|
||||
+static int pppol2tp_get_channel_protocol_ver(struct ppp_channel *);
|
||||
+static void pppol2tp_hold_chan(struct ppp_channel *);
|
||||
+static void pppol2tp_release_chan(struct ppp_channel *);
|
||||
+
|
||||
+static const struct pppol2tp_channel_ops pppol2tp_chan_ops = {
|
||||
+ .ops.start_xmit = pppol2tp_xmit,
|
||||
+ .ops.get_channel_protocol = pppol2tp_get_channel_protocol,
|
||||
+ .ops.get_channel_protocol_ver = pppol2tp_get_channel_protocol_ver,
|
||||
+ .ops.hold = pppol2tp_hold_chan,
|
||||
+ .ops.release = pppol2tp_release_chan,
|
||||
};
|
||||
|
||||
static const struct proto_ops pppol2tp_ops;
|
||||
@@ -373,6 +381,13 @@ static int pppol2tp_xmit(struct ppp_chan
|
||||
skb->data[0] = PPP_ALLSTATIONS;
|
||||
skb->data[1] = PPP_UI;
|
||||
|
||||
+ /* QCA NSS ECM support - start */
|
||||
+ /* set incoming interface as the ppp interface */
|
||||
+ if ((skb->protocol == htons(ETH_P_IP)) ||
|
||||
+ (skb->protocol == htons(ETH_P_IPV6)))
|
||||
+ skb->skb_iif = ppp_dev_index(chan);
|
||||
+ /* QCA NSS ECM support - End */
|
||||
+
|
||||
local_bh_disable();
|
||||
l2tp_xmit_skb(session, skb);
|
||||
local_bh_enable();
|
||||
@@ -818,7 +833,7 @@ static int pppol2tp_connect(struct socke
|
||||
po->chan.hdrlen = PPPOL2TP_L2TP_HDR_SIZE_NOSEQ;
|
||||
|
||||
po->chan.private = sk;
|
||||
- po->chan.ops = &pppol2tp_chan_ops;
|
||||
+ po->chan.ops = (struct ppp_channel_ops *)&pppol2tp_chan_ops.ops;
|
||||
po->chan.mtu = pppol2tp_tunnel_mtu(tunnel);
|
||||
|
||||
error = ppp_register_net_channel(sock_net(sk), &po->chan);
|
||||
@@ -1732,6 +1747,109 @@ static void __exit pppol2tp_exit(void)
|
||||
unregister_pernet_device(&pppol2tp_net_ops);
|
||||
}
|
||||
|
||||
+/* QCA NSS ECM support - Start */
|
||||
+/* pppol2tp_hold_chan() */
|
||||
+static void pppol2tp_hold_chan(struct ppp_channel *chan)
|
||||
+{
|
||||
+ struct sock *sk = (struct sock *)chan->private;
|
||||
+
|
||||
+ sock_hold(sk);
|
||||
+}
|
||||
+
|
||||
+/* pppol2tp_release_chan() */
|
||||
+static void pppol2tp_release_chan(struct ppp_channel *chan)
|
||||
+{
|
||||
+ struct sock *sk = (struct sock *)chan->private;
|
||||
+
|
||||
+ sock_put(sk);
|
||||
+}
|
||||
+
|
||||
+/* pppol2tp_get_channel_protocol()
|
||||
+ * Return the protocol type of the L2TP over PPP protocol
|
||||
+ */
|
||||
+static int pppol2tp_get_channel_protocol(struct ppp_channel *chan)
|
||||
+{
|
||||
+ return PX_PROTO_OL2TP;
|
||||
+}
|
||||
+
|
||||
+/* pppol2tp_get_channel_protocol_ver()
|
||||
+ * Return the protocol version of the L2TP over PPP protocol
|
||||
+ */
|
||||
+static int pppol2tp_get_channel_protocol_ver(struct ppp_channel *chan)
|
||||
+{
|
||||
+ struct sock *sk;
|
||||
+ struct l2tp_session *session;
|
||||
+ struct l2tp_tunnel *tunnel;
|
||||
+ int version = 0;
|
||||
+
|
||||
+ if (chan && chan->private)
|
||||
+ sk = (struct sock *)chan->private;
|
||||
+ else
|
||||
+ return -1;
|
||||
+
|
||||
+ /* Get session and tunnel contexts from the socket */
|
||||
+ session = pppol2tp_sock_to_session(sk);
|
||||
+ if (!session)
|
||||
+ return -1;
|
||||
+
|
||||
+ tunnel = session->tunnel;
|
||||
+ if (!tunnel) {
|
||||
+ sock_put(sk);
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ version = tunnel->version;
|
||||
+
|
||||
+ sock_put(sk);
|
||||
+
|
||||
+ return version;
|
||||
+}
|
||||
+
|
||||
+/* pppol2tp_get_addressing() */
|
||||
+static int pppol2tp_get_addressing(struct ppp_channel *chan,
|
||||
+ struct pppol2tp_common_addr *addr)
|
||||
+{
|
||||
+ struct sock *sk = (struct sock *)chan->private;
|
||||
+ struct l2tp_session *session;
|
||||
+ struct l2tp_tunnel *tunnel;
|
||||
+ struct inet_sock *isk = NULL;
|
||||
+ int err = -ENXIO;
|
||||
+
|
||||
+ /* Get session and tunnel contexts from the socket */
|
||||
+ session = pppol2tp_sock_to_session(sk);
|
||||
+ if (!session)
|
||||
+ return err;
|
||||
+
|
||||
+ tunnel = session->tunnel;
|
||||
+ if (!tunnel) {
|
||||
+ sock_put(sk);
|
||||
+ return err;
|
||||
+ }
|
||||
+ isk = inet_sk(tunnel->sock);
|
||||
+
|
||||
+ addr->local_tunnel_id = tunnel->tunnel_id;
|
||||
+ addr->remote_tunnel_id = tunnel->peer_tunnel_id;
|
||||
+ addr->local_session_id = session->session_id;
|
||||
+ addr->remote_session_id = session->peer_session_id;
|
||||
+
|
||||
+ addr->local_addr.sin_port = isk->inet_sport;
|
||||
+ addr->remote_addr.sin_port = isk->inet_dport;
|
||||
+ addr->local_addr.sin_addr.s_addr = isk->inet_saddr;
|
||||
+ addr->remote_addr.sin_addr.s_addr = isk->inet_daddr;
|
||||
+
|
||||
+ sock_put(sk);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/* pppol2tp_channel_addressing_get() */
|
||||
+int pppol2tp_channel_addressing_get(struct ppp_channel *chan,
|
||||
+ struct pppol2tp_common_addr *addr)
|
||||
+{
|
||||
+ return pppol2tp_get_addressing(chan, addr);
|
||||
+}
|
||||
+EXPORT_SYMBOL(pppol2tp_channel_addressing_get);
|
||||
+/* QCA NSS ECM support - End */
|
||||
+
|
||||
module_init(pppol2tp_init);
|
||||
module_exit(pppol2tp_exit);
|
||||
|
||||
--- a/drivers/net/ppp/ppp_generic.c
|
||||
+++ b/drivers/net/ppp/ppp_generic.c
|
||||
@@ -3743,6 +3743,32 @@ int ppp_is_multilink(struct net_device *
|
||||
}
|
||||
EXPORT_SYMBOL(ppp_is_multilink);
|
||||
|
||||
+/* __ppp_is_multilink()
|
||||
+ * Returns >0 if the device is a multilink PPP netdevice, 0 if not or < 0
|
||||
+ * if the device is not PPP. Caller should acquire ppp_lock before calling
|
||||
+ * this function
|
||||
+ */
|
||||
+int __ppp_is_multilink(struct net_device *dev)
|
||||
+{
|
||||
+ struct ppp *ppp;
|
||||
+ unsigned int flags;
|
||||
+
|
||||
+ if (!dev)
|
||||
+ return -1;
|
||||
+
|
||||
+ if (dev->type != ARPHRD_PPP)
|
||||
+ return -1;
|
||||
+
|
||||
+ ppp = netdev_priv(dev);
|
||||
+ flags = ppp->flags;
|
||||
+
|
||||
+ if (flags & SC_MULTILINK)
|
||||
+ return 1;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+EXPORT_SYMBOL(__ppp_is_multilink);
|
||||
+
|
||||
/* ppp_channel_get_protocol()
|
||||
* Call this to obtain the underlying protocol of the PPP channel,
|
||||
* e.g. PX_PROTO_OE
|
||||
@@ -3881,6 +3907,59 @@ int ppp_hold_channels(struct net_device
|
||||
}
|
||||
EXPORT_SYMBOL(ppp_hold_channels);
|
||||
|
||||
+/* __ppp_hold_channels()
|
||||
+ * Returns the PPP channels of the PPP device, storing each one into
|
||||
+ * channels[].
|
||||
+ *
|
||||
+ * channels[] has chan_sz elements.
|
||||
+ * This function returns the number of channels stored, up to chan_sz.
|
||||
+ * It will return < 0 if the device is not PPP.
|
||||
+ *
|
||||
+ * You MUST release the channels using ppp_release_channels().
|
||||
+ */
|
||||
+int __ppp_hold_channels(struct net_device *dev, struct ppp_channel *channels[],
|
||||
+ unsigned int chan_sz)
|
||||
+{
|
||||
+ struct ppp *ppp;
|
||||
+ int c;
|
||||
+ struct channel *pch;
|
||||
+
|
||||
+ if (!dev)
|
||||
+ return -1;
|
||||
+
|
||||
+ if (dev->type != ARPHRD_PPP)
|
||||
+ return -1;
|
||||
+
|
||||
+ ppp = netdev_priv(dev);
|
||||
+
|
||||
+ c = 0;
|
||||
+ list_for_each_entry(pch, &ppp->channels, clist) {
|
||||
+ struct ppp_channel *chan;
|
||||
+
|
||||
+ if (!pch->chan) {
|
||||
+ /* Channel is going / gone away */
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (c == chan_sz) {
|
||||
+ /* No space to record channel */
|
||||
+ return c;
|
||||
+ }
|
||||
+
|
||||
+ /* Hold the channel, if supported */
|
||||
+ chan = pch->chan;
|
||||
+ if (!chan->ops->hold)
|
||||
+ continue;
|
||||
+
|
||||
+ chan->ops->hold(chan);
|
||||
+
|
||||
+ /* Record the channel */
|
||||
+ channels[c++] = chan;
|
||||
+ }
|
||||
+ return c;
|
||||
+}
|
||||
+EXPORT_SYMBOL(__ppp_hold_channels);
|
||||
+
|
||||
/* ppp_release_channels()
|
||||
* Releases channels
|
||||
*/
|
||||
--- a/net/l2tp/l2tp_core.h
|
||||
+++ b/net/l2tp/l2tp_core.h
|
||||
@@ -235,6 +235,9 @@ struct l2tp_session *l2tp_session_get_by
|
||||
void l2tp_stats_update(struct l2tp_tunnel *tunnel, struct l2tp_session *session,
|
||||
struct l2tp_stats *stats);
|
||||
|
||||
+void l2tp_stats_update(struct l2tp_tunnel *tunnel, struct l2tp_session *session,
|
||||
+ struct l2tp_stats *stats);
|
||||
+
|
||||
/* Tunnel and session lifetime management.
|
||||
* Creation of a new instance is a two-step process: create, then register.
|
||||
* Destruction is triggered using the *_delete functions, and completes asynchronously.
|
|
@ -0,0 +1,22 @@
|
|||
--- a/net/ipv6/ip6_tunnel.c
|
||||
+++ b/net/ipv6/ip6_tunnel.c
|
||||
@@ -2404,7 +2404,7 @@ nla_put_failure:
|
||||
*/
|
||||
void ip6_update_offload_stats(struct net_device *dev, void *ptr)
|
||||
{
|
||||
- struct pcpu_sw_netstats *tstats = per_cpu_ptr(dev->tstats, 0);
|
||||
+ struct pcpu_sw_netstats *tstats = this_cpu_ptr(dev->tstats);
|
||||
const struct pcpu_sw_netstats *offload_stats =
|
||||
(struct pcpu_sw_netstats *)ptr;
|
||||
|
||||
--- a/net/ipv6/sit.c
|
||||
+++ b/net/ipv6/sit.c
|
||||
@@ -1736,7 +1736,7 @@ nla_put_failure:
|
||||
/* 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);
|
||||
+ struct pcpu_sw_netstats *tstats = this_cpu_ptr(dev->tstats);
|
||||
const struct pcpu_sw_netstats *offload_stats =
|
||||
(struct pcpu_sw_netstats *)ptr;
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
--- /dev/null
|
||||
+++ b/include/uapi/linux/tlshdr.h
|
||||
@@ -0,0 +1,21 @@
|
||||
+#ifndef _UAPI_LINUX_TLSHDR_H
|
||||
+#define _UAPI_LINUX_TLSHDR_H
|
||||
+
|
||||
+#include <linux/types.h>
|
||||
+
|
||||
+struct tlshdr {
|
||||
+ __u8 type;
|
||||
+ __be16 version;
|
||||
+ __be16 len;
|
||||
+} __attribute__((packed));
|
||||
+
|
||||
+#define TLSHDR_REC_TYPE_CCS 20 /* TLS packet is change cipher specification */
|
||||
+#define TLSHDR_REC_TYPE_ALERT 21 /* TLS packet is Alert */
|
||||
+#define TLSHDR_REC_TYPE_HANDSHAKE 22 /* TLS packet is Handshake */
|
||||
+#define TLSHDR_REC_TYPE_DATA 23 /* TLS packet is Application data */
|
||||
+
|
||||
+#define TLSHDR_VERSION_1_1 0x0302 /* TLS Header Version(tls 1.1) */
|
||||
+#define TLSHDR_VERSION_1_2 0x0303 /* TLS Header Version(tls 1.2) */
|
||||
+#define TLSHDR_VERSION_1_3 0x0304 /* TLS Header Version(tls 1.3) */
|
||||
+
|
||||
+#endif /* _UAPI_LINUX_TLSHDR_H */
|
|
@ -0,0 +1,876 @@
|
|||
--- a/include/linux/if_bridge.h
|
||||
+++ b/include/linux/if_bridge.h
|
||||
@@ -281,4 +281,17 @@ extern br_get_dst_hook_t __rcu *br_get_d
|
||||
extern struct net_device *br_fdb_bridge_dev_get_and_hold(struct net_bridge *br);
|
||||
/* QCA NSS bridge-mgr support - End */
|
||||
|
||||
+/* QCA qca-mcs support - Start */
|
||||
+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 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;
|
||||
+
|
||||
+typedef void (br_notify_hook_t)(int group, int event, const void *ptr);
|
||||
+extern br_notify_hook_t __rcu *br_notify_hook;
|
||||
+/* QCA qca-mcs support - End */
|
||||
+
|
||||
#endif
|
||||
--- a/net/bridge/br_fdb.c
|
||||
+++ b/net/bridge/br_fdb.c
|
||||
@@ -232,6 +232,8 @@ static void fdb_notify(struct net_bridge
|
||||
kfree_skb(skb);
|
||||
goto errout;
|
||||
}
|
||||
+
|
||||
+ __br_notify(RTNLGRP_NEIGH, type, fdb); /* QCA qca-mcs support */
|
||||
rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);
|
||||
return;
|
||||
errout:
|
||||
@@ -298,6 +300,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); /* QCA qca-mcs support */
|
||||
|
||||
/* 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
|
||||
--- a/net/bridge/br_private.h
|
||||
+++ b/net/bridge/br_private.h
|
||||
@@ -853,6 +853,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); /* QCA qca-mcs support */
|
||||
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);
|
||||
|
||||
@@ -2178,4 +2179,14 @@ struct nd_msg *br_is_nd_neigh_msg(struct
|
||||
#define __br_get(__hook, __default, __args ...) \
|
||||
(__hook ? (__hook(__args)) : (__default))
|
||||
/* QCA NSS ECM support - End */
|
||||
+
|
||||
+/* QCA qca-mcs support - Start */
|
||||
+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);
|
||||
+}
|
||||
+/* QCA qca-mcs support - End */
|
||||
#endif
|
||||
--- a/net/bridge/br_netlink.c
|
||||
+++ b/net/bridge/br_netlink.c
|
||||
@@ -640,6 +640,7 @@ void br_info_notify(int event, const str
|
||||
kfree_skb(skb);
|
||||
goto errout;
|
||||
}
|
||||
+ __br_notify(RTNLGRP_LINK, event, port); /* QCA qca-mcs support */
|
||||
rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC);
|
||||
return;
|
||||
errout:
|
||||
--- a/net/bridge/br.c
|
||||
+++ b/net/bridge/br.c
|
||||
@@ -467,6 +467,12 @@ static void __exit br_deinit(void)
|
||||
br_fdb_fini();
|
||||
}
|
||||
|
||||
+/* QCA qca-mcs support - Start */
|
||||
+/* Hook for bridge event notifications */
|
||||
+br_notify_hook_t __rcu *br_notify_hook __read_mostly;
|
||||
+EXPORT_SYMBOL_GPL(br_notify_hook);
|
||||
+/* QCA qca-mcs support - End */
|
||||
+
|
||||
module_init(br_init)
|
||||
module_exit(br_deinit)
|
||||
MODULE_LICENSE("GPL");
|
||||
--- a/net/bridge/br_device.c
|
||||
+++ b/net/bridge/br_device.c
|
||||
@@ -82,6 +82,13 @@ netdev_tx_t br_dev_xmit(struct sk_buff *
|
||||
if (is_broadcast_ether_addr(dest)) {
|
||||
br_flood(br, skb, BR_PKT_BROADCAST, false, true);
|
||||
} else if (is_multicast_ether_addr(dest)) {
|
||||
+ /* QCA qca-mcs support - Start */
|
||||
+ 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;
|
||||
+ /* QCA qca-mcs support - End */
|
||||
+
|
||||
if (unlikely(netpoll_tx_running(dev))) {
|
||||
br_flood(br, skb, BR_PKT_MULTICAST, false, true);
|
||||
goto out;
|
||||
--- a/net/bridge/br_input.c
|
||||
+++ b/net/bridge/br_input.c
|
||||
@@ -30,7 +30,17 @@ br_netif_receive_skb(struct net *net, st
|
||||
return netif_receive_skb(skb);
|
||||
}
|
||||
|
||||
-static int br_pass_frame_up(struct sk_buff *skb)
|
||||
+/* QCA qca-mcs support - Start */
|
||||
+/* Hook for external Multicast handler */
|
||||
+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);
|
||||
+/* QCA qca-mcs support - End */
|
||||
+
|
||||
+int br_pass_frame_up(struct sk_buff *skb)
|
||||
{
|
||||
struct net_device *indev, *brdev = BR_INPUT_SKB_CB(skb)->brdev;
|
||||
struct net_bridge *br = netdev_priv(brdev);
|
||||
@@ -69,6 +79,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); /* QCA qca-mcs support */
|
||||
|
||||
/* note: already called with rcu_read_lock */
|
||||
int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||
@@ -82,6 +93,11 @@ int br_handle_frame_finish(struct net *n
|
||||
struct net_bridge_mcast *brmctx;
|
||||
struct net_bridge_vlan *vlan;
|
||||
struct net_bridge *br;
|
||||
+ /* QCA qca-mcs support - Start */
|
||||
+ 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);
|
||||
+ /* QCA qca-mcs support - End */
|
||||
u16 vid = 0;
|
||||
u8 state;
|
||||
|
||||
@@ -158,6 +174,12 @@ int br_handle_frame_finish(struct net *n
|
||||
|
||||
switch (pkt_type) {
|
||||
case BR_PKT_MULTICAST:
|
||||
+ /* QCA qca-mcs support - Start */
|
||||
+ multicast_handle_hook = rcu_dereference(br_multicast_handle_hook);
|
||||
+ if (!__br_get(multicast_handle_hook, true, p, skb))
|
||||
+ goto out;
|
||||
+ /* QCA qca-mcs support - End */
|
||||
+
|
||||
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)) {
|
||||
@@ -173,8 +195,15 @@ 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);
|
||||
- break;
|
||||
+ /* QCA qca-mcs support - Start */
|
||||
+ pdst = __br_get(get_dst_hook, NULL, p, &skb);
|
||||
+ if (pdst) {
|
||||
+ if (!skb)
|
||||
+ goto out;
|
||||
+ } else {
|
||||
+ /* QCA qca-mcs support - End */
|
||||
+ dst = br_fdb_find_rcu(br, eth_hdr(skb)->h_dest, vid);
|
||||
+ }
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -189,6 +218,13 @@ int br_handle_frame_finish(struct net *n
|
||||
dst->used = now;
|
||||
br_forward(dst->dst, skb, local_rcv, false);
|
||||
} else {
|
||||
+ /* QCA qca-mcs support - Start */
|
||||
+ if (pdst) {
|
||||
+ br_forward(pdst, skb, local_rcv, false);
|
||||
+ goto out;
|
||||
+ }
|
||||
+ /* QCA qca-mcs support - End */
|
||||
+
|
||||
if (!mcast_hit)
|
||||
br_flood(br, skb, pkt_type, local_rcv, false);
|
||||
else
|
||||
--- a/include/linux/mroute.h
|
||||
+++ b/include/linux/mroute.h
|
||||
@@ -85,4 +85,44 @@ struct rtmsg;
|
||||
int ipmr_get_route(struct net *net, struct sk_buff *skb,
|
||||
__be32 saddr, __be32 daddr,
|
||||
struct rtmsg *rtm, u32 portid);
|
||||
+
|
||||
+/* QCA ECM qca-mcs support - Start */
|
||||
+#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);
|
||||
+/* QCA ECM qca-mcs support - End */
|
||||
#endif
|
||||
--- a/include/linux/mroute6.h
|
||||
+++ b/include/linux/mroute6.h
|
||||
@@ -110,4 +110,47 @@ static inline int ip6mr_sk_done(struct s
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
+
|
||||
+/* QCA qca-mcs support - Start */
|
||||
+#define IP6MR_MFC_EVENT_UPDATE 1
|
||||
+#define IP6MR_MFC_EVENT_DELETE 2
|
||||
+
|
||||
+/*
|
||||
+ * 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);
|
||||
+/* QCA qca-mcs support - End */
|
||||
#endif
|
||||
--- 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); /* QCA ECM qca-mcs support */
|
||||
+
|
||||
/* 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; /* QCA ECM qca-mcs support */
|
||||
|
||||
#ifdef CONFIG_IP_MROUTE_MULTIPLE_TABLES
|
||||
#define ipmr_for_each_table(mrt, net) \
|
||||
@@ -223,6 +229,80 @@ static int ipmr_rule_fill(struct fib_rul
|
||||
return 0;
|
||||
}
|
||||
|
||||
+/* QCA ECM qca-mcs support - Start */
|
||||
+/* 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();
|
||||
+}
|
||||
+/* QCA ECM qca-mcs support - End */
|
||||
+
|
||||
static const struct fib_rules_ops __net_initconst ipmr_rules_ops_template = {
|
||||
.family = RTNL_FAMILY_IPMR,
|
||||
.rule_size = sizeof(struct ipmr_rule),
|
||||
@@ -236,6 +316,156 @@ static const struct fib_rules_ops __net_
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
+/* QCA ECM qca-mcs support - Start */
|
||||
+/* 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;
|
||||
+ cache->_c.mfc_un.res.pkt += pkts_out;
|
||||
+ cache->_c.mfc_un.res.bytes += bytes_out;
|
||||
+
|
||||
+ 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);
|
||||
+/* QCA ECM qca-mcs support - End */
|
||||
+
|
||||
static int __net_init ipmr_rules_init(struct net *net)
|
||||
{
|
||||
struct fib_rules_ops *ops;
|
||||
@@ -1191,6 +1421,10 @@ 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);
|
||||
+ /* QCA ECM qca-mcs support - Start */
|
||||
+ /* Inform offload modules of the delete event */
|
||||
+ ipmr_sync_entry_delete(c->mfc_origin, c->mfc_mcastgrp);
|
||||
+ /* QCA ECM qca-mcs support - End */
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1221,6 +1455,10 @@ 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);
|
||||
+ /* QCA ECM qca-mcs support - Start */
|
||||
+ /* Inform offload modules of the update event */
|
||||
+ ipmr_sync_entry_update(mrt, c);
|
||||
+ /* QCA ECM qca-mcs support - End */
|
||||
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); /* QCA qca-mcs support */
|
||||
+
|
||||
/* 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,6 +104,13 @@ 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);
|
||||
+/* QCA qca-mcs support - Start */
|
||||
+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;
|
||||
+/* QCA qca-mcs support - End */
|
||||
|
||||
#ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES
|
||||
#define ip6mr_for_each_table(mrt, net) \
|
||||
@@ -375,6 +385,84 @@ static struct mfc6_cache_cmp_arg ip6mr_m
|
||||
.mf6c_mcastgrp = IN6ADDR_ANY_INIT,
|
||||
};
|
||||
|
||||
+/* QCA qca-mcs support - Start */
|
||||
+/* 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();
|
||||
+}
|
||||
+/* QCA qca-mcs support - End */
|
||||
+
|
||||
static struct mr_table_ops ip6mr_mr_table_ops = {
|
||||
.rht_params = &ip6mr_rht_params,
|
||||
.cmparg_any = &ip6mr_mr_table_ops_cmparg_any,
|
||||
@@ -697,6 +785,151 @@ static int call_ip6mr_mfc_entry_notifier
|
||||
&mfc->_c, tb_id, &net->ipv6.ipmr_seq);
|
||||
}
|
||||
|
||||
+/* QCA qca-mcs support - Start */
|
||||
+/* 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;
|
||||
+ cache->_c.mfc_un.res.pkt += pkts_out;
|
||||
+ cache->_c.mfc_un.res.bytes += bytes_out;
|
||||
+
|
||||
+ 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);
|
||||
+/* QCA qca-mcs support - End */
|
||||
+
|
||||
/* Delete a VIF entry */
|
||||
static int mif6_delete(struct mr_table *mrt, int vifi, int notify,
|
||||
struct list_head *head)
|
||||
@@ -1221,6 +1454,7 @@ static int ip6mr_mfc_delete(struct mr_ta
|
||||
int parent)
|
||||
{
|
||||
struct mfc6_cache *c;
|
||||
+ struct in6_addr mc_origin, mc_group; /* QCA qca-mcs support */
|
||||
|
||||
/* The entries are added/deleted only under RTNL */
|
||||
rcu_read_lock();
|
||||
@@ -1229,6 +1463,11 @@ static int ip6mr_mfc_delete(struct mr_ta
|
||||
rcu_read_unlock();
|
||||
if (!c)
|
||||
return -ENOENT;
|
||||
+
|
||||
+ /* QCA qca-mcs support - Start */
|
||||
+ memcpy(&mc_origin, &c->mf6c_origin, sizeof(struct in6_addr));
|
||||
+ memcpy(&mc_group, &c->mf6c_mcastgrp, sizeof(struct in6_addr));
|
||||
+ /* QCA qca-mcs support - End */
|
||||
rhltable_remove(&mrt->mfc_hash, &c->_c.mnode, ip6mr_rht_params);
|
||||
list_del_rcu(&c->_c.list);
|
||||
|
||||
@@ -1236,6 +1475,11 @@ 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);
|
||||
+ /* QCA qca-mcs support - Start */
|
||||
+ /* Inform offload modules of the delete event */
|
||||
+ ip6mr_sync_entry_delete(&mc_origin, &mc_group);
|
||||
+ /* QCA qca-mcs support - End */
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1457,6 +1701,10 @@ 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);
|
||||
+ /* QCA qca-mcs support - Start */
|
||||
+ /* Inform offload modules of the update event */
|
||||
+ ip6mr_sync_entry_update(mrt, c);
|
||||
+ /* QCA qca-mcs support - End */
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
--- a/crypto/authenc.c
|
||||
+++ b/crypto/authenc.c
|
||||
@@ -417,6 +417,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
|
||||
@@ -101,6 +101,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
|
||||
@@ -658,6 +658,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;
|
||||
|
||||
@@ -669,6 +670,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);
|
||||
@@ -890,6 +896,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;
|
||||
@@ -897,6 +904,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
|
||||
@@ -696,6 +696,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;
|
||||
|
||||
@@ -707,6 +708,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);
|
||||
@@ -934,6 +940,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;
|
||||
@@ -945,6 +952,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;
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
From eee3a7956b943dd3e23a74fbb5bfe89405eb0782 Mon Sep 17 00:00:00 2001
|
||||
From: Andrea Righi <andrea.righi@canonical.com>
|
||||
Date: Mon, 6 Dec 2021 17:34:47 +0100
|
||||
Subject: UBUNTU: SAUCE: ipv6: fix NULL pointer dereference in ip6_output()
|
||||
|
||||
It is possible to trigger a NULL pointer dereference by running the srv6
|
||||
net kselftest (tools/testing/selftests/net/srv6_end_dt46_l3vpn_test.sh):
|
||||
|
||||
[ 249.051216] BUG: kernel NULL pointer dereference, address: 0000000000000378
|
||||
[ 249.052331] #PF: supervisor read access in kernel mode
|
||||
[ 249.053137] #PF: error_code(0x0000) - not-present page
|
||||
[ 249.053960] PGD 0 P4D 0
|
||||
[ 249.054376] Oops: 0000 [#1] PREEMPT SMP NOPTI
|
||||
[ 249.055083] CPU: 1 PID: 21 Comm: ksoftirqd/1 Tainted: G E 5.16.0-rc4 #2
|
||||
[ 249.056328] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.14.0-2 04/01/2014
|
||||
[ 249.057632] RIP: 0010:ip6_forward+0x53c/0xab0
|
||||
[ 249.058354] Code: 49 c7 44 24 20 00 00 00 00 48 83 e0 fe 48 8b 40 30 48 3d 70 b2 b5 81 0f 85 b5 04 00 00 e8 7c f2 ff ff 41 89 c5 e9 17 01 00 00 <44> 8b 93 78 03 00 00 45 85 d2 0f 85 92 fb ff ff 49 8b 54 24 10 48
|
||||
[ 249.061274] RSP: 0018:ffffc900000cbb30 EFLAGS: 00010246
|
||||
[ 249.062042] RAX: 0000000000000000 RBX: 0000000000000000 RCX: ffff8881051d3400
|
||||
[ 249.063141] RDX: ffff888104bda000 RSI: 00000000000002c0 RDI: 0000000000000000
|
||||
[ 249.064264] RBP: ffffc900000cbbc8 R08: 0000000000000000 R09: 0000000000000000
|
||||
[ 249.065376] R10: 0000000000000040 R11: 0000000000000000 R12: ffff888103409800
|
||||
[ 249.066498] R13: ffff8881051d3410 R14: ffff888102725280 R15: ffff888103525000
|
||||
[ 249.067619] FS: 0000000000000000(0000) GS:ffff88813bc80000(0000) knlGS:0000000000000000
|
||||
[ 249.068881] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
|
||||
[ 249.069777] CR2: 0000000000000378 CR3: 0000000104980000 CR4: 0000000000750ee0
|
||||
[ 249.070907] PKRU: 55555554
|
||||
[ 249.071337] Call Trace:
|
||||
[ 249.071730] <TASK>
|
||||
[ 249.072070] ? debug_smp_processor_id+0x17/0x20
|
||||
[ 249.072807] seg6_input_core+0x2bb/0x2d0
|
||||
[ 249.073436] ? _raw_spin_unlock_irqrestore+0x29/0x40
|
||||
[ 249.074225] seg6_input+0x3b/0x130
|
||||
[ 249.074768] lwtunnel_input+0x5e/0xa0
|
||||
[ 249.075357] ip_rcv+0x17b/0x190
|
||||
[ 249.075867] ? update_load_avg+0x82/0x600
|
||||
[ 249.076514] __netif_receive_skb_one_core+0x86/0xa0
|
||||
[ 249.077231] __netif_receive_skb+0x15/0x60
|
||||
[ 249.077843] process_backlog+0x97/0x160
|
||||
[ 249.078389] __napi_poll+0x31/0x170
|
||||
[ 249.078912] net_rx_action+0x229/0x270
|
||||
[ 249.079506] __do_softirq+0xef/0x2ed
|
||||
[ 249.080085] run_ksoftirqd+0x37/0x50
|
||||
[ 249.080663] smpboot_thread_fn+0x193/0x230
|
||||
[ 249.081312] kthread+0x17a/0x1a0
|
||||
[ 249.081847] ? smpboot_register_percpu_thread+0xe0/0xe0
|
||||
[ 249.082677] ? set_kthread_struct+0x50/0x50
|
||||
[ 249.083340] ret_from_fork+0x22/0x30
|
||||
[ 249.083926] </TASK>
|
||||
[ 249.090295] ---[ end trace 1998d7ba5965a365 ]---
|
||||
|
||||
It looks like commit 0857d6f8c759 ("ipv6: When forwarding count rx stats
|
||||
on the orig netdev") tries to determine the right netdev to account the
|
||||
rx stats, but in this particular case it's failing and the netdev is
|
||||
NULL.
|
||||
|
||||
Fallback to the previous method of determining the netdev interface (via
|
||||
skb->dev) to account the rx stats when the orig netdev can't be
|
||||
determined.
|
||||
|
||||
Fixes: 0857d6f8c759 ("ipv6: When forwarding count rx stats on the orig netdev")
|
||||
Signed-off-by: Andrea Righi <andrea.righi@canonical.com>
|
||||
(cherry picked from https://lore.kernel.org/lkml/20211206163447.991402-1-andrea.righi@canonical.com/T/#u)
|
||||
Signed-off-by: Andrea Righi <andrea.righi@canonical.com>
|
||||
---
|
||||
net/ipv6/ip6_output.c | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
--- a/net/ipv6/ip6_output.c
|
||||
+++ b/net/ipv6/ip6_output.c
|
||||
@@ -492,6 +492,9 @@ int ip6_forward(struct sk_buff *skb)
|
||||
u32 mtu;
|
||||
|
||||
idev = __in6_dev_get_safely(dev_get_by_index_rcu(net, IP6CB(skb)->iif));
|
||||
+ if (unlikely(!idev))
|
||||
+ idev = __in6_dev_get_safely(skb->dev);
|
||||
+
|
||||
if (net->ipv6.devconf_all->forwarding == 0)
|
||||
goto error;
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
diff -uprN a/arch/arm64/boot/dts/qcom/ipq8074.dtsi b/arch/arm64/boot/dts/qcom/ipq8074.dtsi
|
||||
--- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi 2023-06-22 18:11:32.910676000 -0700
|
||||
+++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi 2023-07-26 21:43:58.269612521 -0700
|
||||
@@ -750,6 +750,21 @@
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
+ blsp1_i2c4: i2c@78b8000 {
|
||||
+ compatible = "qcom,i2c-qup-v2.2.1";
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <0>;
|
||||
+ reg = <0x078b8000 0x600>;
|
||||
+ interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
|
||||
+ clocks = <&gcc GCC_BLSP1_QUP4_I2C_APPS_CLK>,
|
||||
+ <&gcc GCC_BLSP1_AHB_CLK>;
|
||||
+ clock-names = "core", "iface";
|
||||
+ clock-frequency = <100000>;
|
||||
+ dmas = <&blsp_dma 18>, <&blsp_dma 19>;
|
||||
+ dma-names = "tx", "rx";
|
||||
+ status = "disabled";
|
||||
+ };
|
||||
+
|
||||
blsp1_i2c5: i2c@78b9000 {
|
||||
compatible = "qcom,i2c-qup-v2.2.1";
|
||||
#address-cells = <1>;
|
|
@ -0,0 +1,412 @@
|
|||
--- a/include/linux/cpuhotplug.h
|
||||
+++ b/include/linux/cpuhotplug.h
|
||||
@@ -94,6 +94,7 @@ enum cpuhp_state {
|
||||
CPUHP_RADIX_DEAD,
|
||||
CPUHP_PAGE_ALLOC,
|
||||
CPUHP_NET_DEV_DEAD,
|
||||
+ CPUHP_SKB_RECYCLER_DEAD,
|
||||
CPUHP_PCI_XGENE_DEAD,
|
||||
CPUHP_IOMMU_IOVA_DEAD,
|
||||
CPUHP_LUSTRE_CFS_DEAD,
|
||||
--- a/include/linux/skbuff.h
|
||||
+++ b/include/linux/skbuff.h
|
||||
@@ -1240,7 +1240,7 @@ static inline void kfree_skb_list(struct sk_buff *segs)
|
||||
kfree_skb_list_reason(segs, SKB_DROP_REASON_NOT_SPECIFIED);
|
||||
}
|
||||
|
||||
-#ifdef CONFIG_TRACEPOINTS
|
||||
+#ifdef CONFIG_SKB_RECYCLER
|
||||
void consume_skb(struct sk_buff *skb);
|
||||
#else
|
||||
static inline void consume_skb(struct sk_buff *skb)
|
||||
@@ -1252,6 +1252,8 @@ static inline void consume_skb(struct sk_buff *skb)
|
||||
void __consume_stateless_skb(struct sk_buff *skb);
|
||||
void __kfree_skb(struct sk_buff *skb);
|
||||
extern struct kmem_cache *skbuff_head_cache;
|
||||
+extern void kfree_skbmem(struct sk_buff *skb);
|
||||
+extern void skb_release_data(struct sk_buff *skb);
|
||||
|
||||
void kfree_skb_partial(struct sk_buff *skb, bool head_stolen);
|
||||
bool skb_try_coalesce(struct sk_buff *to, struct sk_buff *from,
|
||||
--- a/net/Kconfig
|
||||
+++ b/net/Kconfig
|
||||
@@ -332,6 +332,27 @@ config NET_FLOW_LIMIT
|
||||
with many clients some protection against DoS by a single (spoofed)
|
||||
flow that greatly exceeds average workload.
|
||||
|
||||
+config SKB_RECYCLER
|
||||
+ bool "Generic skb recycling"
|
||||
+ default y
|
||||
+ help
|
||||
+ SKB_RECYCLER is used to implement RX-to-RX skb recycling.
|
||||
+ This config enables the recycling scheme for bridging and
|
||||
+ routing workloads. It can reduce skbuff freeing or
|
||||
+ reallocation overhead.
|
||||
+
|
||||
+config SKB_RECYCLER_MULTI_CPU
|
||||
+ bool "Cross-CPU recycling for CPU-locked workloads"
|
||||
+ depends on SMP && SKB_RECYCLER
|
||||
+ default n
|
||||
+
|
||||
+config ALLOC_SKB_PAGE_FRAG_DISABLE
|
||||
+ bool "Disable page fragment based skbuff payload allocations"
|
||||
+ depends on !SKB_RECYCLER
|
||||
+ default n
|
||||
+ help
|
||||
+ Disable page fragment based allocations for skbuff payloads.
|
||||
+
|
||||
menu "Network testing"
|
||||
|
||||
config NET_PKTGEN
|
||||
--- a/net/core/Makefile
|
||||
+++ b/net/core/Makefile
|
||||
@@ -40,3 +40,4 @@ obj-$(CONFIG_NET_SOCK_MSG) += skmsg.o
|
||||
obj-$(CONFIG_BPF_SYSCALL) += sock_map.o
|
||||
obj-$(CONFIG_BPF_SYSCALL) += bpf_sk_storage.o
|
||||
obj-$(CONFIG_OF) += of_net.o
|
||||
+obj-$(CONFIG_SKB_RECYCLER) += skbuff_recycle.o
|
||||
--- a/net/core/dev.c
|
||||
+++ b/net/core/dev.c
|
||||
@@ -5974,10 +5974,16 @@ static int process_backlog(struct napi_struct *napi, int quota)
|
||||
|
||||
napi->weight = READ_ONCE(dev_rx_weight);
|
||||
while (again) {
|
||||
- struct sk_buff *skb;
|
||||
+ struct sk_buff *skb, *next_skb;
|
||||
|
||||
while ((skb = __skb_dequeue(&sd->process_queue))) {
|
||||
rcu_read_lock();
|
||||
+
|
||||
+ next_skb = skb_peek(&sd->process_queue);
|
||||
+ if (likely(next_skb)) {
|
||||
+ prefetch(next_skb->data);
|
||||
+ }
|
||||
+
|
||||
__netif_receive_skb(skb);
|
||||
rcu_read_unlock();
|
||||
input_queue_head_incr(sd);
|
||||
--- a/net/core/skbuff.c
|
||||
+++ b/net/core/skbuff.c
|
||||
@@ -84,6 +84,33 @@
|
||||
#include "dev.h"
|
||||
#include "sock_destructor.h"
|
||||
|
||||
+struct kmem_cache *skb_data_cache;
|
||||
+
|
||||
+/*
|
||||
+ * For low memory profile, NSS_SKB_FIXED_SIZE_2K is enabled and
|
||||
+ * CONFIG_SKB_RECYCLER is disabled. For premium and enterprise profile
|
||||
+ * CONFIG_SKB_RECYCLER is enabled and NSS_SKB_FIXED_SIZE_2K is disabled.
|
||||
+ * Irrespective of NSS_SKB_FIXED_SIZE_2K enabled/disabled, the
|
||||
+ * CONFIG_SKB_RECYCLER and __LP64__ determines the value of SKB_DATA_CACHE_SIZE
|
||||
+ */
|
||||
+#if defined(CONFIG_SKB_RECYCLER)
|
||||
+/*
|
||||
+ * 2688 for 64bit arch, 2624 for 32bit arch
|
||||
+ */
|
||||
+#define SKB_DATA_CACHE_SIZE (SKB_DATA_ALIGN(SKB_RECYCLE_SIZE + NET_SKB_PAD) + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
|
||||
+#else
|
||||
+/*
|
||||
+ * 2368 for 64bit arch, 2176 for 32bit arch
|
||||
+ */
|
||||
+#if defined(__LP64__)
|
||||
+#define SKB_DATA_CACHE_SIZE ((SKB_DATA_ALIGN(1984 + NET_SKB_PAD)) + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
|
||||
+#else
|
||||
+#define SKB_DATA_CACHE_SIZE ((SKB_DATA_ALIGN(1856 + NET_SKB_PAD)) + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
|
||||
+#endif
|
||||
+#endif
|
||||
+
|
||||
+#include "skbuff_recycle.h"
|
||||
+
|
||||
struct kmem_cache *skbuff_head_cache __ro_after_init;
|
||||
static struct kmem_cache *skbuff_fclone_cache __ro_after_init;
|
||||
#ifdef CONFIG_SKB_EXTENSIONS
|
||||
@@ -426,32 +453,46 @@ EXPORT_SYMBOL(napi_build_skb);
|
||||
* memory is free
|
||||
*/
|
||||
static void *kmalloc_reserve(unsigned int *size, gfp_t flags, int node,
|
||||
- bool *pfmemalloc)
|
||||
-{
|
||||
- bool ret_pfmemalloc = false;
|
||||
- size_t obj_size;
|
||||
- void *obj;
|
||||
+ bool *pfmemalloc)
|
||||
+ {
|
||||
+ void *obj;
|
||||
+ bool ret_pfmemalloc = false;
|
||||
+ unsigned int obj_size = *size;
|
||||
+
|
||||
+ if (obj_size > SZ_2K && obj_size <= SKB_DATA_CACHE_SIZE) {
|
||||
+ obj = kmem_cache_alloc_node(skb_data_cache,
|
||||
+ flags | __GFP_NOMEMALLOC | __GFP_NOWARN,
|
||||
+ node);
|
||||
+ *size = SKB_DATA_CACHE_SIZE;
|
||||
+ if (obj || !(gfp_pfmemalloc_allowed(flags)))
|
||||
+ goto out;
|
||||
|
||||
- obj_size = SKB_HEAD_ALIGN(*size);
|
||||
+ /* Try again but now we are using pfmemalloc reserves */
|
||||
+ ret_pfmemalloc = true;
|
||||
+ obj = kmem_cache_alloc_node(skb_data_cache, flags, node);
|
||||
+ goto out;
|
||||
+ }
|
||||
|
||||
obj_size = kmalloc_size_roundup(obj_size);
|
||||
- /* The following cast might truncate high-order bits of obj_size, this
|
||||
+
|
||||
+ /*
|
||||
+ * The following cast might truncate high-order bits of obj_size, this
|
||||
* is harmless because kmalloc(obj_size >= 2^32) will fail anyway.
|
||||
*/
|
||||
*size = (unsigned int)obj_size;
|
||||
|
||||
- /*
|
||||
- * Try a regular allocation, when that fails and we're not entitled
|
||||
- * to the reserves, fail.
|
||||
- */
|
||||
+ /*
|
||||
+ * Try a regular allocation, when that fails and we're not entitled
|
||||
+ * to the reserves, fail.
|
||||
+ */
|
||||
obj = kmalloc_node_track_caller(obj_size,
|
||||
- flags | __GFP_NOMEMALLOC | __GFP_NOWARN,
|
||||
- node);
|
||||
- if (obj || !(gfp_pfmemalloc_allowed(flags)))
|
||||
- goto out;
|
||||
+ flags | __GFP_NOMEMALLOC | __GFP_NOWARN,
|
||||
+ node);
|
||||
+ if (obj || !(gfp_pfmemalloc_allowed(flags)))
|
||||
+ goto out;
|
||||
|
||||
- /* Try again but now we are using pfmemalloc reserves */
|
||||
- ret_pfmemalloc = true;
|
||||
+ /* Try again but now we are using pfmemalloc reserves */
|
||||
+ ret_pfmemalloc = true;
|
||||
obj = kmalloc_node_track_caller(obj_size, flags, node);
|
||||
|
||||
out:
|
||||
@@ -513,10 +554,12 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,
|
||||
* aligned memory blocks, unless SLUB/SLAB debug is enabled.
|
||||
* Both skb->head and skb_shared_info are cache line aligned.
|
||||
*/
|
||||
+ size = SKB_DATA_ALIGN(size);
|
||||
+ size += SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
|
||||
data = kmalloc_reserve(&size, gfp_mask, node, &pfmemalloc);
|
||||
if (unlikely(!data))
|
||||
goto nodata;
|
||||
- /* kmalloc_size_roundup() might give us more room than requested.
|
||||
+ /* kmalloc_reserve(size) might give us more room than requested.
|
||||
* Put skb_shared_info exactly at the end of allocated zone,
|
||||
* to allow max possible filling before reallocation.
|
||||
*/
|
||||
@@ -551,7 +594,7 @@ EXPORT_SYMBOL(__alloc_skb);
|
||||
/**
|
||||
* __netdev_alloc_skb - allocate an skbuff for rx on a specific device
|
||||
* @dev: network device to receive on
|
||||
- * @len: length to allocate
|
||||
+ * @length: length to allocate
|
||||
* @gfp_mask: get_free_pages mask, passed to alloc_skb
|
||||
*
|
||||
* Allocate a new &sk_buff and assign it a usage count of one. The
|
||||
@@ -561,29 +604,53 @@ EXPORT_SYMBOL(__alloc_skb);
|
||||
*
|
||||
* %NULL is returned if there is no free memory.
|
||||
*/
|
||||
-struct sk_buff *__netdev_alloc_skb(struct net_device *dev, unsigned int len,
|
||||
- gfp_t gfp_mask)
|
||||
+struct sk_buff *__netdev_alloc_skb(struct net_device *dev,
|
||||
+ unsigned int length, gfp_t gfp_mask)
|
||||
{
|
||||
- struct page_frag_cache *nc;
|
||||
struct sk_buff *skb;
|
||||
+ unsigned int len = length;
|
||||
+
|
||||
+#ifdef CONFIG_SKB_RECYCLER
|
||||
+ skb = skb_recycler_alloc(dev, length);
|
||||
+ if (likely(skb))
|
||||
+ return skb;
|
||||
+
|
||||
+ len = SKB_RECYCLE_SIZE;
|
||||
+ if (unlikely(length > SKB_RECYCLE_SIZE))
|
||||
+ len = length;
|
||||
+
|
||||
+ skb = __alloc_skb(len + NET_SKB_PAD, gfp_mask,
|
||||
+ SKB_ALLOC_RX, NUMA_NO_NODE);
|
||||
+ if (!skb)
|
||||
+ goto skb_fail;
|
||||
+ goto skb_success;
|
||||
+#else
|
||||
+ struct page_frag_cache *nc;
|
||||
bool pfmemalloc;
|
||||
+ bool page_frag_alloc_enable = true;
|
||||
void *data;
|
||||
|
||||
len += NET_SKB_PAD;
|
||||
|
||||
+
|
||||
+#ifdef CONFIG_ALLOC_SKB_PAGE_FRAG_DISABLE
|
||||
+ page_frag_alloc_enable = false;
|
||||
+#endif
|
||||
/* If requested length is either too small or too big,
|
||||
* we use kmalloc() for skb->head allocation.
|
||||
*/
|
||||
if (len <= SKB_WITH_OVERHEAD(1024) ||
|
||||
len > SKB_WITH_OVERHEAD(PAGE_SIZE) ||
|
||||
- (gfp_mask & (__GFP_DIRECT_RECLAIM | GFP_DMA))) {
|
||||
+ (gfp_mask & (__GFP_DIRECT_RECLAIM | GFP_DMA)) ||
|
||||
+ !page_frag_alloc_enable) {
|
||||
skb = __alloc_skb(len, gfp_mask, SKB_ALLOC_RX, NUMA_NO_NODE);
|
||||
if (!skb)
|
||||
goto skb_fail;
|
||||
goto skb_success;
|
||||
}
|
||||
|
||||
- len = SKB_HEAD_ALIGN(len);
|
||||
+ len += SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
|
||||
+ len = SKB_DATA_ALIGN(len);
|
||||
|
||||
if (sk_memalloc_socks())
|
||||
gfp_mask |= __GFP_MEMALLOC;
|
||||
@@ -612,6 +679,7 @@ struct sk_buff *__netdev_alloc_skb(struct net_device *dev, unsigned int len,
|
||||
if (pfmemalloc)
|
||||
skb->pfmemalloc = 1;
|
||||
skb->head_frag = 1;
|
||||
+#endif
|
||||
|
||||
skb_success:
|
||||
skb_reserve(skb, NET_SKB_PAD);
|
||||
@@ -682,7 +750,8 @@ struct sk_buff *__napi_alloc_skb(struct napi_struct *napi, unsigned int len,
|
||||
data = page_frag_alloc_1k(&nc->page_small, gfp_mask);
|
||||
pfmemalloc = NAPI_SMALL_PAGE_PFMEMALLOC(nc->page_small);
|
||||
} else {
|
||||
- len = SKB_HEAD_ALIGN(len);
|
||||
+ len += SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
|
||||
+ len = SKB_DATA_ALIGN(len);
|
||||
|
||||
data = page_frag_alloc(&nc->page, len, gfp_mask);
|
||||
pfmemalloc = nc->page.pfmemalloc;
|
||||
@@ -780,7 +849,7 @@ static void skb_free_head(struct sk_buff *skb)
|
||||
}
|
||||
}
|
||||
|
||||
-static void skb_release_data(struct sk_buff *skb)
|
||||
+void skb_release_data(struct sk_buff *skb)
|
||||
{
|
||||
struct skb_shared_info *shinfo = skb_shinfo(skb);
|
||||
int i;
|
||||
@@ -822,7 +891,7 @@ static void skb_release_data(struct sk_buff *skb)
|
||||
/*
|
||||
* Free an skbuff by memory without cleaning the state.
|
||||
*/
|
||||
-static void kfree_skbmem(struct sk_buff *skb)
|
||||
+void kfree_skbmem(struct sk_buff *skb)
|
||||
{
|
||||
struct sk_buff_fclones *fclones;
|
||||
|
||||
@@ -1034,7 +1103,6 @@ void skb_tx_error(struct sk_buff *skb)
|
||||
}
|
||||
EXPORT_SYMBOL(skb_tx_error);
|
||||
|
||||
-#ifdef CONFIG_TRACEPOINTS
|
||||
/**
|
||||
* consume_skb - free an skbuff
|
||||
* @skb: buffer to free
|
||||
@@ -1043,13 +1111,50 @@ EXPORT_SYMBOL(skb_tx_error);
|
||||
* Functions identically to kfree_skb, but kfree_skb assumes that the frame
|
||||
* is being dropped after a failure and notes that
|
||||
*/
|
||||
+#ifdef CONFIG_SKB_RECYCLER
|
||||
void consume_skb(struct sk_buff *skb)
|
||||
{
|
||||
if (!skb_unref(skb))
|
||||
return;
|
||||
|
||||
+ prefetch(&skb->destructor);
|
||||
+
|
||||
+ /*Tian: Not sure if we need to continue using this since
|
||||
+ * since unref does the work in 5.4
|
||||
+ */
|
||||
+
|
||||
+ /*
|
||||
+ if (likely(atomic_read(&skb->users) == 1))
|
||||
+ smp_rmb();
|
||||
+ else if (likely(!atomic_dec_and_test(&skb->users)))
|
||||
+ return;
|
||||
+ */
|
||||
+
|
||||
+ /* If possible we'd like to recycle any skb rather than just free it,
|
||||
+ * but in order to do that we need to release any head state too.
|
||||
+ * We don't want to do this later because we'll be in a pre-emption
|
||||
+ * disabled state.
|
||||
+ */
|
||||
+ skb_release_head_state(skb);
|
||||
+
|
||||
+ /* Can we recycle this skb? If we can then it will be much faster
|
||||
+ * for us to recycle this one later than to allocate a new one
|
||||
+ * from scratch.
|
||||
+ */
|
||||
+ if (likely(skb->head) && likely(skb_recycler_consume(skb)))
|
||||
+ return;
|
||||
+
|
||||
+#ifdef CONFIG_TRACEPOINTS
|
||||
trace_consume_skb(skb);
|
||||
- __kfree_skb(skb);
|
||||
+#endif
|
||||
+ /* We're not recycling so now we need to do the rest of what we would
|
||||
+ * have done in __kfree_skb (above and beyond the skb_release_head_state
|
||||
+ * that we already did).
|
||||
+ */
|
||||
+ if (likely(skb->head))
|
||||
+ skb_release_data(skb);
|
||||
+
|
||||
+ kfree_skbmem(skb);
|
||||
}
|
||||
EXPORT_SYMBOL(consume_skb);
|
||||
#endif
|
||||
@@ -1856,6 +1961,8 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
|
||||
if (skb_pfmemalloc(skb))
|
||||
gfp_mask |= __GFP_MEMALLOC;
|
||||
|
||||
+ size = SKB_DATA_ALIGN(size);
|
||||
+ size += SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
|
||||
data = kmalloc_reserve(&size, gfp_mask, NUMA_NO_NODE, NULL);
|
||||
if (!data)
|
||||
goto nodata;
|
||||
@@ -4557,6 +4664,11 @@ static void skb_extensions_init(void) {}
|
||||
|
||||
void __init skb_init(void)
|
||||
{
|
||||
+ skb_data_cache = kmem_cache_create_usercopy("skb_data_cache",
|
||||
+ SKB_DATA_CACHE_SIZE,
|
||||
+ 0, SLAB_PANIC, 0, SKB_DATA_CACHE_SIZE,
|
||||
+ NULL);
|
||||
+
|
||||
skbuff_head_cache = kmem_cache_create_usercopy("skbuff_head_cache",
|
||||
sizeof(struct sk_buff),
|
||||
0,
|
||||
@@ -4570,6 +4682,7 @@ void __init skb_init(void)
|
||||
SLAB_HWCACHE_ALIGN|SLAB_PANIC,
|
||||
NULL);
|
||||
skb_extensions_init();
|
||||
+ skb_recycler_init();
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -6224,6 +6337,8 @@ static int pskb_carve_inside_header(struct sk_buff *skb, const u32 off,
|
||||
if (skb_pfmemalloc(skb))
|
||||
gfp_mask |= __GFP_MEMALLOC;
|
||||
|
||||
+ size = SKB_DATA_ALIGN(size);
|
||||
+ size += SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
|
||||
data = kmalloc_reserve(&size, gfp_mask, NUMA_NO_NODE, NULL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
@@ -6340,6 +6455,8 @@ static int pskb_carve_inside_nonlinear(struct sk_buff *skb, const u32 off,
|
||||
if (skb_pfmemalloc(skb))
|
||||
gfp_mask |= __GFP_MEMALLOC;
|
||||
|
||||
+ size = SKB_DATA_ALIGN(size);
|
||||
+ size += SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
|
||||
data = kmalloc_reserve(&size, gfp_mask, NUMA_NO_NODE, NULL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
|
@ -0,0 +1,10 @@
|
|||
--- a/crypto/algapi.c
|
||||
+++ b/crypto/algapi.c
|
||||
@@ -290,7 +290,6 @@ static struct crypto_larval *__crypto_re
|
||||
}
|
||||
|
||||
if (!strcmp(q->cra_driver_name, alg->cra_name) ||
|
||||
- !strcmp(q->cra_driver_name, alg->cra_driver_name) ||
|
||||
!strcmp(q->cra_name, alg->cra_driver_name))
|
||||
goto err;
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
--- a/drivers/mtd/mtdblock.c
|
||||
+++ b/drivers/mtd/mtdblock.c
|
||||
@@ -261,10 +261,6 @@ static int mtdblock_open(struct mtd_blkt
|
||||
return 0;
|
||||
}
|
||||
|
||||
- if (mtd_type_is_nand(mbd->mtd))
|
||||
- pr_warn("%s: MTD device '%s' is NAND, please consider using UBI block devices instead.\n",
|
||||
- mbd->tr->name, mbd->mtd->name);
|
||||
-
|
||||
/* OK, it's not open. Create cache info for it */
|
||||
mtdblk->count = 1;
|
||||
mutex_init(&mtdblk->cache_mutex);
|
|
@ -0,0 +1,311 @@
|
|||
From 6504bc9edeb1a2a54d813f4bb5d0267e7bf827f9 Mon Sep 17 00:00:00 2001
|
||||
From: Praveenkumar I <ipkumar@codeaurora.org>
|
||||
Date: Thu, 6 Feb 2020 17:35:42 +0530
|
||||
Subject: [PATCH 4/8] clk: ipq8074: Support added for necessary clocks and
|
||||
reset
|
||||
|
||||
Change-Id: I21a76a44185f766e9b6dcba274392ea8e599718b
|
||||
Signed-off-by: Praveenkumar I <ipkumar@codeaurora.org>
|
||||
Signed-off-by: Rajkumar Ayyasamy <arajkuma@codeaurora.org>
|
||||
---
|
||||
drivers/clk/qcom/gcc-ipq8074.c | 238 ++++++++++++++++++-
|
||||
include/dt-bindings/clock/qcom,gcc-ipq8074.h | 35 ++-
|
||||
2 files changed, 258 insertions(+), 15 deletions(-)
|
||||
|
||||
--- a/drivers/clk/qcom/gcc-ipq8074.c
|
||||
+++ b/drivers/clk/qcom/gcc-ipq8074.c
|
||||
@@ -48,6 +48,22 @@ enum {
|
||||
P_UNIPHY2_TX,
|
||||
};
|
||||
|
||||
+static const char * const gcc_xo_gpll4_gpll0_gpll6_gpll0_div2[] = {
|
||||
+ "xo",
|
||||
+ "gpll4",
|
||||
+ "gpll0",
|
||||
+ "gpll6",
|
||||
+ "gpll0_out_main_div2",
|
||||
+};
|
||||
+
|
||||
+static const struct parent_map gcc_xo_gpll4_gpll0_gpll6_gpll0_div2_map[] = {
|
||||
+ { P_XO, 0 },
|
||||
+ { P_GPLL4, 1 },
|
||||
+ { P_GPLL0, 2 },
|
||||
+ { P_GPLL6, 3 },
|
||||
+ { P_GPLL0_DIV2, 4 },
|
||||
+};
|
||||
+
|
||||
static struct clk_alpha_pll gpll0_main = {
|
||||
.offset = 0x21000,
|
||||
.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
|
||||
@@ -629,6 +645,12 @@ static const struct freq_tbl ftbl_pcie_a
|
||||
{ }
|
||||
};
|
||||
|
||||
+struct freq_tbl ftbl_pcie_rchng_clk_src[] = {
|
||||
+ F(19200000, P_XO, 1, 0, 0),
|
||||
+ F(100000000, P_GPLL0, 8, 0, 0),
|
||||
+ { }
|
||||
+};
|
||||
+
|
||||
static struct clk_rcg2 pcie0_axi_clk_src = {
|
||||
.cmd_rcgr = 0x75054,
|
||||
.freq_tbl = ftbl_pcie_axi_clk_src,
|
||||
@@ -2029,6 +2051,78 @@ static struct clk_rcg2 gp3_clk_src = {
|
||||
},
|
||||
};
|
||||
|
||||
+struct freq_tbl ftbl_qdss_tsctr_clk_src[] = {
|
||||
+ F(160000000, P_GPLL0_DIV2, 2.5, 0, 0),
|
||||
+ F(320000000, P_GPLL0, 2.5, 0, 0),
|
||||
+ F(600000000, P_GPLL6, 2, 0, 0),
|
||||
+ { }
|
||||
+};
|
||||
+
|
||||
+struct clk_rcg2 qdss_tsctr_clk_src = {
|
||||
+ .cmd_rcgr = 0x29064,
|
||||
+ .freq_tbl = ftbl_qdss_tsctr_clk_src,
|
||||
+ .hid_width = 5,
|
||||
+ .parent_map = gcc_xo_gpll4_gpll0_gpll6_gpll0_div2_map,
|
||||
+ .clkr.hw.init = &(struct clk_init_data){
|
||||
+ .name = "qdss_tsctr_clk_src",
|
||||
+ .parent_names = gcc_xo_gpll4_gpll0_gpll6_gpll0_div2,
|
||||
+ .num_parents = 5,
|
||||
+ .ops = &clk_rcg2_ops,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+static struct clk_fixed_factor qdss_dap_sync_clk_src = {
|
||||
+ .mult = 1,
|
||||
+ .div = 4,
|
||||
+ .hw.init = &(struct clk_init_data){
|
||||
+ .name = "qdss_dap_sync_clk_src",
|
||||
+ .parent_names = (const char *[]){
|
||||
+ "qdss_tsctr_clk_src"
|
||||
+ },
|
||||
+ .num_parents = 1,
|
||||
+ .ops = &clk_fixed_factor_ops,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+struct freq_tbl ftbl_qdss_at_clk_src[] = {
|
||||
+ F(66670000, P_GPLL0_DIV2, 6, 0, 0),
|
||||
+ F(240000000, P_GPLL6, 6, 0, 0),
|
||||
+ { }
|
||||
+};
|
||||
+
|
||||
+struct clk_rcg2 qdss_at_clk_src = {
|
||||
+ .cmd_rcgr = 0x2900c,
|
||||
+ .freq_tbl = ftbl_qdss_at_clk_src,
|
||||
+ .hid_width = 5,
|
||||
+ .parent_map = gcc_xo_gpll4_gpll0_gpll6_gpll0_div2_map,
|
||||
+ .clkr.hw.init = &(struct clk_init_data){
|
||||
+ .name = "qdss_at_clk_src",
|
||||
+ .parent_names = gcc_xo_gpll4_gpll0_gpll6_gpll0_div2,
|
||||
+ .num_parents = 5,
|
||||
+ .ops = &clk_rcg2_ops,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+
|
||||
+struct freq_tbl ftbl_adss_pwm_clk_src[] = {
|
||||
+ F(19200000, P_XO, 1, 0, 0),
|
||||
+ F(200000000, P_GPLL0, 4, 0, 0),
|
||||
+ { }
|
||||
+};
|
||||
+
|
||||
+struct clk_rcg2 adss_pwm_clk_src = {
|
||||
+ .cmd_rcgr = 0x1c008,
|
||||
+ .freq_tbl = ftbl_adss_pwm_clk_src,
|
||||
+ .hid_width = 5,
|
||||
+ .parent_map = gcc_xo_gpll0_map,
|
||||
+ .clkr.hw.init = &(struct clk_init_data){
|
||||
+ .name = "adss_pwm_clk_src",
|
||||
+ .parent_data = gcc_xo_gpll0,
|
||||
+ .num_parents = 2,
|
||||
+ .ops = &clk_rcg2_ops,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
static struct clk_branch gcc_blsp1_ahb_clk = {
|
||||
.halt_reg = 0x01008,
|
||||
.clkr = {
|
||||
@@ -4224,13 +4318,7 @@ static struct clk_branch gcc_gp3_clk = {
|
||||
},
|
||||
};
|
||||
|
||||
-static const struct freq_tbl ftbl_pcie_rchng_clk_src[] = {
|
||||
- F(19200000, P_XO, 1, 0, 0),
|
||||
- F(100000000, P_GPLL0, 8, 0, 0),
|
||||
- { }
|
||||
-};
|
||||
-
|
||||
-static struct clk_rcg2 pcie0_rchng_clk_src = {
|
||||
+struct clk_rcg2 pcie0_rchng_clk_src = {
|
||||
.cmd_rcgr = 0x75070,
|
||||
.freq_tbl = ftbl_pcie_rchng_clk_src,
|
||||
.hid_width = 5,
|
||||
@@ -4322,6 +4410,114 @@ static const struct alpha_pll_config nss
|
||||
.alpha_en_mask = BIT(24),
|
||||
};
|
||||
|
||||
+static struct clk_branch gcc_snoc_bus_timeout2_ahb_clk = {
|
||||
+ .halt_reg = 0x4700c,
|
||||
+ .halt_bit = 31,
|
||||
+ .clkr = {
|
||||
+ .enable_reg = 0x4700c,
|
||||
+ .enable_mask = BIT(0),
|
||||
+ .hw.init = &(struct clk_init_data){
|
||||
+ .name = "gcc_snoc_bus_timeout2_ahb_clk",
|
||||
+ .parent_names = (const char *[]){
|
||||
+ "usb0_master_clk_src"
|
||||
+ },
|
||||
+ .num_parents = 1,
|
||||
+ .flags = CLK_SET_RATE_PARENT,
|
||||
+ .ops = &clk_branch2_ops,
|
||||
+ },
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+static struct clk_branch gcc_snoc_bus_timeout3_ahb_clk = {
|
||||
+ .halt_reg = 0x47014,
|
||||
+ .halt_bit = 31,
|
||||
+ .clkr = {
|
||||
+ .enable_reg = 0x47014,
|
||||
+ .enable_mask = BIT(0),
|
||||
+ .hw.init = &(struct clk_init_data){
|
||||
+ .name = "gcc_snoc_bus_timeout3_ahb_clk",
|
||||
+ .parent_names = (const char *[]){
|
||||
+ "usb1_master_clk_src"
|
||||
+ },
|
||||
+ .num_parents = 1,
|
||||
+ .flags = CLK_SET_RATE_PARENT,
|
||||
+ .ops = &clk_branch2_ops,
|
||||
+ },
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+static struct clk_branch gcc_dcc_clk = {
|
||||
+ .halt_reg = 0x77004,
|
||||
+ .halt_bit = 31,
|
||||
+ .clkr = {
|
||||
+ .enable_reg = 0x77004,
|
||||
+ .enable_mask = BIT(0),
|
||||
+ .hw.init = &(struct clk_init_data){
|
||||
+ .name = "gcc_dcc_clk",
|
||||
+ .parent_names = (const char *[]){
|
||||
+ "pcnoc_clk_src"
|
||||
+ },
|
||||
+ .num_parents = 1,
|
||||
+ .flags = CLK_SET_RATE_PARENT,
|
||||
+ .ops = &clk_branch2_ops,
|
||||
+ },
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+static struct clk_branch gcc_qdss_at_clk = {
|
||||
+ .halt_reg = 0x29024,
|
||||
+ .halt_bit = 31,
|
||||
+ .clkr = {
|
||||
+ .enable_reg = 0x29024,
|
||||
+ .enable_mask = BIT(0),
|
||||
+ .hw.init = &(struct clk_init_data){
|
||||
+ .name = "gcc_qdss_at_clk",
|
||||
+ .parent_names = (const char *[]){
|
||||
+ "qdss_at_clk_src"
|
||||
+ },
|
||||
+ .num_parents = 1,
|
||||
+ .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
|
||||
+ .ops = &clk_branch2_ops,
|
||||
+ },
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+static struct clk_branch gcc_qdss_dap_clk = {
|
||||
+ .halt_reg = 0x29084,
|
||||
+ .halt_bit = 31,
|
||||
+ .clkr = {
|
||||
+ .enable_reg = 0x29084,
|
||||
+ .enable_mask = BIT(0),
|
||||
+ .hw.init = &(struct clk_init_data){
|
||||
+ .name = "gcc_qdss_dap_clk",
|
||||
+ .parent_names = (const char *[]){
|
||||
+ "qdss_dap_sync_clk_src"
|
||||
+ },
|
||||
+ .num_parents = 1,
|
||||
+ .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
|
||||
+ .ops = &clk_branch2_ops,
|
||||
+ },
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+static struct clk_branch gcc_adss_pwm_clk = {
|
||||
+ .halt_reg = 0x1c020,
|
||||
+ .halt_bit = 31,
|
||||
+ .clkr = {
|
||||
+ .enable_reg = 0x1c020,
|
||||
+ .enable_mask = BIT(0),
|
||||
+ .hw.init = &(struct clk_init_data){
|
||||
+ .name = "gcc_adss_pwm_clk",
|
||||
+ .parent_names = (const char *[]){
|
||||
+ "adss_pwm_clk_src"
|
||||
+ },
|
||||
+ .num_parents = 1,
|
||||
+ .flags = CLK_SET_RATE_PARENT,
|
||||
+ .ops = &clk_branch2_ops,
|
||||
+ },
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
static struct clk_hw *gcc_ipq8074_hws[] = {
|
||||
&gpll0_out_main_div2.hw,
|
||||
&gpll6_out_main_div2.hw,
|
||||
@@ -4330,6 +4526,7 @@ static struct clk_hw *gcc_ipq8074_hws[]
|
||||
&gcc_xo_div4_clk_src.hw,
|
||||
&nss_noc_clk_src.hw,
|
||||
&nss_ppe_cdiv_clk_src.hw,
|
||||
+ &qdss_dap_sync_clk_src.hw,
|
||||
};
|
||||
|
||||
static struct clk_regmap *gcc_ipq8074_clks[] = {
|
||||
@@ -4561,6 +4758,15 @@ static struct clk_regmap *gcc_ipq8074_cl
|
||||
[GCC_PCIE0_RCHNG_CLK] = &gcc_pcie0_rchng_clk.clkr,
|
||||
[GCC_PCIE0_AXI_S_BRIDGE_CLK] = &gcc_pcie0_axi_s_bridge_clk.clkr,
|
||||
[GCC_CRYPTO_PPE_CLK] = &gcc_crypto_ppe_clk.clkr,
|
||||
+ [GCC_SNOC_BUS_TIMEOUT2_AHB_CLK] = &gcc_snoc_bus_timeout2_ahb_clk.clkr,
|
||||
+ [GCC_SNOC_BUS_TIMEOUT3_AHB_CLK] = &gcc_snoc_bus_timeout3_ahb_clk.clkr,
|
||||
+ [GCC_DCC_CLK] = &gcc_dcc_clk.clkr,
|
||||
+ [QDSS_TSCTR_CLK_SRC] = &qdss_tsctr_clk_src.clkr,
|
||||
+ [QDSS_AT_CLK_SRC] = &qdss_at_clk_src.clkr,
|
||||
+ [GCC_QDSS_AT_CLK] = &gcc_qdss_at_clk.clkr,
|
||||
+ [GCC_QDSS_DAP_CLK] = &gcc_qdss_dap_clk.clkr,
|
||||
+ [ADSS_PWM_CLK_SRC] = &adss_pwm_clk_src.clkr,
|
||||
+ [GCC_ADSS_PWM_CLK] = &gcc_adss_pwm_clk.clkr,
|
||||
};
|
||||
|
||||
static const struct qcom_reset_map gcc_ipq8074_resets[] = {
|
||||
--- a/include/dt-bindings/clock/qcom,gcc-ipq8074.h
|
||||
+++ b/include/dt-bindings/clock/qcom,gcc-ipq8074.h
|
||||
@@ -230,10 +230,19 @@
|
||||
#define GCC_GP1_CLK 221
|
||||
#define GCC_GP2_CLK 222
|
||||
#define GCC_GP3_CLK 223
|
||||
-#define GCC_PCIE0_AXI_S_BRIDGE_CLK 224
|
||||
-#define GCC_PCIE0_RCHNG_CLK_SRC 225
|
||||
-#define GCC_PCIE0_RCHNG_CLK 226
|
||||
-#define GCC_CRYPTO_PPE_CLK 227
|
||||
+#define GCC_CRYPTO_PPE_CLK 224
|
||||
+#define GCC_PCIE0_RCHNG_CLK_SRC 225
|
||||
+#define GCC_PCIE0_RCHNG_CLK 226
|
||||
+#define GCC_PCIE0_AXI_S_BRIDGE_CLK 227
|
||||
+#define GCC_SNOC_BUS_TIMEOUT2_AHB_CLK 228
|
||||
+#define GCC_SNOC_BUS_TIMEOUT3_AHB_CLK 229
|
||||
+#define GCC_DCC_CLK 230
|
||||
+#define ADSS_PWM_CLK_SRC 231
|
||||
+#define GCC_ADSS_PWM_CLK 232
|
||||
+#define QDSS_TSCTR_CLK_SRC 233
|
||||
+#define QDSS_AT_CLK_SRC 234
|
||||
+#define GCC_QDSS_AT_CLK 235
|
||||
+#define GCC_QDSS_DAP_CLK 236
|
||||
|
||||
#define GCC_BLSP1_BCR 0
|
||||
#define GCC_BLSP1_QUP1_BCR 1
|
|
@ -0,0 +1,44 @@
|
|||
From 462aa0c53397ec5bf78e3e7f68aa8a3ca300f4ba Mon Sep 17 00:00:00 2001
|
||||
From: Selvam Sathappan Periakaruppan <speriaka@codeaurora.org>
|
||||
Date: Tue, 24 Mar 2020 19:09:38 +0530
|
||||
Subject: [PATCH 5/8] clk: qcom: ipq8074: Fix gcc_snoc_bus_timeout_ahb_clk
|
||||
offset
|
||||
|
||||
By default, the ipq8074 V2 clks are provided in the gcc driver.
|
||||
Updating the gcc_snoc_bus_timeout_ahb_clk offsets also as needed
|
||||
in ipq8074 V2.
|
||||
|
||||
Change-Id: I5a6e98d002f5c3354a804e55dd9ebb1f83f7f974
|
||||
Signed-off-by: Selvam Sathappan Periakaruppan <speriaka@codeaurora.org>
|
||||
---
|
||||
drivers/clk/qcom/gcc-ipq8074.c | 8 ++++----
|
||||
1 file changed, 4 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/drivers/clk/qcom/gcc-ipq8074.c
|
||||
+++ b/drivers/clk/qcom/gcc-ipq8074.c
|
||||
@@ -4411,10 +4411,10 @@ static const struct alpha_pll_config nss
|
||||
};
|
||||
|
||||
static struct clk_branch gcc_snoc_bus_timeout2_ahb_clk = {
|
||||
- .halt_reg = 0x4700c,
|
||||
+ .halt_reg = 0x47014,
|
||||
.halt_bit = 31,
|
||||
.clkr = {
|
||||
- .enable_reg = 0x4700c,
|
||||
+ .enable_reg = 0x47014,
|
||||
.enable_mask = BIT(0),
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "gcc_snoc_bus_timeout2_ahb_clk",
|
||||
@@ -4429,10 +4429,10 @@ static struct clk_branch gcc_snoc_bus_ti
|
||||
};
|
||||
|
||||
static struct clk_branch gcc_snoc_bus_timeout3_ahb_clk = {
|
||||
- .halt_reg = 0x47014,
|
||||
+ .halt_reg = 0x4701C,
|
||||
.halt_bit = 31,
|
||||
.clkr = {
|
||||
- .enable_reg = 0x47014,
|
||||
+ .enable_reg = 0x4701C,
|
||||
.enable_mask = BIT(0),
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "gcc_snoc_bus_timeout3_ahb_clk",
|
|
@ -0,0 +1,41 @@
|
|||
From 52315bec6ed633b6a71f28b746029602f8bd70b9 Mon Sep 17 00:00:00 2001
|
||||
From: Balaji Prakash J <bjagadee@codeaurora.org>
|
||||
Date: Wed, 22 Apr 2020 20:35:30 +0530
|
||||
Subject: [PATCH] clk: ipq8074: fix gcc_blsp1_ahb_clk properties
|
||||
|
||||
All the voting enabled clocks does not support the enable
|
||||
from CBCR register. So, updated gcc_blsp1_ahb_clk enable
|
||||
register and mask to enable bit in APCS_CLOCK_BRANCH_ENA_VOTE.
|
||||
|
||||
Also, the voting controlled clocks are shared among multiple
|
||||
components like APSS, RPM, NSS, TZ, etc. So, turning the
|
||||
voting off from APSS does not make the clock off if it has
|
||||
been voted from another component. Added the flag
|
||||
BRANCH_HALT_VOTED in order to skip checking the clock
|
||||
disable status.
|
||||
|
||||
This change is referred from the below commits,
|
||||
1. 246b4fb3af9bd65d8af794aac2f0e7b1ed9cc2dd
|
||||
2. c8374157d5ae91d3b3e0d513d62808a798b32d3a
|
||||
|
||||
Signed-off-by: Balaji Prakash J <bjagadee@codeaurora.org>
|
||||
Change-Id: I505cb560b31ad27a02c165fbe13bb33a2fc7d230
|
||||
---
|
||||
drivers/clk/qcom/gcc-ipq8074.c | 5 +++--
|
||||
1 file changed, 3 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/clk/qcom/gcc-ipq8074.c
|
||||
+++ b/drivers/clk/qcom/gcc-ipq8074.c
|
||||
@@ -2125,9 +2125,10 @@ struct clk_rcg2 adss_pwm_clk_src = {
|
||||
|
||||
static struct clk_branch gcc_blsp1_ahb_clk = {
|
||||
.halt_reg = 0x01008,
|
||||
+ .halt_check = BRANCH_HALT_VOTED,
|
||||
.clkr = {
|
||||
- .enable_reg = 0x01008,
|
||||
- .enable_mask = BIT(0),
|
||||
+ .enable_reg = 0x0b004,
|
||||
+ .enable_mask = BIT(10),
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "gcc_blsp1_ahb_clk",
|
||||
.parent_hws = (const struct clk_hw *[]){
|
|
@ -0,0 +1,875 @@
|
|||
--- a/include/linux/if_bridge.h
|
||||
+++ b/include/linux/if_bridge.h
|
||||
@@ -71,6 +71,9 @@ 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 void br_dev_update_stats(struct net_device *dev,
|
||||
+ struct rtnl_link_stats64 *nlstats);
|
||||
+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,
|
||||
@@ -213,4 +216,42 @@ static inline clock_t br_get_ageing_time
|
||||
}
|
||||
#endif
|
||||
|
||||
+/* QCA NSS ECM support - Start */
|
||||
+extern struct net_device *br_port_dev_get(struct net_device *dev,
|
||||
+ unsigned char *addr,
|
||||
+ 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 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);
|
||||
+
|
||||
+typedef struct net_bridge_port *br_port_dev_get_hook_t(struct net_device *dev,
|
||||
+ struct sk_buff *skb,
|
||||
+ unsigned char *addr,
|
||||
+ unsigned int cookie);
|
||||
+extern br_port_dev_get_hook_t __rcu *br_port_dev_get_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;
|
||||
+ 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);
|
||||
+
|
||||
+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;
|
||||
+/* QCA NSS ECM support - End */
|
||||
+
|
||||
#endif
|
||||
--- a/include/linux/if_vlan.h
|
||||
+++ b/include/linux/if_vlan.h
|
||||
@@ -143,7 +143,10 @@ 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); /* QCA NSS ECM support */
|
||||
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); /* QCA NSS ECM support */
|
||||
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)
|
||||
+{
|
||||
+
|
||||
+} /* QCA NSS ECM support */
|
||||
+
|
||||
static inline struct net_device *
|
||||
__vlan_find_dev_deep_rcu(struct net_device *real_dev,
|
||||
__be16 vlan_proto, u16 vlan_id)
|
||||
--- a/include/linux/netdevice.h
|
||||
+++ b/include/linux/netdevice.h
|
||||
@@ -2936,6 +2936,10 @@ enum netdev_cmd {
|
||||
NETDEV_OFFLOAD_XSTATS_REPORT_USED,
|
||||
NETDEV_OFFLOAD_XSTATS_REPORT_DELTA,
|
||||
NETDEV_XDP_FEAT_CHANGE,
|
||||
+ /* QCA NSS ECM Support - Start */
|
||||
+ NETDEV_BR_JOIN,
|
||||
+ NETDEV_BR_LEAVE,
|
||||
+ /* QCA NSS ECM Support - End */
|
||||
};
|
||||
const char *netdev_cmd_to_name(enum netdev_cmd cmd);
|
||||
|
||||
--- a/include/net/ip6_route.h
|
||||
+++ b/include/net/ip6_route.h
|
||||
@@ -207,6 +207,11 @@ void rt6_multipath_rebalance(struct fib6
|
||||
void rt6_uncached_list_add(struct rt6_info *rt);
|
||||
void rt6_uncached_list_del(struct rt6_info *rt);
|
||||
|
||||
+/* QCA NSS ECM support - Start */
|
||||
+int rt6_register_notifier(struct notifier_block *nb);
|
||||
+int rt6_unregister_notifier(struct notifier_block *nb);
|
||||
+/* QCA NSS ECM support - End */
|
||||
+
|
||||
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/neighbour.h
|
||||
+++ b/include/net/neighbour.h
|
||||
@@ -249,6 +249,13 @@ static inline int neigh_parms_family(str
|
||||
return p->tbl->family;
|
||||
}
|
||||
|
||||
+/* QCA NSS ECM support - Start */
|
||||
+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))];
|
||||
+};
|
||||
+/* QCA NSS ECM support - End */
|
||||
+
|
||||
#define NEIGH_PRIV_ALIGN sizeof(long long)
|
||||
#define NEIGH_ENTRY_SIZE(size) ALIGN((size), NEIGH_PRIV_ALIGN)
|
||||
|
||||
@@ -395,6 +402,11 @@ void __neigh_for_each_release(struct nei
|
||||
int (*cb)(struct neighbour *));
|
||||
int neigh_xmit(int fam, struct net_device *, const void *, struct sk_buff *);
|
||||
|
||||
+/* QCA NSS ECM support - Start */
|
||||
+extern void neigh_mac_update_register_notify(struct notifier_block *nb);
|
||||
+extern void neigh_mac_update_unregister_notify(struct notifier_block *nb);
|
||||
+/* QCA NSS ECM support - End */
|
||||
+
|
||||
struct neigh_seq_state {
|
||||
struct seq_net_private p;
|
||||
struct neigh_table *tbl;
|
||||
@@ -600,4 +612,5 @@ static inline void neigh_update_is_route
|
||||
*notify = 1;
|
||||
}
|
||||
}
|
||||
+
|
||||
#endif
|
||||
--- a/include/net/route.h
|
||||
+++ b/include/net/route.h
|
||||
@@ -237,6 +237,11 @@ 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);
|
||||
|
||||
+/* QCA NSS ECM support - Start */
|
||||
+int ip_rt_register_notifier(struct notifier_block *nb);
|
||||
+int ip_rt_unregister_notifier(struct notifier_block *nb);
|
||||
+/* QCA NSS ECM support - End */
|
||||
+
|
||||
struct in_ifaddr;
|
||||
void fib_add_ifaddr(struct in_ifaddr *);
|
||||
void fib_del_ifaddr(struct in_ifaddr *, struct in_ifaddr *);
|
||||
--- a/net/bridge/br_private.h
|
||||
+++ b/net/bridge/br_private.h
|
||||
@@ -2266,4 +2266,6 @@ 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)) /* QCA NSS ECM support */
|
||||
#endif
|
||||
--- a/net/8021q/vlan_core.c
|
||||
+++ b/net/8021q/vlan_core.c
|
||||
@@ -72,6 +72,28 @@ bool vlan_do_receive(struct sk_buff **sk
|
||||
return true;
|
||||
}
|
||||
|
||||
+/* QCA NSS ECM support - Start */
|
||||
+/* 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 = per_cpu_ptr(vlan_dev_priv(dev)->vlan_pcpu_stats, 0);
|
||||
+
|
||||
+ 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);
|
||||
+/* QCA NSS ECM support - End */
|
||||
+
|
||||
/* 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)
|
||||
@@ -110,6 +132,15 @@ struct net_device *vlan_dev_real_dev(con
|
||||
}
|
||||
EXPORT_SYMBOL(vlan_dev_real_dev);
|
||||
|
||||
+/* QCA NSS ECM support - Start */
|
||||
+/* 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);
|
||||
+/* QCA NSS ECM support - End */
|
||||
+
|
||||
u16 vlan_dev_vlan_id(const struct net_device *dev)
|
||||
{
|
||||
return vlan_dev_priv(dev)->vlan_id;
|
||||
--- 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,25 @@ static void fdb_notify(struct net_bridge
|
||||
if (swdev_notify)
|
||||
br_switchdev_fdb_notify(br, fdb, type);
|
||||
|
||||
+ /* QCA NSS ECM support - Start */
|
||||
+ 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);
|
||||
+ }
|
||||
+ /* QCA NSS ECM support - End */
|
||||
+
|
||||
skb = nlmsg_new(fdb_nlmsg_size(), GFP_ATOMIC);
|
||||
if (skb == NULL)
|
||||
goto errout;
|
||||
@@ -519,6 +552,22 @@ out:
|
||||
spin_unlock_bh(&br->hash_lock);
|
||||
}
|
||||
|
||||
+/* QCA NSS ECM support - Start */
|
||||
+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);
|
||||
+/* QCA NSS ECM support - End */
|
||||
+
|
||||
void br_fdb_cleanup(struct work_struct *work)
|
||||
{
|
||||
struct net_bridge *br = container_of(work, struct net_bridge,
|
||||
@@ -527,6 +576,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]; /* QCA NSS ECM support */
|
||||
|
||||
/* this part is tricky, in order to avoid blocking learning and
|
||||
* consequently forwarding, we rely on rcu to delete objects with
|
||||
@@ -553,8 +603,15 @@ 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))
|
||||
+ if (!hlist_unhashed(&f->fdb_node)) {
|
||||
+ ether_addr_copy(mac_addr, f->key.addr.addr);
|
||||
fdb_delete(br, f, true);
|
||||
+ /* QCA NSS ECM support - Start */
|
||||
+ atomic_notifier_call_chain(
|
||||
+ &br_fdb_update_notifier_list, 0,
|
||||
+ (void *)mac_addr);
|
||||
+ /* QCA NSS ECM support - End */
|
||||
+ }
|
||||
spin_unlock_bh(&br->hash_lock);
|
||||
}
|
||||
}
|
||||
@@ -891,6 +948,12 @@ void br_fdb_update(struct net_bridge *br
|
||||
*/
|
||||
if (unlikely(test_bit(BR_FDB_LOCKED, &fdb->flags)))
|
||||
clear_bit(BR_FDB_LOCKED, &fdb->flags);
|
||||
+
|
||||
+ /* QCA NSS ECM support - Start */
|
||||
+ atomic_notifier_call_chain(
|
||||
+ &br_fdb_update_notifier_list,
|
||||
+ 0, (void *)addr);
|
||||
+ /* QCA NSS ECM support - End */
|
||||
}
|
||||
|
||||
if (unlikely(test_bit(BR_FDB_ADDED_BY_USER, &flags)))
|
||||
@@ -914,6 +977,64 @@ void br_fdb_update(struct net_bridge *br
|
||||
}
|
||||
}
|
||||
|
||||
+/* QCA NSS ECM support - Start */
|
||||
+/* 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);
|
||||
+
|
||||
+/* 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)
|
||||
+{
|
||||
+ 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);
|
||||
+
|
||||
+/* QCA NSS ECM support - End */
|
||||
/* 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
|
||||
@@ -26,6 +26,12 @@
|
||||
|
||||
#include "br_private.h"
|
||||
|
||||
+/* QCA NSS ECM support - Start */
|
||||
+/* 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);
|
||||
+/* QCA NSS ECM support - End */
|
||||
+
|
||||
/*
|
||||
* Determine initial path cost based on speed.
|
||||
* using recommendations from 802.1d standard
|
||||
@@ -697,6 +703,8 @@ int br_add_if(struct net_bridge *br, str
|
||||
|
||||
kobject_uevent(&p->kobj, KOBJ_ADD);
|
||||
|
||||
+ call_netdevice_notifiers(NETDEV_BR_JOIN, dev); /* QCA NSS ECM support */
|
||||
+
|
||||
return 0;
|
||||
|
||||
err6:
|
||||
@@ -732,6 +740,8 @@ int br_del_if(struct net_bridge *br, str
|
||||
if (!p || p->br != br)
|
||||
return -EINVAL;
|
||||
|
||||
+ call_netdevice_notifiers(NETDEV_BR_LEAVE, dev); /* QCA NSS ECM support */
|
||||
+
|
||||
/* 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.
|
||||
@@ -775,3 +785,97 @@ 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()
|
||||
+ * 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 sk_buff *skb,
|
||||
+ unsigned int cookie)
|
||||
+{
|
||||
+ 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;
|
||||
+
|
||||
+ 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,
|
||||
+ addr, cookie);
|
||||
+ 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 */
|
||||
+ 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;
|
||||
+}
|
||||
+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 pcpu_sw_netstats *tstats;
|
||||
+
|
||||
+ /* Is this a bridge? */
|
||||
+ if (!(dev->priv_flags & IFF_EBRIDGE))
|
||||
+ return;
|
||||
+
|
||||
+ tstats = this_cpu_ptr(dev->tstats);
|
||||
+
|
||||
+ u64_stats_update_begin(&tstats->syncp);
|
||||
+ u64_stats_add(&tstats->rx_packets, nlstats->rx_packets);
|
||||
+ u64_stats_add(&tstats->rx_bytes, nlstats->rx_bytes);
|
||||
+ u64_stats_add(&tstats->tx_packets, nlstats->tx_packets);
|
||||
+ u64_stats_add(&tstats->tx_bytes, nlstats->tx_bytes);
|
||||
+ u64_stats_update_end(&tstats->syncp);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(br_dev_update_stats);
|
||||
+
|
||||
+/* QCA NSS ECM support - Start */
|
||||
+/* 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);
|
||||
+
|
||||
+/* QCA NSS ECM support - End */
|
||||
--- a/net/core/neighbour.c
|
||||
+++ b/net/core/neighbour.c
|
||||
@@ -1275,6 +1275,22 @@ static void neigh_update_hhs(struct neig
|
||||
}
|
||||
}
|
||||
|
||||
+/* QCA NSS ECM support - Start */
|
||||
+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);
|
||||
+/* QCA NSS ECM support - End */
|
||||
+
|
||||
/* Generic update routine.
|
||||
-- lladdr is new lladdr or NULL, if it is not supplied.
|
||||
-- new is new state.
|
||||
@@ -1303,6 +1319,7 @@ static int __neigh_update(struct neighbo
|
||||
struct net_device *dev;
|
||||
int err, notify = 0;
|
||||
u8 old;
|
||||
+ struct neigh_mac_update nmu; /* QCA NSS ECM support */
|
||||
|
||||
trace_neigh_update(neigh, lladdr, new, flags, nlmsg_pid);
|
||||
|
||||
@@ -1317,7 +1334,10 @@ static int __neigh_update(struct neighbo
|
||||
new = old;
|
||||
goto out;
|
||||
}
|
||||
- if (!(flags & NEIGH_UPDATE_F_ADMIN) &&
|
||||
+
|
||||
+ memset(&nmu, 0, sizeof(struct neigh_mac_update)); /* QCA NSS ECM support */
|
||||
+
|
||||
+ if (!(flags & NEIGH_UPDATE_F_ADMIN) &&
|
||||
(old & (NUD_NOARP | NUD_PERMANENT)))
|
||||
goto out;
|
||||
|
||||
@@ -1354,7 +1374,12 @@ static int __neigh_update(struct neighbo
|
||||
- compare new & old
|
||||
- if they are different, check override flag
|
||||
*/
|
||||
- if ((old & NUD_VALID) &&
|
||||
+ /* QCA NSS ECM update - Start */
|
||||
+ memcpy(nmu.old_mac, neigh->ha, dev->addr_len);
|
||||
+ memcpy(nmu.update_mac, lladdr, dev->addr_len);
|
||||
+ /* QCA NSS ECM update - End */
|
||||
+
|
||||
+ if ((old & NUD_VALID) &&
|
||||
!memcmp(lladdr, neigh->ha, dev->addr_len))
|
||||
lladdr = neigh->ha;
|
||||
} else {
|
||||
@@ -1476,8 +1501,11 @@ 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); /* QCA NSS ECM support */
|
||||
+ }
|
||||
trace_neigh_update_done(neigh, err);
|
||||
return err;
|
||||
}
|
||||
--- 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); /* QCA NSS ECM support */
|
||||
+
|
||||
/* 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,9 @@ 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:
|
||||
@@ -1775,6 +1781,9 @@ 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;
|
||||
@@ -2407,6 +2416,20 @@ void __init fib_trie_init(void)
|
||||
0, SLAB_PANIC | SLAB_ACCOUNT, NULL);
|
||||
}
|
||||
|
||||
+/* QCA NSS ECM support - Start */
|
||||
+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);
|
||||
+/* QCA NSS ECM support - End */
|
||||
+
|
||||
struct fib_table *fib_trie_table(u32 id, struct fib_table *alias)
|
||||
{
|
||||
struct fib_table *tb;
|
||||
--- a/net/ipv6/ndisc.c
|
||||
+++ b/net/ipv6/ndisc.c
|
||||
@@ -666,6 +666,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)
|
||||
--- a/net/ipv6/route.c
|
||||
+++ b/net/ipv6/route.c
|
||||
@@ -197,6 +197,9 @@ static void rt6_uncached_list_flush_dev(
|
||||
}
|
||||
}
|
||||
|
||||
+/* Define route change notification chain. */
|
||||
+ATOMIC_NOTIFIER_HEAD(ip6route_chain); /* QCA NSS ECM support */
|
||||
+
|
||||
static inline const void *choose_neigh_daddr(const struct in6_addr *p,
|
||||
struct sk_buff *skb,
|
||||
const void *daddr)
|
||||
@@ -3864,6 +3867,10 @@ 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;
|
||||
@@ -3885,6 +3892,9 @@ static int __ip6_del_rt(struct fib6_info
|
||||
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;
|
||||
@@ -6329,6 +6339,20 @@ static int ip6_route_dev_notify(struct n
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
+/* QCA NSS ECM support - Start */
|
||||
+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);
|
||||
+/* QCA NSS ECM support - End */
|
||||
+
|
||||
/*
|
||||
* /proc
|
||||
*/
|
||||
--- a/net/core/dev.c
|
||||
+++ b/net/core/dev.c
|
||||
@@ -1673,6 +1673,7 @@ 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";
|
||||
--- a/net/ipv6/addrconf.c
|
||||
+++ b/net/ipv6/addrconf.c
|
||||
@@ -1002,6 +1002,7 @@ void inet6_ifa_finish_destroy(struct ine
|
||||
|
||||
kfree_rcu(ifp, rcu);
|
||||
}
|
||||
+EXPORT_SYMBOL(inet6_ifa_finish_destroy);
|
||||
|
||||
static void
|
||||
ipv6_link_dev_addr(struct inet6_dev *idev, struct inet6_ifaddr *ifp)
|
||||
--- a/include/net/vxlan.h
|
||||
+++ b/include/net/vxlan.h
|
||||
@@ -440,6 +440,15 @@ static inline __be32 vxlan_compute_rco(u
|
||||
return vni_field;
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * vxlan_get_vni()
|
||||
+ * Returns the vni corresponding to tunnel
|
||||
+ */
|
||||
+static inline u32 vxlan_get_vni(struct vxlan_dev *vxlan_tun)
|
||||
+{
|
||||
+ return be32_to_cpu(vxlan_tun->cfg.vni);
|
||||
+}
|
||||
+
|
||||
static inline unsigned short vxlan_get_sk_family(struct vxlan_sock *vs)
|
||||
{
|
||||
return vs->sock->sk->sk_family;
|
||||
--- a/include/uapi/linux/in.h
|
||||
+++ b/include/uapi/linux/in.h
|
||||
@@ -63,6 +63,8 @@ enum {
|
||||
#define IPPROTO_MTP IPPROTO_MTP
|
||||
IPPROTO_BEETPH = 94, /* IP option pseudo header for BEET */
|
||||
#define IPPROTO_BEETPH IPPROTO_BEETPH
|
||||
+ IPPROTO_ETHERIP = 97, /* ETHERIP protocol number */
|
||||
+#define IPPROTO_ETHERIP IPPROTO_ETHERIP
|
||||
IPPROTO_ENCAP = 98, /* Encapsulation Header */
|
||||
#define IPPROTO_ENCAP IPPROTO_ENCAP
|
||||
IPPROTO_PIM = 103, /* Protocol Independent Multicast */
|
||||
@@ -327,7 +329,7 @@ struct sockaddr_in {
|
||||
#endif
|
||||
|
||||
/* <asm/byteorder.h> contains the htonl type stuff.. */
|
||||
-#include <asm/byteorder.h>
|
||||
+#include <asm/byteorder.h>
|
||||
|
||||
|
||||
#endif /* _UAPI_LINUX_IN_H */
|
||||
--- a/tools/include/uapi/linux/in.h
|
||||
+++ b/tools/include/uapi/linux/in.h
|
||||
@@ -63,6 +63,8 @@ enum {
|
||||
#define IPPROTO_MTP IPPROTO_MTP
|
||||
IPPROTO_BEETPH = 94, /* IP option pseudo header for BEET */
|
||||
#define IPPROTO_BEETPH IPPROTO_BEETPH
|
||||
+ IPPROTO_ETHERIP = 97, /* ETHERIP protocol number */
|
||||
+#define IPPROTO_ETHERIP IPPROTO_ETHERIP
|
||||
IPPROTO_ENCAP = 98, /* Encapsulation Header */
|
||||
#define IPPROTO_ENCAP IPPROTO_ENCAP
|
||||
IPPROTO_PIM = 103, /* Protocol Independent Multicast */
|
||||
@@ -327,7 +329,7 @@ struct sockaddr_in {
|
||||
#endif
|
||||
|
||||
/* <asm/byteorder.h> contains the htonl type stuff.. */
|
||||
-#include <asm/byteorder.h>
|
||||
+#include <asm/byteorder.h>
|
||||
|
||||
|
||||
#endif /* _UAPI_LINUX_IN_H */
|
||||
--- a/net/netfilter/nf_conntrack_ecache.c
|
||||
+++ b/net/netfilter/nf_conntrack_ecache.c
|
||||
@@ -266,7 +266,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);
|
||||
}
|
||||
--- 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
|
||||
@@ -633,6 +633,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,
|
||||
@@ -840,6 +841,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),
|
||||
@@ -1050,6 +1059,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
|
|
@ -0,0 +1,600 @@
|
|||
--- a/drivers/net/ppp/ppp_generic.c
|
||||
+++ b/drivers/net/ppp/ppp_generic.c
|
||||
@@ -48,6 +48,7 @@
|
||||
#include <net/slhc_vj.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/refcount.h>
|
||||
+#include <linux/if_pppox.h>
|
||||
|
||||
#include <linux/nsproxy.h>
|
||||
#include <net/net_namespace.h>
|
||||
@@ -254,6 +255,25 @@ struct ppp_net {
|
||||
#define seq_before(a, b) ((s32)((a) - (b)) < 0)
|
||||
#define seq_after(a, b) ((s32)((a) - (b)) > 0)
|
||||
|
||||
+
|
||||
+/*
|
||||
+ * Registration/Unregistration methods
|
||||
+ * for PPP channel connect and disconnect event notifications.
|
||||
+ */
|
||||
+RAW_NOTIFIER_HEAD(ppp_channel_connection_notifier_list);
|
||||
+
|
||||
+void ppp_channel_connection_register_notify(struct notifier_block *nb)
|
||||
+{
|
||||
+ raw_notifier_chain_register(&ppp_channel_connection_notifier_list, nb);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(ppp_channel_connection_register_notify);
|
||||
+
|
||||
+void ppp_channel_connection_unregister_notify(struct notifier_block *nb)
|
||||
+{
|
||||
+ raw_notifier_chain_unregister(&ppp_channel_connection_notifier_list, nb);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(ppp_channel_connection_unregister_notify);
|
||||
+
|
||||
/* Prototypes. */
|
||||
static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf,
|
||||
struct file *file, unsigned int cmd, unsigned long arg);
|
||||
@@ -3453,7 +3473,10 @@ ppp_connect_channel(struct channel *pch,
|
||||
struct ppp_net *pn;
|
||||
int ret = -ENXIO;
|
||||
int hdrlen;
|
||||
+ int ppp_proto;
|
||||
+ int version;
|
||||
|
||||
+ int notify = 0;
|
||||
pn = ppp_pernet(pch->chan_net);
|
||||
|
||||
mutex_lock(&pn->all_ppp_mutex);
|
||||
@@ -3485,13 +3508,40 @@ ppp_connect_channel(struct channel *pch,
|
||||
++ppp->n_channels;
|
||||
pch->ppp = ppp;
|
||||
refcount_inc(&ppp->file.refcnt);
|
||||
+
|
||||
+ /* Set the netdev priv flag if the prototype
|
||||
+ * is L2TP or PPTP. Return success in all cases
|
||||
+ */
|
||||
+ if (!pch->chan)
|
||||
+ goto out2;
|
||||
+
|
||||
+ ppp_proto = ppp_channel_get_protocol(pch->chan);
|
||||
+ if (ppp_proto == PX_PROTO_PPTP) {
|
||||
+ ppp->dev->priv_flags_ext |= IFF_EXT_PPP_PPTP;
|
||||
+ } else if (ppp_proto == PX_PROTO_OL2TP) {
|
||||
+ version = ppp_channel_get_proto_version(pch->chan);
|
||||
+ if (version == 2)
|
||||
+ ppp->dev->priv_flags_ext |= IFF_EXT_PPP_L2TPV2;
|
||||
+ else if (version == 3)
|
||||
+ ppp->dev->priv_flags_ext |= IFF_EXT_PPP_L2TPV3;
|
||||
+ }
|
||||
+ notify = 1;
|
||||
+
|
||||
+ out2:
|
||||
ppp_unlock(ppp);
|
||||
ret = 0;
|
||||
-
|
||||
outl:
|
||||
write_unlock_bh(&pch->upl);
|
||||
out:
|
||||
mutex_unlock(&pn->all_ppp_mutex);
|
||||
+
|
||||
+ if (notify && ppp && ppp->dev) {
|
||||
+ dev_hold(ppp->dev);
|
||||
+ raw_notifier_call_chain(&ppp_channel_connection_notifier_list,
|
||||
+ PPP_CHANNEL_CONNECT, ppp->dev);
|
||||
+ dev_put(ppp->dev);
|
||||
+ }
|
||||
+
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -3509,6 +3559,13 @@ ppp_disconnect_channel(struct channel *p
|
||||
pch->ppp = NULL;
|
||||
write_unlock_bh(&pch->upl);
|
||||
if (ppp) {
|
||||
+ if (ppp->dev) {
|
||||
+ dev_hold(ppp->dev);
|
||||
+ raw_notifier_call_chain(&ppp_channel_connection_notifier_list,
|
||||
+ PPP_CHANNEL_DISCONNECT, ppp->dev);
|
||||
+ dev_put(ppp->dev);
|
||||
+ }
|
||||
+
|
||||
/* remove it from the ppp unit's list */
|
||||
ppp_lock(ppp);
|
||||
list_del(&pch->clist);
|
||||
@@ -3588,6 +3645,222 @@ static void *unit_find(struct idr *p, in
|
||||
return idr_find(p, n);
|
||||
}
|
||||
|
||||
+/* Updates the PPP interface statistics. */
|
||||
+void ppp_update_stats(struct net_device *dev, unsigned long rx_packets,
|
||||
+ unsigned long rx_bytes, unsigned long tx_packets,
|
||||
+ unsigned long tx_bytes, unsigned long rx_errors,
|
||||
+ unsigned long tx_errors, unsigned long rx_dropped,
|
||||
+ unsigned long tx_dropped)
|
||||
+{
|
||||
+ struct ppp *ppp;
|
||||
+
|
||||
+ if (!dev)
|
||||
+ return;
|
||||
+
|
||||
+ if (dev->type != ARPHRD_PPP)
|
||||
+ return;
|
||||
+
|
||||
+ ppp = netdev_priv(dev);
|
||||
+
|
||||
+ ppp_xmit_lock(ppp);
|
||||
+ ppp->stats64.tx_packets += tx_packets;
|
||||
+ ppp->stats64.tx_bytes += tx_bytes;
|
||||
+ ppp->dev->stats.tx_errors += tx_errors;
|
||||
+ ppp->dev->stats.tx_dropped += tx_dropped;
|
||||
+ if (tx_packets)
|
||||
+ ppp->last_xmit = jiffies;
|
||||
+ ppp_xmit_unlock(ppp);
|
||||
+
|
||||
+ ppp_recv_lock(ppp);
|
||||
+ ppp->stats64.rx_packets += rx_packets;
|
||||
+ ppp->stats64.rx_bytes += rx_bytes;
|
||||
+ ppp->dev->stats.rx_errors += rx_errors;
|
||||
+ ppp->dev->stats.rx_dropped += rx_dropped;
|
||||
+ if (rx_packets)
|
||||
+ ppp->last_recv = jiffies;
|
||||
+ ppp_recv_unlock(ppp);
|
||||
+}
|
||||
+
|
||||
+/* Returns >0 if the device is a multilink PPP netdevice, 0 if not or < 0 if
|
||||
+ * the device is not PPP.
|
||||
+ */
|
||||
+int ppp_is_multilink(struct net_device *dev)
|
||||
+{
|
||||
+ struct ppp *ppp;
|
||||
+ unsigned int flags;
|
||||
+
|
||||
+ if (!dev)
|
||||
+ return -1;
|
||||
+
|
||||
+ if (dev->type != ARPHRD_PPP)
|
||||
+ return -1;
|
||||
+
|
||||
+ ppp = netdev_priv(dev);
|
||||
+ ppp_lock(ppp);
|
||||
+ flags = ppp->flags;
|
||||
+ ppp_unlock(ppp);
|
||||
+
|
||||
+ if (flags & SC_MULTILINK)
|
||||
+ return 1;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+EXPORT_SYMBOL(ppp_is_multilink);
|
||||
+
|
||||
+/* ppp_channel_get_protocol()
|
||||
+ * Call this to obtain the underlying protocol of the PPP channel,
|
||||
+ * e.g. PX_PROTO_OE
|
||||
+ *
|
||||
+ * NOTE: Some channels do not use PX sockets so the protocol value may be very
|
||||
+ * different for them.
|
||||
+ * NOTE: -1 indicates failure.
|
||||
+ * NOTE: Once you know the channel protocol you may then either cast 'chan' to
|
||||
+ * its sub-class or use the channel protocol specific API's as provided by that
|
||||
+ * channel sub type.
|
||||
+ */
|
||||
+int ppp_channel_get_protocol(struct ppp_channel *chan)
|
||||
+{
|
||||
+ if (!chan->ops->get_channel_protocol)
|
||||
+ return -1;
|
||||
+
|
||||
+ return chan->ops->get_channel_protocol(chan);
|
||||
+}
|
||||
+EXPORT_SYMBOL(ppp_channel_get_protocol);
|
||||
+
|
||||
+/* ppp_channel_get_proto_version()
|
||||
+ * Call this to get channel protocol version
|
||||
+ */
|
||||
+int ppp_channel_get_proto_version(struct ppp_channel *chan)
|
||||
+{
|
||||
+ if (!chan->ops->get_channel_protocol_ver)
|
||||
+ return -1;
|
||||
+
|
||||
+ return chan->ops->get_channel_protocol_ver(chan);
|
||||
+}
|
||||
+EXPORT_SYMBOL(ppp_channel_get_proto_version);
|
||||
+
|
||||
+/* ppp_channel_hold()
|
||||
+ * Call this to hold a channel.
|
||||
+ *
|
||||
+ * Returns true on success or false if the hold could not happen.
|
||||
+ *
|
||||
+ * NOTE: chan must be protected against destruction during this call -
|
||||
+ * either by correct locking etc. or because you already have an implicit
|
||||
+ * or explicit hold to the channel already and this is an additional hold.
|
||||
+ */
|
||||
+bool ppp_channel_hold(struct ppp_channel *chan)
|
||||
+{
|
||||
+ if (!chan->ops->hold)
|
||||
+ return false;
|
||||
+
|
||||
+ chan->ops->hold(chan);
|
||||
+ return true;
|
||||
+}
|
||||
+EXPORT_SYMBOL(ppp_channel_hold);
|
||||
+
|
||||
+/* ppp_channel_release()
|
||||
+ * Call this to release a hold you have upon a channel
|
||||
+ */
|
||||
+void ppp_channel_release(struct ppp_channel *chan)
|
||||
+{
|
||||
+ chan->ops->release(chan);
|
||||
+}
|
||||
+EXPORT_SYMBOL(ppp_channel_release);
|
||||
+
|
||||
+/* Check if ppp xmit lock is on hold */
|
||||
+bool ppp_is_xmit_locked(struct net_device *dev)
|
||||
+{
|
||||
+ struct ppp *ppp;
|
||||
+
|
||||
+ if (!dev)
|
||||
+ return false;
|
||||
+
|
||||
+ if (dev->type != ARPHRD_PPP)
|
||||
+ return false;
|
||||
+
|
||||
+ ppp = netdev_priv(dev);
|
||||
+ if (!ppp)
|
||||
+ return false;
|
||||
+
|
||||
+ if (spin_is_locked(&(ppp)->wlock))
|
||||
+ return true;
|
||||
+
|
||||
+ return false;
|
||||
+}
|
||||
+EXPORT_SYMBOL(ppp_is_xmit_locked);
|
||||
+
|
||||
+/* ppp_hold_channels()
|
||||
+ * Returns the PPP channels of the PPP device, storing each one into
|
||||
+ * channels[].
|
||||
+ *
|
||||
+ * channels[] has chan_sz elements.
|
||||
+ * This function returns the number of channels stored, up to chan_sz.
|
||||
+ * It will return < 0 if the device is not PPP.
|
||||
+ *
|
||||
+ * You MUST release the channels using ppp_release_channels().
|
||||
+ */
|
||||
+int ppp_hold_channels(struct net_device *dev, struct ppp_channel *channels[],
|
||||
+ unsigned int chan_sz)
|
||||
+{
|
||||
+ struct ppp *ppp;
|
||||
+ int c;
|
||||
+ struct channel *pch;
|
||||
+
|
||||
+ if (!dev)
|
||||
+ return -1;
|
||||
+
|
||||
+ if (dev->type != ARPHRD_PPP)
|
||||
+ return -1;
|
||||
+
|
||||
+ ppp = netdev_priv(dev);
|
||||
+
|
||||
+ c = 0;
|
||||
+ ppp_lock(ppp);
|
||||
+ list_for_each_entry(pch, &ppp->channels, clist) {
|
||||
+ struct ppp_channel *chan;
|
||||
+
|
||||
+ if (!pch->chan) {
|
||||
+ /* Channel is going / gone away */
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (c == chan_sz) {
|
||||
+ /* No space to record channel */
|
||||
+ ppp_unlock(ppp);
|
||||
+ return c;
|
||||
+ }
|
||||
+
|
||||
+ /* Hold the channel, if supported */
|
||||
+ chan = pch->chan;
|
||||
+ if (!chan->ops->hold)
|
||||
+ continue;
|
||||
+
|
||||
+ chan->ops->hold(chan);
|
||||
+
|
||||
+ /* Record the channel */
|
||||
+ channels[c++] = chan;
|
||||
+ }
|
||||
+ ppp_unlock(ppp);
|
||||
+ return c;
|
||||
+}
|
||||
+EXPORT_SYMBOL(ppp_hold_channels);
|
||||
+
|
||||
+/* ppp_release_channels()
|
||||
+ * Releases channels
|
||||
+ */
|
||||
+void ppp_release_channels(struct ppp_channel *channels[], unsigned int chan_sz)
|
||||
+{
|
||||
+ unsigned int c;
|
||||
+
|
||||
+ for (c = 0; c < chan_sz; ++c) {
|
||||
+ struct ppp_channel *chan;
|
||||
+
|
||||
+ chan = channels[c];
|
||||
+ chan->ops->release(chan);
|
||||
+ }
|
||||
+}
|
||||
+EXPORT_SYMBOL(ppp_release_channels);
|
||||
+
|
||||
/* Module/initialization stuff */
|
||||
|
||||
module_init(ppp_init);
|
||||
@@ -3604,6 +3877,7 @@ EXPORT_SYMBOL(ppp_input_error);
|
||||
EXPORT_SYMBOL(ppp_output_wakeup);
|
||||
EXPORT_SYMBOL(ppp_register_compressor);
|
||||
EXPORT_SYMBOL(ppp_unregister_compressor);
|
||||
+EXPORT_SYMBOL(ppp_update_stats);
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS_CHARDEV(PPP_MAJOR, 0);
|
||||
MODULE_ALIAS_RTNL_LINK("ppp");
|
||||
--- a/drivers/net/ppp/pppoe.c
|
||||
+++ b/drivers/net/ppp/pppoe.c
|
||||
@@ -62,6 +62,7 @@
|
||||
#include <linux/inetdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/skbuff.h>
|
||||
+#include <linux/if_arp.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/if_pppox.h>
|
||||
@@ -87,7 +88,7 @@
|
||||
static int __pppoe_xmit(struct sock *sk, struct sk_buff *skb);
|
||||
|
||||
static const struct proto_ops pppoe_ops;
|
||||
-static const struct ppp_channel_ops pppoe_chan_ops;
|
||||
+static const struct pppoe_channel_ops pppoe_chan_ops;
|
||||
|
||||
/* per-net private data for this module */
|
||||
static unsigned int pppoe_net_id __read_mostly;
|
||||
@@ -692,7 +693,7 @@ static int pppoe_connect(struct socket *
|
||||
|
||||
po->chan.mtu = dev->mtu - sizeof(struct pppoe_hdr) - 2;
|
||||
po->chan.private = sk;
|
||||
- po->chan.ops = &pppoe_chan_ops;
|
||||
+ po->chan.ops = (struct ppp_channel_ops *)&pppoe_chan_ops;
|
||||
|
||||
error = ppp_register_net_channel(dev_net(dev), &po->chan);
|
||||
if (error) {
|
||||
@@ -995,9 +996,80 @@ static int pppoe_fill_forward_path(struc
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static const struct ppp_channel_ops pppoe_chan_ops = {
|
||||
- .start_xmit = pppoe_xmit,
|
||||
- .fill_forward_path = pppoe_fill_forward_path,
|
||||
+/************************************************************************
|
||||
+ *
|
||||
+ * function called by generic PPP driver to hold channel
|
||||
+ *
|
||||
+ ***********************************************************************/
|
||||
+static void pppoe_hold_chan(struct ppp_channel *chan)
|
||||
+{
|
||||
+ struct sock *sk = (struct sock *)chan->private;
|
||||
+
|
||||
+ sock_hold(sk);
|
||||
+}
|
||||
+
|
||||
+/************************************************************************
|
||||
+ *
|
||||
+ * function called by generic PPP driver to release channel
|
||||
+ *
|
||||
+ ***********************************************************************/
|
||||
+static void pppoe_release_chan(struct ppp_channel *chan)
|
||||
+{
|
||||
+ struct sock *sk = (struct sock *)chan->private;
|
||||
+
|
||||
+ sock_put(sk);
|
||||
+}
|
||||
+
|
||||
+/************************************************************************
|
||||
+ *
|
||||
+ * function called to get the channel protocol type
|
||||
+ *
|
||||
+ ***********************************************************************/
|
||||
+static int pppoe_get_channel_protocol(struct ppp_channel *chan)
|
||||
+{
|
||||
+ return PX_PROTO_OE;
|
||||
+}
|
||||
+
|
||||
+/************************************************************************
|
||||
+ *
|
||||
+ * function called to get the PPPoE channel addressing
|
||||
+ * NOTE: This function returns a HOLD to the netdevice
|
||||
+ *
|
||||
+ ***********************************************************************/
|
||||
+static int pppoe_get_addressing(struct ppp_channel *chan,
|
||||
+ struct pppoe_opt *addressing)
|
||||
+{
|
||||
+ struct sock *sk = (struct sock *)chan->private;
|
||||
+ struct pppox_sock *po = pppox_sk(sk);
|
||||
+ int err = 0;
|
||||
+
|
||||
+ *addressing = po->proto.pppoe;
|
||||
+ if (!addressing->dev)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ dev_hold(addressing->dev);
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+/* pppoe_channel_addressing_get()
|
||||
+ * Return PPPoE channel specific addressing information.
|
||||
+ */
|
||||
+int pppoe_channel_addressing_get(struct ppp_channel *chan,
|
||||
+ struct pppoe_opt *addressing)
|
||||
+{
|
||||
+ return pppoe_get_addressing(chan, addressing);
|
||||
+}
|
||||
+EXPORT_SYMBOL(pppoe_channel_addressing_get);
|
||||
+
|
||||
+static const struct pppoe_channel_ops pppoe_chan_ops = {
|
||||
+ /* PPPoE specific channel ops */
|
||||
+ .get_addressing = pppoe_get_addressing,
|
||||
+ /* General ppp channel ops */
|
||||
+ .ops.start_xmit = pppoe_xmit,
|
||||
+ .ops.get_channel_protocol = pppoe_get_channel_protocol,
|
||||
+ .ops.hold = pppoe_hold_chan,
|
||||
+ .ops.release = pppoe_release_chan,
|
||||
+ .ops.fill_forward_path = pppoe_fill_forward_path,
|
||||
};
|
||||
|
||||
static int pppoe_recvmsg(struct socket *sock, struct msghdr *m,
|
||||
--- a/include/linux/if_pppox.h
|
||||
+++ b/include/linux/if_pppox.h
|
||||
@@ -91,4 +91,17 @@ enum {
|
||||
PPPOX_DEAD = 16 /* dead, useless, please clean me up!*/
|
||||
};
|
||||
|
||||
+/*
|
||||
+ * PPPoE Channel specific operations
|
||||
+ */
|
||||
+struct pppoe_channel_ops {
|
||||
+ /* Must be first - general to all PPP channels */
|
||||
+ struct ppp_channel_ops ops;
|
||||
+ int (*get_addressing)(struct ppp_channel *, struct pppoe_opt *);
|
||||
+};
|
||||
+
|
||||
+/* Return PPPoE channel specific addressing information */
|
||||
+extern int pppoe_channel_addressing_get(struct ppp_channel *chan,
|
||||
+ struct pppoe_opt *addressing);
|
||||
+
|
||||
#endif /* !(__LINUX_IF_PPPOX_H) */
|
||||
--- a/include/linux/netdevice.h
|
||||
+++ b/include/linux/netdevice.h
|
||||
@@ -1762,6 +1762,36 @@ 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
|
||||
+ * @IFF_EXT_HW_NO_OFFLOAD: device is an NON Offload device
|
||||
+ * @IFF_EXT_L2TPV3: device is a L2TPV3 Ethernet 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,
|
||||
+ IFF_EXT_HW_NO_OFFLOAD = 1<<8,
|
||||
+ IFF_EXT_ETH_L2TPV3 = 1<<9,
|
||||
+};
|
||||
+
|
||||
#define IFF_802_1Q_VLAN IFF_802_1Q_VLAN
|
||||
#define IFF_EBRIDGE IFF_EBRIDGE
|
||||
#define IFF_BONDING IFF_BONDING
|
||||
@@ -2127,6 +2157,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;
|
||||
--- a/include/linux/ppp_channel.h
|
||||
+++ b/include/linux/ppp_channel.h
|
||||
@@ -19,6 +19,10 @@
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/poll.h>
|
||||
#include <net/net_namespace.h>
|
||||
+#include <linux/notifier.h>
|
||||
+
|
||||
+#define PPP_CHANNEL_DISCONNECT 0
|
||||
+#define PPP_CHANNEL_CONNECT 1
|
||||
|
||||
struct net_device_path;
|
||||
struct net_device_path_ctx;
|
||||
@@ -30,9 +34,19 @@ struct ppp_channel_ops {
|
||||
int (*start_xmit)(struct ppp_channel *, struct sk_buff *);
|
||||
/* Handle an ioctl call that has come in via /dev/ppp. */
|
||||
int (*ioctl)(struct ppp_channel *, unsigned int, unsigned long);
|
||||
+ /* Get channel protocol type, one of PX_PROTO_XYZ or specific to
|
||||
+ * the channel subtype
|
||||
+ */
|
||||
+ int (*get_channel_protocol)(struct ppp_channel *);
|
||||
+ /* Get channel protocol version */
|
||||
+ int (*get_channel_protocol_ver)(struct ppp_channel *);
|
||||
+ /* Hold the channel from being destroyed */
|
||||
+ void (*hold)(struct ppp_channel *);
|
||||
+ /* Release hold on the channel */
|
||||
+ void (*release)(struct ppp_channel *);
|
||||
int (*fill_forward_path)(struct net_device_path_ctx *,
|
||||
- struct net_device_path *,
|
||||
- const struct ppp_channel *);
|
||||
+ struct net_device_path *,
|
||||
+ const struct ppp_channel *);
|
||||
};
|
||||
|
||||
struct ppp_channel {
|
||||
@@ -76,6 +90,51 @@ extern int ppp_unit_number(struct ppp_ch
|
||||
/* Get the device name associated with a channel, or NULL if none */
|
||||
extern char *ppp_dev_name(struct ppp_channel *);
|
||||
|
||||
+/* Call this to obtain the underlying protocol of the PPP channel,
|
||||
+ * e.g. PX_PROTO_OE
|
||||
+ */
|
||||
+extern int ppp_channel_get_protocol(struct ppp_channel *);
|
||||
+
|
||||
+/* Call this get protocol version */
|
||||
+extern int ppp_channel_get_proto_version(struct ppp_channel *);
|
||||
+
|
||||
+/* Call this to hold a channel */
|
||||
+extern bool ppp_channel_hold(struct ppp_channel *);
|
||||
+
|
||||
+/* Call this to release a hold you have upon a channel */
|
||||
+extern void ppp_channel_release(struct ppp_channel *);
|
||||
+
|
||||
+/* Release hold on PPP channels */
|
||||
+extern void ppp_release_channels(struct ppp_channel *channels[],
|
||||
+ unsigned int chan_sz);
|
||||
+
|
||||
+/* Hold PPP channels for the PPP device */
|
||||
+extern int ppp_hold_channels(struct net_device *dev,
|
||||
+ struct ppp_channel *channels[],
|
||||
+ unsigned int chan_sz);
|
||||
+
|
||||
+/* Test if ppp xmit lock is locked */
|
||||
+extern bool ppp_is_xmit_locked(struct net_device *dev);
|
||||
+
|
||||
+/* Test if the ppp device is a multi-link ppp device */
|
||||
+extern int ppp_is_multilink(struct net_device *dev);
|
||||
+
|
||||
+/* Register the PPP channel connect notifier */
|
||||
+extern void ppp_channel_connection_register_notify(struct notifier_block *nb);
|
||||
+
|
||||
+/* Unregister the PPP channel connect notifier */
|
||||
+extern void ppp_channel_connection_unregister_notify(struct notifier_block *nb);
|
||||
+
|
||||
+/* Update statistics of the PPP net_device by incrementing related
|
||||
+ * statistics field value with corresponding parameter
|
||||
+ */
|
||||
+extern void ppp_update_stats(struct net_device *dev, unsigned long rx_packets,
|
||||
+ unsigned long rx_bytes, unsigned long tx_packets,
|
||||
+ unsigned long tx_bytes, unsigned long rx_errors,
|
||||
+ unsigned long tx_errors, unsigned long rx_dropped,
|
||||
+ unsigned long tx_dropped);
|
||||
+
|
||||
+
|
||||
/*
|
||||
* SMP locking notes:
|
||||
* The channel code must ensure that when it calls ppp_unregister_channel,
|
|
@ -0,0 +1,46 @@
|
|||
--- 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; /* QCA NSS ECM bonding support */
|
||||
|
||||
static const struct flow_dissector_key flow_keys_bonding_keys[] = {
|
||||
{
|
||||
@@ -5872,6 +5873,11 @@ static void bond_destructor(struct net_d
|
||||
if (bond->wq)
|
||||
destroy_workqueue(bond->wq);
|
||||
|
||||
+ /* QCA NSS ECM bonding support - Start */
|
||||
+ if (bond->id != (~0U))
|
||||
+ clear_bit(bond->id, &bond_id_mask);
|
||||
+ /* QCA NSS ECM bonding support - End */
|
||||
+
|
||||
free_percpu(bond->rr_tx_counter);
|
||||
}
|
||||
|
||||
@@ -6421,6 +6427,13 @@ int bond_create(struct net *net, const c
|
||||
|
||||
bond_work_init_all(bond);
|
||||
|
||||
+ /* QCA NSS ECM bonding support - Start */
|
||||
+ bond->id = ~0U;
|
||||
+ if (bond_id_mask != (~0UL)) {
|
||||
+ bond->id = (u32)ffz(bond_id_mask);
|
||||
+ set_bit(bond->id, &bond_id_mask);
|
||||
+ }
|
||||
+ /* QCA NSS ECM bonding support - End */
|
||||
out:
|
||||
rtnl_unlock();
|
||||
return res;
|
||||
--- a/include/net/bonding.h
|
||||
+++ b/include/net/bonding.h
|
||||
@@ -261,6 +261,7 @@ struct bonding {
|
||||
spinlock_t ipsec_lock;
|
||||
#endif /* CONFIG_XFRM_OFFLOAD */
|
||||
struct bpf_prog *xdp_prog;
|
||||
+ u32 id;/* QCA NSS ECM bonding support */
|
||||
};
|
||||
|
||||
#define bond_slave_get_rcu(dev) \
|
|
@ -0,0 +1,685 @@
|
|||
--- a/drivers/net/bonding/bond_3ad.c
|
||||
+++ b/drivers/net/bonding/bond_3ad.c
|
||||
@@ -116,6 +116,40 @@ static void ad_marker_response_received(
|
||||
struct port *port);
|
||||
static void ad_update_actor_keys(struct port *port, bool reset);
|
||||
|
||||
+/* QCA NSS ECM bonding support - Start */
|
||||
+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);
|
||||
+/* QCA NSS ECM bonding support - End */
|
||||
|
||||
/* ================= api to bonding and kernel code ================== */
|
||||
|
||||
@@ -1073,7 +1107,31 @@ static void ad_mux_machine(struct port *
|
||||
ad_disable_collecting_distributing(port,
|
||||
update_slave_arr);
|
||||
port->ntt = true;
|
||||
+
|
||||
+ /* QCA NSS ECM bonding support - Start */
|
||||
+ /* 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;
|
||||
+ /* QCA NSS ECM bonding support - End */
|
||||
case AD_MUX_COLLECTING_DISTRIBUTING:
|
||||
port->actor_oper_port_state |= LACP_STATE_COLLECTING;
|
||||
port->actor_oper_port_state |= LACP_STATE_DISTRIBUTING;
|
||||
@@ -1917,6 +1975,7 @@ static void ad_enable_collecting_distrib
|
||||
bool *update_slave_arr)
|
||||
{
|
||||
if (port->aggregator->is_active) {
|
||||
+ struct bond_cb *lag_cb_main; /* QCA NSS ECM bonding support */
|
||||
slave_dbg(port->slave->bond->dev, port->slave->dev,
|
||||
"Enabling port %d (LAG %d)\n",
|
||||
port->actor_port_number,
|
||||
@@ -1924,6 +1983,16 @@ static void ad_enable_collecting_distrib
|
||||
__enable_port(port);
|
||||
/* Slave array needs update */
|
||||
*update_slave_arr = true;
|
||||
+
|
||||
+ /* QCA NSS ECM bonding support - Start */
|
||||
+ 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();
|
||||
+ /* QCA NSS ECM bonding support - End */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2683,6 +2752,104 @@ int bond_3ad_get_active_agg_info(struct
|
||||
return ret;
|
||||
}
|
||||
|
||||
+/* QCA NSS ECM bonding support - Start */
|
||||
+/* 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;
|
||||
+}
|
||||
+/* QCA NSS ECM bonding support - End */
|
||||
+
|
||||
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
|
||||
@@ -288,6 +288,21 @@ const char *bond_mode_name(int mode)
|
||||
return names[mode];
|
||||
}
|
||||
|
||||
+/* QCA NSS ECM bonding support */
|
||||
+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);
|
||||
+/* QCA NSS ECM bonding support */
|
||||
+
|
||||
/**
|
||||
* bond_dev_queue_xmit - Prepare skb for xmit.
|
||||
*
|
||||
@@ -1189,6 +1204,23 @@ void bond_change_active_slave(struct bon
|
||||
if (BOND_MODE(bond) == BOND_MODE_8023AD)
|
||||
bond_3ad_handle_link_change(new_active, BOND_LINK_UP);
|
||||
|
||||
+ /* QCA NSS ECM bonding support - Start */
|
||||
+ 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();
|
||||
+ }
|
||||
+ /* QCA NSS ECM bonding support - End */
|
||||
+
|
||||
if (bond_is_lb(bond))
|
||||
bond_alb_handle_link_change(bond, new_active, BOND_LINK_UP);
|
||||
} else {
|
||||
@@ -1833,6 +1865,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; /* QCA NSS ECM bonding support */
|
||||
int link_reporting;
|
||||
int res = 0, i;
|
||||
|
||||
@@ -2278,6 +2311,15 @@ 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");
|
||||
|
||||
+ /* QCA NSS ECM bonding support - Start */
|
||||
+ 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();
|
||||
+ /* QCA NSS ECM bonding support - End */
|
||||
+
|
||||
/* enslave is successful */
|
||||
bond_queue_slave_event(new_slave);
|
||||
return 0;
|
||||
@@ -2343,6 +2385,15 @@ err_undo_flags:
|
||||
}
|
||||
}
|
||||
|
||||
+ /* QCA NSS ECM bonding support - Start */
|
||||
+ 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();
|
||||
+ /* QCA NSS ECM bonding support - End */
|
||||
+
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -2364,6 +2415,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; /* QCA NSS ECM bonding support */
|
||||
int old_flags = bond_dev->flags;
|
||||
netdev_features_t old_features = bond_dev->features;
|
||||
|
||||
@@ -2386,6 +2438,15 @@ static int __bond_release_one(struct net
|
||||
|
||||
bond_set_slave_inactive_flags(slave, BOND_SLAVE_NOTIFY_NOW);
|
||||
|
||||
+ /* QCA NSS ECM bonding support - Start */
|
||||
+ 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();
|
||||
+ /* QCA NSS ECM bonding support - End */
|
||||
+
|
||||
bond_sysfs_slave_del(slave);
|
||||
|
||||
/* recompute stats just before removing the slave */
|
||||
@@ -2708,6 +2769,8 @@ static void bond_miimon_commit(struct bo
|
||||
struct slave *slave, *primary, *active;
|
||||
bool do_failover = false;
|
||||
struct list_head *iter;
|
||||
+ struct net_device *slave_dev = NULL; /* QCA NSS ECM bonding support */
|
||||
+ struct bond_cb *lag_cb_main; /* QCA NSS ECM bonding support */
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
@@ -2747,6 +2810,12 @@ static void bond_miimon_commit(struct bo
|
||||
bond_set_active_slave(slave);
|
||||
}
|
||||
|
||||
+ /* QCA NSS ECM bonding support - Start */
|
||||
+ if ((bond->params.mode == BOND_MODE_XOR) &&
|
||||
+ (!slave_dev))
|
||||
+ slave_dev = slave->dev;
|
||||
+ /* QCA NSS ECM bonding support - End */
|
||||
+
|
||||
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");
|
||||
@@ -2795,6 +2864,16 @@ static void bond_miimon_commit(struct bo
|
||||
unblock_netpoll_tx();
|
||||
}
|
||||
|
||||
+ /* QCA NSS ECM bonding support - Start */
|
||||
+ 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();
|
||||
+ /* QCA NSS ECM bonding support - End */
|
||||
+
|
||||
bond_set_carrier(bond);
|
||||
}
|
||||
|
||||
@@ -4047,8 +4126,219 @@ 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]; /* QCA NSS ECM bonding support */
|
||||
+}
|
||||
+
|
||||
+/* QCA NSS ECM bonding support - Start */
|
||||
+/* 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;
|
||||
+}
|
||||
+/* QCA NSS ECM bonding support - End */
|
||||
|
||||
static bool bond_flow_ip(struct sk_buff *skb, struct flow_keys *fk, const void *data,
|
||||
int hlen, __be16 l2_proto, int *nhoff, int *ip_proto, bool l34)
|
||||
@@ -5177,15 +5467,18 @@ 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;
|
||||
+ /* QCA NSS ECM bonding support - Start */
|
||||
+ 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);
|
||||
+ /* QCA NSS ECM bonding support - End */
|
||||
}
|
||||
|
||||
/* in broadcast mode, we send everything to all usable interfaces. */
|
||||
@@ -5435,8 +5728,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); /* QCA NSS ECM bonding support */
|
||||
+ case BOND_MODE_8023AD:
|
||||
return bond_3ad_xor_xmit(skb, dev);
|
||||
case BOND_MODE_BROADCAST:
|
||||
return bond_xmit_broadcast(skb, dev);
|
||||
--- a/include/net/bond_3ad.h
|
||||
+++ b/include/net/bond_3ad.h
|
||||
@@ -302,8 +302,15 @@ 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);
|
||||
+/* QCA NSS ECM bonding support */
|
||||
+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);
|
||||
+/* QCA NSS ECM bonding support */
|
||||
+
|
||||
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);
|
||||
#endif /* _NET_BOND_3AD_H */
|
||||
-
|
||||
--- 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; /* QCA NSS ECM bonding support */
|
||||
+
|
||||
#ifdef CONFIG_NET_POLL_CONTROLLER
|
||||
extern atomic_t netpoll_block_tx;
|
||||
|
||||
@@ -653,6 +655,7 @@ struct bond_net {
|
||||
|
||||
int bond_rcv_validate(const struct sk_buff *skb, struct bonding *bond, struct slave *slave);
|
||||
netdev_tx_t bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_device *slave_dev);
|
||||
+int bond_get_id(struct net_device *bond_dev); /* QCA NSS ECM bonding support */
|
||||
int bond_create(struct net *net, const char *name);
|
||||
int bond_create_sysfs(struct bond_net *net);
|
||||
void bond_destroy_sysfs(struct bond_net *net);
|
||||
@@ -684,6 +687,13 @@ 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);
|
||||
+/* QCA NSS ECM bonding support - Start */
|
||||
+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);
|
||||
+/* QCA NSS ECM bonding support - End */
|
||||
+
|
||||
void bond_work_init_all(struct bonding *bond);
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
@@ -788,4 +798,18 @@ static inline netdev_tx_t bond_tx_drop(s
|
||||
return NET_XMIT_DROP;
|
||||
}
|
||||
|
||||
+/* QCA NSS ECM bonding support - Start */
|
||||
+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);
|
||||
+/* QCA NSS ECM bonding support - End */
|
||||
+
|
||||
#endif /* _NET_BONDING_H */
|
|
@ -0,0 +1,96 @@
|
|||
--- a/include/linux/if_macvlan.h
|
||||
+++ b/include/linux/if_macvlan.h
|
||||
@@ -15,6 +15,13 @@ struct macvlan_port;
|
||||
#define MACVLAN_MC_FILTER_BITS 8
|
||||
#define MACVLAN_MC_FILTER_SZ (1 << MACVLAN_MC_FILTER_BITS)
|
||||
|
||||
+/* QCA NSS ECM Support - Start */
|
||||
+/*
|
||||
+ * 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);
|
||||
+/* QCA NSS ECM Support - End */
|
||||
+
|
||||
struct macvlan_dev {
|
||||
struct net_device *dev;
|
||||
struct list_head list;
|
||||
@@ -35,6 +42,7 @@ struct macvlan_dev {
|
||||
#ifdef CONFIG_NET_POLL_CONTROLLER
|
||||
struct netpoll *netpoll;
|
||||
#endif
|
||||
+ macvlan_offload_stats_update_cb_t offload_stats_update; /* QCA NSS ECM support */
|
||||
};
|
||||
|
||||
static inline void macvlan_count_rx(const struct macvlan_dev *vlan,
|
||||
@@ -107,4 +115,26 @@ static inline int macvlan_release_l2fw_o
|
||||
macvlan->accel_priv = NULL;
|
||||
return dev_uc_add(macvlan->lowerdev, dev->dev_addr);
|
||||
}
|
||||
+
|
||||
+/* QCA NSS ECM Support - Start */
|
||||
+#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;
|
||||
+}
|
||||
+#endif
|
||||
+/* QCA NSS ECM Support - End */
|
||||
#endif /* _LINUX_IF_MACVLAN_H */
|
||||
--- a/drivers/net/macvlan.c
|
||||
+++ b/drivers/net/macvlan.c
|
||||
@@ -960,6 +960,34 @@ static void macvlan_uninit(struct net_de
|
||||
macvlan_port_destroy(port->dev);
|
||||
}
|
||||
|
||||
+/* QCA NSS ECM Support - Start */
|
||||
+/* 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);
|
||||
+}
|
||||
+/* QCA NSS ECM Support - End */
|
||||
+
|
||||
static void macvlan_dev_get_stats64(struct net_device *dev,
|
||||
struct rtnl_link_stats64 *stats)
|
||||
{
|
||||
@@ -1506,6 +1534,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; /* QCA NSS ECM Support */
|
||||
|
||||
vlan->mode = MACVLAN_MODE_VEPA;
|
||||
if (data && data[IFLA_MACVLAN_MODE])
|
|
@ -0,0 +1,154 @@
|
|||
--- 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/include/net/netfilter/nf_conntrack_extend.h
|
||||
+++ b/include/net/netfilter/nf_conntrack_extend.h
|
||||
@@ -31,6 +31,10 @@ 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, /* QCA NSS ECM support */
|
||||
+#endif
|
||||
+
|
||||
NF_CT_EXT_NUM,
|
||||
};
|
||||
|
||||
--- a/net/netfilter/nf_conntrack_extend.c
|
||||
+++ b/net/netfilter/nf_conntrack_extend.c
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <net/netfilter/nf_conntrack_labels.h>
|
||||
#include <net/netfilter/nf_conntrack_synproxy.h>
|
||||
#include <net/netfilter/nf_conntrack_act_ct.h>
|
||||
+#include <net/netfilter/nf_conntrack_dscpremark_ext.h>
|
||||
#include <net/netfilter/nf_nat.h>
|
||||
|
||||
#define NF_CT_EXT_PREALLOC 128u /* conntrack events are on by default */
|
||||
@@ -54,6 +55,9 @@ 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 +90,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
|
||||
;
|
||||
}
|
||||
|
||||
--- a/net/netfilter/Makefile
|
||||
+++ b/net/netfilter/Makefile
|
||||
@@ -15,6 +15,7 @@ nf_conntrack-$(CONFIG_NF_CONNTRACK_OVS)
|
||||
nf_conntrack-$(CONFIG_NF_CT_PROTO_DCCP) += nf_conntrack_proto_dccp.o
|
||||
nf_conntrack-$(CONFIG_NF_CT_PROTO_SCTP) += nf_conntrack_proto_sctp.o
|
||||
nf_conntrack-$(CONFIG_NF_CT_PROTO_GRE) += nf_conntrack_proto_gre.o
|
||||
+nf_conntrack-$(CONFIG_NF_CONNTRACK_DSCPREMARK_EXT) += nf_conntrack_dscpremark_ext.o
|
||||
ifeq ($(CONFIG_NF_CONNTRACK),m)
|
||||
nf_conntrack-$(CONFIG_DEBUG_INFO_BTF_MODULES) += nf_conntrack_bpf.o
|
||||
else ifeq ($(CONFIG_NF_CONNTRACK),y)
|
||||
--- 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;
|
||||
}
|
|
@ -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
|
||||
@@ -3867,10 +3867,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;
|
||||
@@ -3892,9 +3888,6 @@ static int __ip6_del_rt(struct fib6_info
|
||||
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;
|
||||
@@ -4500,6 +4493,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;
|
||||
}
|
||||
|
||||
@@ -5518,11 +5515,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,
|
||||
@@ -5539,9 +5542,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 */
|
|
@ -0,0 +1,92 @@
|
|||
From 3c17a0e1112be70071e98d5208da5b55dcec20a6 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Casey <simon501098c@gmail.com>
|
||||
Date: Wed, 2 Feb 2022 19:37:29 +0100
|
||||
Subject: [PATCH] Update 607-qca-add-add-nss-bridge-mgr-support.patch for kernel 5.15
|
||||
|
||||
---
|
||||
include/linux/if_bridge.h | 4 ++++
|
||||
net/bridge/br_fdb.c | 25 +++++++++++++++++++++----
|
||||
2 files changed, 25 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/include/linux/if_bridge.h
|
||||
+++ b/include/linux/if_bridge.h
|
||||
@@ -254,4 +254,8 @@ typedef struct net_bridge_port *br_get_d
|
||||
extern br_get_dst_hook_t __rcu *br_get_dst_hook;
|
||||
/* QCA NSS ECM support - End */
|
||||
|
||||
+/* QCA NSS bridge-mgr support - Start */
|
||||
+extern struct net_device *br_fdb_bridge_dev_get_and_hold(struct net_bridge *br);
|
||||
+/* QCA NSS bridge-mgr support - End */
|
||||
+
|
||||
#endif
|
||||
--- a/net/bridge/br_fdb.c
|
||||
+++ b/net/bridge/br_fdb.c
|
||||
@@ -576,7 +576,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]; /* QCA NSS ECM support */
|
||||
+ struct br_fdb_event fdb_event; /* QCA NSS bridge-mgr support */
|
||||
|
||||
/* this part is tricky, in order to avoid blocking learning and
|
||||
* consequently forwarding, we rely on rcu to delete objects with
|
||||
@@ -604,12 +604,13 @@ 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);
|
||||
/* QCA NSS ECM support - Start */
|
||||
atomic_notifier_call_chain(
|
||||
&br_fdb_update_notifier_list, 0,
|
||||
- (void *)mac_addr);
|
||||
+ (void *)&fdb_event);
|
||||
/* QCA NSS ECM support - End */
|
||||
}
|
||||
spin_unlock_bh(&br->hash_lock);
|
||||
@@ -907,10 +908,21 @@ static bool __fdb_mark_active(struct net
|
||||
test_and_clear_bit(BR_FDB_NOTIFY_INACTIVE, &fdb->flags));
|
||||
}
|
||||
|
||||
+/* QCA NSS bridge-mgr support - Start */
|
||||
+/* 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);
|
||||
+/* QCA NSS bridge-mgr support - End */
|
||||
+
|
||||
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; /* QCA NSS bridge-mgr support */
|
||||
|
||||
/* some users want to always flood. */
|
||||
if (hold_time(br) == 0)
|
||||
@@ -936,6 +948,12 @@ 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);
|
||||
+ /* QCA NSS bridge-mgr support - Start */
|
||||
+ ether_addr_copy(fdb_event.addr, addr);
|
||||
+ fdb_event.br = br;
|
||||
+ fdb_event.orig_dev = fdb->dst->dev;
|
||||
+ fdb_event.dev = source->dev;
|
||||
+ /* QCA NSS bridge-mgr support - End */
|
||||
WRITE_ONCE(fdb->dst, source);
|
||||
fdb_modified = true;
|
||||
/* Take over HW learned entry */
|
||||
@@ -952,7 +970,7 @@ void br_fdb_update(struct net_bridge *br
|
||||
/* QCA NSS ECM support - Start */
|
||||
atomic_notifier_call_chain(
|
||||
&br_fdb_update_notifier_list,
|
||||
- 0, (void *)addr);
|
||||
+ 0, (void *)&fdb_event);
|
||||
/* QCA NSS ECM support - End */
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
--- 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, /* QCA NSS Qdisc IGS Support */
|
||||
/* other actions go here */
|
||||
__TCA_ID_MAX = 255
|
||||
};
|
||||
@@ -817,4 +818,14 @@ enum {
|
||||
TCF_EM_OPND_LT
|
||||
};
|
||||
|
||||
+/* QCA NSS Qdisc Support - Start */
|
||||
+#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)
|
||||
+/* QCA NSS Qdisc Support - End */
|
||||
+
|
||||
#endif
|
|
@ -0,0 +1,463 @@
|
|||
--- 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->rx_stats.sync);
|
||||
+ txp->rx_stats.packets += u64_stats_read(&offload_stats->rx_packets);
|
||||
+ txp->rx_stats.bytes += u64_stats_read(&offload_stats->rx_bytes);
|
||||
+ txp->tx_stats.packets += u64_stats_read(&offload_stats->tx_packets);
|
||||
+ txp->tx_stats.bytes += u64_stats_read(&offload_stats->tx_bytes);
|
||||
+ u64_stats_update_end(&txp->rx_stats.sync);
|
||||
+}
|
||||
+EXPORT_SYMBOL(ifb_update_offload_stats);
|
||||
+
|
||||
static void ifb_stats64(struct net_device *dev,
|
||||
struct rtnl_link_stats64 *stats)
|
||||
{
|
||||
@@ -326,6 +351,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
|
||||
@@ -4696,6 +4696,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
|
||||
@@ -5222,6 +5231,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/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)
|
||||
|
||||
+/* QCA NSS Clients Support - Start */
|
||||
+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 */
|
||||
+};
|
||||
+/* QCA NSS Clients Support - End */
|
||||
#endif
|
||||
--- a/net/sched/sch_api.c
|
||||
+++ b/net/sched/sch_api.c
|
||||
@@ -314,6 +314,7 @@ struct Qdisc *qdisc_lookup(struct net_de
|
||||
out:
|
||||
return q;
|
||||
}
|
||||
+EXPORT_SYMBOL(qdisc_lookup);
|
||||
|
||||
struct Qdisc *qdisc_lookup_rcu(struct net_device *dev, u32 handle)
|
||||
{
|
||||
@@ -2389,4 +2390,26 @@ static int __init pktsched_init(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
+/* QCA NSS Qdisc Support - Start */
|
||||
+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);
|
||||
+/* QCA NSS Qdisc Support - End */
|
||||
+
|
||||
subsys_initcall(pktsched_init);
|
||||
--- a/net/sched/sch_generic.c
|
||||
+++ b/net/sched/sch_generic.c
|
||||
@@ -1069,6 +1069,7 @@ static void __qdisc_destroy(struct Qdisc
|
||||
|
||||
call_rcu(&qdisc->rcu, qdisc_free_cb);
|
||||
}
|
||||
+EXPORT_SYMBOL(qdisc_destroy);
|
||||
|
||||
void qdisc_destroy(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;
|
||||
@@ -751,6 +752,42 @@ static inline bool skb_skip_tc_classify(
|
||||
return false;
|
||||
}
|
||||
|
||||
+/* QCA NSS Qdisc Support - Start */
|
||||
+/*
|
||||
+ * 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;
|
||||
+}
|
||||
+/* QCA NSS Qdisc Support - End */
|
||||
+
|
||||
/* 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 +1360,9 @@ static inline void qdisc_synchronize(con
|
||||
msleep(1);
|
||||
}
|
||||
|
||||
+/* QCA NSS Qdisc Support - Start */
|
||||
+void qdisc_destroy(struct Qdisc *qdisc);
|
||||
+void tcf_destroy_chain(struct tcf_proto __rcu **fl);
|
||||
+/* QCA NSS Qdisc Support - End */
|
||||
+
|
||||
#endif
|
||||
--- a/include/linux/skbuff.h
|
||||
+++ b/include/linux/skbuff.h
|
||||
@@ -764,6 +764,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
|
||||
@@ -945,6 +946,9 @@ struct sk_buff {
|
||||
__u8 tc_at_ingress:1; /* See TC_AT_INGRESS_MASK */
|
||||
__u8 tc_skip_classify:1;
|
||||
#endif
|
||||
+#ifdef CONFIG_NET_CLS_ACT
|
||||
+ __u8 tc_skip_classify_offload:1; /* QCA NSS Qdisc Support */
|
||||
+#endif
|
||||
__u8 remcsum_offload:1;
|
||||
__u8 csum_complete_sw:1;
|
||||
__u8 csum_level:2;
|
|
@ -0,0 +1,46 @@
|
|||
--- a/net/l2tp/l2tp_core.c
|
||||
+++ b/net/l2tp/l2tp_core.c
|
||||
@@ -398,6 +398,31 @@ err_tlock:
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(l2tp_session_register);
|
||||
|
||||
+void l2tp_stats_update(struct l2tp_tunnel *tunnel,
|
||||
+ struct l2tp_session *session,
|
||||
+ struct l2tp_stats *stats)
|
||||
+{
|
||||
+ atomic_long_add(atomic_long_read(&stats->rx_packets),
|
||||
+ &tunnel->stats.rx_packets);
|
||||
+ atomic_long_add(atomic_long_read(&stats->rx_bytes),
|
||||
+ &tunnel->stats.rx_bytes);
|
||||
+ atomic_long_add(atomic_long_read(&stats->tx_packets),
|
||||
+ &tunnel->stats.tx_packets);
|
||||
+ atomic_long_add(atomic_long_read(&stats->tx_bytes),
|
||||
+ &tunnel->stats.tx_bytes);
|
||||
+
|
||||
+ atomic_long_add(atomic_long_read(&stats->rx_packets),
|
||||
+ &session->stats.rx_packets);
|
||||
+ atomic_long_add(atomic_long_read(&stats->rx_bytes),
|
||||
+ &session->stats.rx_bytes);
|
||||
+ atomic_long_add(atomic_long_read(&stats->tx_packets),
|
||||
+ &session->stats.tx_packets);
|
||||
+ atomic_long_add(atomic_long_read(&stats->tx_bytes),
|
||||
+ &session->stats.tx_bytes);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(l2tp_stats_update);
|
||||
+
|
||||
+
|
||||
/*****************************************************************************
|
||||
* Receive data handling
|
||||
*****************************************************************************/
|
||||
--- a/net/l2tp/l2tp_core.h
|
||||
+++ b/net/l2tp/l2tp_core.h
|
||||
@@ -232,6 +232,9 @@ struct l2tp_session *l2tp_session_get_nt
|
||||
struct l2tp_session *l2tp_session_get_by_ifname(const struct net *net,
|
||||
const char *ifname);
|
||||
|
||||
+void l2tp_stats_update(struct l2tp_tunnel *tunnel, struct l2tp_session *session,
|
||||
+ struct l2tp_stats *stats);
|
||||
+
|
||||
/* Tunnel and session lifetime management.
|
||||
* Creation of a new instance is a two-step process: create, then register.
|
||||
* Destruction is triggered using the *_delete functions, and completes asynchronously.
|
|
@ -0,0 +1,478 @@
|
|||
--- a/include/linux/if_pppox.h
|
||||
+++ b/include/linux/if_pppox.h
|
||||
@@ -36,6 +36,7 @@ struct pptp_opt {
|
||||
u32 ack_sent, ack_recv;
|
||||
u32 seq_sent, seq_recv;
|
||||
int ppp_flags;
|
||||
+ bool pptp_offload_mode;
|
||||
};
|
||||
#include <net/sock.h>
|
||||
|
||||
@@ -100,8 +101,40 @@ struct pppoe_channel_ops {
|
||||
int (*get_addressing)(struct ppp_channel *, struct pppoe_opt *);
|
||||
};
|
||||
|
||||
+/* PPTP client callback */
|
||||
+typedef int (*pptp_gre_seq_offload_callback_t)(struct sk_buff *skb,
|
||||
+ struct net_device *pptp_dev);
|
||||
+
|
||||
/* Return PPPoE channel specific addressing information */
|
||||
extern int pppoe_channel_addressing_get(struct ppp_channel *chan,
|
||||
struct pppoe_opt *addressing);
|
||||
|
||||
+/* Lookup PPTP session info and return PPTP session using sip, dip and local call id */
|
||||
+extern int pptp_session_find_by_src_callid(struct pptp_opt *opt, __be16 src_call_id,
|
||||
+ __be32 daddr, __be32 saddr);
|
||||
+
|
||||
+/* Lookup PPTP session info and return PPTP session using dip and peer call id */
|
||||
+extern int pptp_session_find(struct pptp_opt *opt, __be16 peer_call_id,
|
||||
+ __be32 peer_ip_addr);
|
||||
+
|
||||
+/* Return PPTP session information given the channel */
|
||||
+extern void pptp_channel_addressing_get(struct pptp_opt *opt,
|
||||
+ struct ppp_channel *chan);
|
||||
+
|
||||
+/* Enable the PPTP session offload flag */
|
||||
+extern int pptp_session_enable_offload_mode(__be16 peer_call_id,
|
||||
+ __be32 peer_ip_addr);
|
||||
+
|
||||
+/* Disable the PPTP session offload flag */
|
||||
+extern int pptp_session_disable_offload_mode(__be16 peer_call_id,
|
||||
+ __be32 peer_ip_addr);
|
||||
+
|
||||
+/* Register the PPTP GRE packets sequence number offload callback */
|
||||
+extern int
|
||||
+pptp_register_gre_seq_offload_callback(pptp_gre_seq_offload_callback_t
|
||||
+ pptp_client_cb);
|
||||
+
|
||||
+/* Unregister the PPTP GRE packets sequence number offload callback */
|
||||
+extern void pptp_unregister_gre_seq_offload_callback(void);
|
||||
+
|
||||
#endif /* !(__LINUX_IF_PPPOX_H) */
|
||||
--- a/drivers/net/ppp/ppp_generic.c
|
||||
+++ b/drivers/net/ppp/ppp_generic.c
|
||||
@@ -2973,6 +2973,20 @@ char *ppp_dev_name(struct ppp_channel *c
|
||||
return name;
|
||||
}
|
||||
|
||||
+/* Return the PPP net device index */
|
||||
+int ppp_dev_index(struct ppp_channel *chan)
|
||||
+{
|
||||
+ struct channel *pch = chan->ppp;
|
||||
+ int ifindex = 0;
|
||||
+
|
||||
+ if (pch) {
|
||||
+ read_lock_bh(&pch->upl);
|
||||
+ if (pch->ppp && pch->ppp->dev)
|
||||
+ ifindex = pch->ppp->dev->ifindex;
|
||||
+ read_unlock_bh(&pch->upl);
|
||||
+ }
|
||||
+ return ifindex;
|
||||
+}
|
||||
|
||||
/*
|
||||
* Disconnect a channel from the generic layer.
|
||||
@@ -3681,6 +3695,28 @@ void ppp_update_stats(struct net_device
|
||||
ppp_recv_unlock(ppp);
|
||||
}
|
||||
|
||||
+/* Returns true if Compression is enabled on PPP device
|
||||
+ */
|
||||
+bool ppp_is_cp_enabled(struct net_device *dev)
|
||||
+{
|
||||
+ struct ppp *ppp;
|
||||
+ bool flag = false;
|
||||
+
|
||||
+ if (!dev)
|
||||
+ return false;
|
||||
+
|
||||
+ if (dev->type != ARPHRD_PPP)
|
||||
+ return false;
|
||||
+
|
||||
+ ppp = netdev_priv(dev);
|
||||
+ ppp_lock(ppp);
|
||||
+ flag = !!(ppp->xstate & SC_COMP_RUN) || !!(ppp->rstate & SC_DECOMP_RUN);
|
||||
+ ppp_unlock(ppp);
|
||||
+
|
||||
+ return flag;
|
||||
+}
|
||||
+EXPORT_SYMBOL(ppp_is_cp_enabled);
|
||||
+
|
||||
/* Returns >0 if the device is a multilink PPP netdevice, 0 if not or < 0 if
|
||||
* the device is not PPP.
|
||||
*/
|
||||
@@ -3872,6 +3908,7 @@ EXPORT_SYMBOL(ppp_unregister_channel);
|
||||
EXPORT_SYMBOL(ppp_channel_index);
|
||||
EXPORT_SYMBOL(ppp_unit_number);
|
||||
EXPORT_SYMBOL(ppp_dev_name);
|
||||
+EXPORT_SYMBOL(ppp_dev_index);
|
||||
EXPORT_SYMBOL(ppp_input);
|
||||
EXPORT_SYMBOL(ppp_input_error);
|
||||
EXPORT_SYMBOL(ppp_output_wakeup);
|
||||
--- a/include/linux/ppp_channel.h
|
||||
+++ b/include/linux/ppp_channel.h
|
||||
@@ -84,6 +84,9 @@ extern void ppp_unregister_channel(struc
|
||||
/* Get the channel number for a channel */
|
||||
extern int ppp_channel_index(struct ppp_channel *);
|
||||
|
||||
+/* Get the device index associated with a channel, or 0, if none */
|
||||
+extern int ppp_dev_index(struct ppp_channel *);
|
||||
+
|
||||
/* Get the unit number associated with a channel, or -1 if none */
|
||||
extern int ppp_unit_number(struct ppp_channel *);
|
||||
|
||||
@@ -116,6 +119,7 @@ extern int ppp_hold_channels(struct net_
|
||||
/* Test if ppp xmit lock is locked */
|
||||
extern bool ppp_is_xmit_locked(struct net_device *dev);
|
||||
|
||||
+bool ppp_is_cp_enabled(struct net_device *dev);
|
||||
/* Test if the ppp device is a multi-link ppp device */
|
||||
extern int ppp_is_multilink(struct net_device *dev);
|
||||
|
||||
--- a/drivers/net/ppp/pptp.c
|
||||
+++ b/drivers/net/ppp/pptp.c
|
||||
@@ -50,6 +50,8 @@ static struct proto pptp_sk_proto __read
|
||||
static const struct ppp_channel_ops pptp_chan_ops;
|
||||
static const struct proto_ops pptp_ops;
|
||||
|
||||
+static pptp_gre_seq_offload_callback_t __rcu pptp_gre_offload_xmit_cb;
|
||||
+
|
||||
static struct pppox_sock *lookup_chan(u16 call_id, __be32 s_addr)
|
||||
{
|
||||
struct pppox_sock *sock;
|
||||
@@ -91,6 +93,79 @@ static int lookup_chan_dst(u16 call_id,
|
||||
return i < MAX_CALLID;
|
||||
}
|
||||
|
||||
+/* Search a pptp session based on local call id, local and remote ip address */
|
||||
+static int lookup_session_src(struct pptp_opt *opt, u16 call_id, __be32 daddr, __be32 saddr)
|
||||
+{
|
||||
+ struct pppox_sock *sock;
|
||||
+ int i = 1;
|
||||
+
|
||||
+ rcu_read_lock();
|
||||
+ for_each_set_bit_from(i, callid_bitmap, MAX_CALLID) {
|
||||
+ sock = rcu_dereference(callid_sock[i]);
|
||||
+ if (!sock)
|
||||
+ continue;
|
||||
+
|
||||
+ if (sock->proto.pptp.src_addr.call_id == call_id &&
|
||||
+ sock->proto.pptp.dst_addr.sin_addr.s_addr == daddr &&
|
||||
+ sock->proto.pptp.src_addr.sin_addr.s_addr == saddr) {
|
||||
+ sock_hold(sk_pppox(sock));
|
||||
+ memcpy(opt, &sock->proto.pptp, sizeof(struct pptp_opt));
|
||||
+ sock_put(sk_pppox(sock));
|
||||
+ rcu_read_unlock();
|
||||
+ return 0;
|
||||
+ }
|
||||
+ }
|
||||
+ rcu_read_unlock();
|
||||
+ return -EINVAL;
|
||||
+}
|
||||
+
|
||||
+/* Search a pptp session based on peer call id and peer ip address */
|
||||
+static int lookup_session_dst(struct pptp_opt *opt, u16 call_id, __be32 d_addr)
|
||||
+{
|
||||
+ struct pppox_sock *sock;
|
||||
+ int i = 1;
|
||||
+
|
||||
+ rcu_read_lock();
|
||||
+ for_each_set_bit_from(i, callid_bitmap, MAX_CALLID) {
|
||||
+ sock = rcu_dereference(callid_sock[i]);
|
||||
+ if (!sock)
|
||||
+ continue;
|
||||
+
|
||||
+ if (sock->proto.pptp.dst_addr.call_id == call_id &&
|
||||
+ sock->proto.pptp.dst_addr.sin_addr.s_addr == d_addr) {
|
||||
+ sock_hold(sk_pppox(sock));
|
||||
+ memcpy(opt, &sock->proto.pptp, sizeof(struct pptp_opt));
|
||||
+ sock_put(sk_pppox(sock));
|
||||
+ rcu_read_unlock();
|
||||
+ return 0;
|
||||
+ }
|
||||
+ }
|
||||
+ rcu_read_unlock();
|
||||
+ return -EINVAL;
|
||||
+}
|
||||
+
|
||||
+/* If offload mode set then this function sends all packets to
|
||||
+ * offload module instead of network stack
|
||||
+ */
|
||||
+static int pptp_client_skb_xmit(struct sk_buff *skb,
|
||||
+ struct net_device *pptp_dev)
|
||||
+{
|
||||
+ pptp_gre_seq_offload_callback_t pptp_gre_offload_cb_f;
|
||||
+ int ret;
|
||||
+
|
||||
+ rcu_read_lock();
|
||||
+ pptp_gre_offload_cb_f = rcu_dereference(pptp_gre_offload_xmit_cb);
|
||||
+
|
||||
+ if (!pptp_gre_offload_cb_f) {
|
||||
+ rcu_read_unlock();
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ ret = pptp_gre_offload_cb_f(skb, pptp_dev);
|
||||
+ rcu_read_unlock();
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
static int add_chan(struct pppox_sock *sock,
|
||||
struct pptp_addr *sa)
|
||||
{
|
||||
@@ -136,7 +211,7 @@ static struct rtable *pptp_route_output(
|
||||
struct net *net;
|
||||
|
||||
net = sock_net(sk);
|
||||
- flowi4_init_output(fl4, sk->sk_bound_dev_if, sk->sk_mark, 0,
|
||||
+ flowi4_init_output(fl4, 0, sk->sk_mark, 0,
|
||||
RT_SCOPE_UNIVERSE, IPPROTO_GRE, 0,
|
||||
po->proto.pptp.dst_addr.sin_addr.s_addr,
|
||||
po->proto.pptp.src_addr.sin_addr.s_addr,
|
||||
@@ -163,8 +238,11 @@ static int pptp_xmit(struct ppp_channel
|
||||
|
||||
struct rtable *rt;
|
||||
struct net_device *tdev;
|
||||
+ struct net_device *pptp_dev;
|
||||
struct iphdr *iph;
|
||||
int max_headroom;
|
||||
+ int pptp_ifindex;
|
||||
+ int ret;
|
||||
|
||||
if (sk_pppox(po)->sk_state & PPPOX_DEAD)
|
||||
goto tx_error;
|
||||
@@ -258,7 +336,32 @@ static int pptp_xmit(struct ppp_channel
|
||||
ip_select_ident(net, skb, NULL);
|
||||
ip_send_check(iph);
|
||||
|
||||
- ip_local_out(net, skb->sk, skb);
|
||||
+ pptp_ifindex = ppp_dev_index(chan);
|
||||
+
|
||||
+ /* set incoming interface as the ppp interface */
|
||||
+ if (skb->skb_iif)
|
||||
+ skb->skb_iif = pptp_ifindex;
|
||||
+
|
||||
+ /* If the PPTP GRE seq number offload module is not enabled yet
|
||||
+ * then sends all PPTP GRE packets through linux network stack
|
||||
+ */
|
||||
+ if (!opt->pptp_offload_mode) {
|
||||
+ ip_local_out(net, skb->sk, skb);
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ pptp_dev = dev_get_by_index(&init_net, pptp_ifindex);
|
||||
+ if (!pptp_dev)
|
||||
+ goto tx_error;
|
||||
+
|
||||
+ /* If PPTP offload module is enabled then forward all PPTP GRE
|
||||
+ * packets to PPTP GRE offload module
|
||||
+ */
|
||||
+ ret = pptp_client_skb_xmit(skb, pptp_dev);
|
||||
+ dev_put(pptp_dev);
|
||||
+ if (ret < 0)
|
||||
+ goto tx_error;
|
||||
+
|
||||
return 1;
|
||||
|
||||
tx_error:
|
||||
@@ -314,6 +417,13 @@ static int pptp_rcv_core(struct sock *sk
|
||||
goto drop;
|
||||
|
||||
payload = skb->data + headersize;
|
||||
+
|
||||
+ /* If offload is enabled, we expect the offload module
|
||||
+ * to handle PPTP GRE sequence number checks
|
||||
+ */
|
||||
+ if (opt->pptp_offload_mode)
|
||||
+ goto allow_packet;
|
||||
+
|
||||
/* check for expected sequence number */
|
||||
if (seq < opt->seq_recv + 1 || WRAPPED(opt->seq_recv, seq)) {
|
||||
if ((payload[0] == PPP_ALLSTATIONS) && (payload[1] == PPP_UI) &&
|
||||
@@ -371,6 +481,7 @@ static int pptp_rcv(struct sk_buff *skb)
|
||||
if (po) {
|
||||
skb_dst_drop(skb);
|
||||
nf_reset_ct(skb);
|
||||
+ skb->skb_iif = ppp_dev_index(&po->chan);
|
||||
return sk_receive_skb(sk_pppox(po), skb, 0);
|
||||
}
|
||||
drop:
|
||||
@@ -473,7 +584,7 @@ static int pptp_connect(struct socket *s
|
||||
|
||||
opt->dst_addr = sp->sa_addr.pptp;
|
||||
sk->sk_state |= PPPOX_CONNECTED;
|
||||
-
|
||||
+ opt->pptp_offload_mode = false;
|
||||
end:
|
||||
release_sock(sk);
|
||||
return error;
|
||||
@@ -603,9 +714,169 @@ static int pptp_ppp_ioctl(struct ppp_cha
|
||||
return err;
|
||||
}
|
||||
|
||||
+/* pptp_channel_addressing_get()
|
||||
+ * Return PPTP channel specific addressing information.
|
||||
+ */
|
||||
+void pptp_channel_addressing_get(struct pptp_opt *opt, struct ppp_channel *chan)
|
||||
+{
|
||||
+ struct sock *sk;
|
||||
+ struct pppox_sock *po;
|
||||
+
|
||||
+ if (!opt)
|
||||
+ return;
|
||||
+
|
||||
+ sk = (struct sock *)chan->private;
|
||||
+ if (!sk)
|
||||
+ return;
|
||||
+
|
||||
+ sock_hold(sk);
|
||||
+
|
||||
+ /* This is very unlikely, but check the socket is connected state */
|
||||
+ if (unlikely(sock_flag(sk, SOCK_DEAD) ||
|
||||
+ !(sk->sk_state & PPPOX_CONNECTED))) {
|
||||
+ sock_put(sk);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ po = pppox_sk(sk);
|
||||
+ memcpy(opt, &po->proto.pptp, sizeof(struct pptp_opt));
|
||||
+ sock_put(sk);
|
||||
+}
|
||||
+EXPORT_SYMBOL(pptp_channel_addressing_get);
|
||||
+
|
||||
+/* pptp_session_find()
|
||||
+ * Search and return a PPTP session info based on peer callid and IP
|
||||
+ * address. The function accepts the parameters in network byte order.
|
||||
+ */
|
||||
+int pptp_session_find(struct pptp_opt *opt, __be16 peer_call_id,
|
||||
+ __be32 peer_ip_addr)
|
||||
+{
|
||||
+ if (!opt)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ return lookup_session_dst(opt, ntohs(peer_call_id), peer_ip_addr);
|
||||
+}
|
||||
+EXPORT_SYMBOL(pptp_session_find);
|
||||
+
|
||||
+/* pptp_session_find_by_src_callid()
|
||||
+ * Search and return a PPTP session info based on src callid and IP
|
||||
+ * address. The function accepts the parameters in network byte order.
|
||||
+ */
|
||||
+int pptp_session_find_by_src_callid(struct pptp_opt *opt, __be16 src_call_id,
|
||||
+ __be32 daddr, __be32 saddr)
|
||||
+{
|
||||
+ if (!opt)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ return lookup_session_src(opt, ntohs(src_call_id), daddr, saddr);
|
||||
+}
|
||||
+EXPORT_SYMBOL(pptp_session_find_by_src_callid);
|
||||
+
|
||||
+ /* Function to change the offload mode true/false for a PPTP session */
|
||||
+static int pptp_set_offload_mode(bool accel_mode,
|
||||
+ __be16 peer_call_id, __be32 peer_ip_addr)
|
||||
+{
|
||||
+ struct pppox_sock *sock;
|
||||
+ int i = 1;
|
||||
+
|
||||
+ rcu_read_lock();
|
||||
+ for_each_set_bit_from(i, callid_bitmap, MAX_CALLID) {
|
||||
+ sock = rcu_dereference(callid_sock[i]);
|
||||
+ if (!sock)
|
||||
+ continue;
|
||||
+
|
||||
+ if (sock->proto.pptp.dst_addr.call_id == peer_call_id &&
|
||||
+ sock->proto.pptp.dst_addr.sin_addr.s_addr == peer_ip_addr) {
|
||||
+ sock_hold(sk_pppox(sock));
|
||||
+ sock->proto.pptp.pptp_offload_mode = accel_mode;
|
||||
+ sock_put(sk_pppox(sock));
|
||||
+ rcu_read_unlock();
|
||||
+ return 0;
|
||||
+ }
|
||||
+ }
|
||||
+ rcu_read_unlock();
|
||||
+ return -EINVAL;
|
||||
+}
|
||||
+
|
||||
+/* Enable the PPTP session offload flag */
|
||||
+int pptp_session_enable_offload_mode(__be16 peer_call_id, __be32 peer_ip_addr)
|
||||
+{
|
||||
+ return pptp_set_offload_mode(true, peer_call_id, peer_ip_addr);
|
||||
+}
|
||||
+EXPORT_SYMBOL(pptp_session_enable_offload_mode);
|
||||
+
|
||||
+/* Disable the PPTP session offload flag */
|
||||
+int pptp_session_disable_offload_mode(__be16 peer_call_id, __be32 peer_ip_addr)
|
||||
+{
|
||||
+ return pptp_set_offload_mode(false, peer_call_id, peer_ip_addr);
|
||||
+}
|
||||
+EXPORT_SYMBOL(pptp_session_disable_offload_mode);
|
||||
+
|
||||
+/* Register the offload callback function on behalf of the module which
|
||||
+ * will own the sequence and acknowledgment number updates for all
|
||||
+ * PPTP GRE packets. All PPTP GRE packets are then transmitted to this
|
||||
+ * module after encapsulation in order to ensure the correct seq/ack
|
||||
+ * fields are set in the packets before transmission. This is required
|
||||
+ * when PPTP flows are offloaded to acceleration engines, in-order to
|
||||
+ * ensure consistency in sequence and ack numbers between PPTP control
|
||||
+ * (PPP LCP) and data packets
|
||||
+ */
|
||||
+int pptp_register_gre_seq_offload_callback(pptp_gre_seq_offload_callback_t
|
||||
+ pptp_gre_offload_cb)
|
||||
+{
|
||||
+ pptp_gre_seq_offload_callback_t pptp_gre_offload_cb_f;
|
||||
+
|
||||
+ rcu_read_lock();
|
||||
+ pptp_gre_offload_cb_f = rcu_dereference(pptp_gre_offload_xmit_cb);
|
||||
+
|
||||
+ if (pptp_gre_offload_cb_f) {
|
||||
+ rcu_read_unlock();
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ rcu_assign_pointer(pptp_gre_offload_xmit_cb, pptp_gre_offload_cb);
|
||||
+ rcu_read_unlock();
|
||||
+ return 0;
|
||||
+}
|
||||
+EXPORT_SYMBOL(pptp_register_gre_seq_offload_callback);
|
||||
+
|
||||
+/* Unregister the PPTP GRE packets sequence number offload callback */
|
||||
+void pptp_unregister_gre_seq_offload_callback(void)
|
||||
+{
|
||||
+ rcu_assign_pointer(pptp_gre_offload_xmit_cb, NULL);
|
||||
+}
|
||||
+EXPORT_SYMBOL(pptp_unregister_gre_seq_offload_callback);
|
||||
+
|
||||
+/* pptp_hold_chan() */
|
||||
+static void pptp_hold_chan(struct ppp_channel *chan)
|
||||
+{
|
||||
+ struct sock *sk = (struct sock *)chan->private;
|
||||
+
|
||||
+ sock_hold(sk);
|
||||
+}
|
||||
+
|
||||
+/* pptp_release_chan() */
|
||||
+static void pptp_release_chan(struct ppp_channel *chan)
|
||||
+{
|
||||
+ struct sock *sk = (struct sock *)chan->private;
|
||||
+
|
||||
+ sock_put(sk);
|
||||
+}
|
||||
+
|
||||
+/* pptp_get_channel_protocol()
|
||||
+ * Return the protocol type of the PPTP over PPP protocol
|
||||
+ */
|
||||
+static int pptp_get_channel_protocol(struct ppp_channel *chan)
|
||||
+{
|
||||
+ return PX_PROTO_PPTP;
|
||||
+}
|
||||
+
|
||||
static const struct ppp_channel_ops pptp_chan_ops = {
|
||||
.start_xmit = pptp_xmit,
|
||||
.ioctl = pptp_ppp_ioctl,
|
||||
+ .get_channel_protocol = pptp_get_channel_protocol,
|
||||
+ .hold = pptp_hold_chan,
|
||||
+ .release = pptp_release_chan,
|
||||
};
|
||||
|
||||
static struct proto pptp_sk_proto __read_mostly = {
|
|
@ -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
|
||||
@@ -558,4 +558,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
|
||||
@@ -2411,6 +2411,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
|
||||
@@ -1733,6 +1733,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 },
|
|
@ -0,0 +1,103 @@
|
|||
--- a/drivers/net/vxlan/vxlan_core.c
|
||||
+++ b/drivers/net/vxlan/vxlan_core.c
|
||||
@@ -29,6 +29,20 @@
|
||||
#include <net/vxlan.h>
|
||||
#include <net/nexthop.h>
|
||||
|
||||
+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);
|
||||
+
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
#include <net/ip6_tunnel.h>
|
||||
#include <net/ip6_checksum.h>
|
||||
@@ -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,
|
||||
@@ -2581,6 +2612,9 @@ void vxlan_xmit_one(struct sk_buff *skb,
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
+ /* Reset the skb_iif to Tunnels interface index */
|
||||
+ skb->skb_iif = dev->ifindex;
|
||||
+
|
||||
tos = ip_tunnel_ecn_encap(tos, old_iph, skb);
|
||||
ttl = ttl ? : ip4_dst_hoplimit(&rt->dst);
|
||||
err = vxlan_build_skb(skb, ndst, sizeof(struct iphdr),
|
||||
@@ -2652,6 +2686,9 @@ void vxlan_xmit_one(struct sk_buff *skb,
|
||||
if (err < 0)
|
||||
goto tx_error;
|
||||
|
||||
+ /* Reset the skb_iif to Tunnels interface index */
|
||||
+ skb->skb_iif = dev->ifindex;
|
||||
+
|
||||
udp_tunnel6_xmit_skb(ndst, sock6->sock->sk, skb, dev,
|
||||
&local_ip.sin6.sin6_addr,
|
||||
&dst->sin6.sin6_addr, tos, ttl,
|
||||
--- 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);
|
||||
|
|
@ -0,0 +1,368 @@
|
|||
--- a/include/linux/ppp_channel.h
|
||||
+++ b/include/linux/ppp_channel.h
|
||||
@@ -61,6 +61,51 @@ struct ppp_channel {
|
||||
};
|
||||
|
||||
#ifdef __KERNEL__
|
||||
+/* Call this to obtain the underlying protocol of the PPP channel,
|
||||
+ * e.g. PX_PROTO_OE
|
||||
+ */
|
||||
+extern int ppp_channel_get_protocol(struct ppp_channel *);
|
||||
+
|
||||
+/* Call this to hold a channel */
|
||||
+extern bool ppp_channel_hold(struct ppp_channel *);
|
||||
+
|
||||
+/* Call this to release a hold you have upon a channel */
|
||||
+extern void ppp_channel_release(struct ppp_channel *);
|
||||
+
|
||||
+/* Release hold on PPP channels */
|
||||
+extern void ppp_release_channels(struct ppp_channel *channels[],
|
||||
+ unsigned int chan_sz);
|
||||
+
|
||||
+/* Test if ppp xmit lock is locked */
|
||||
+extern bool ppp_is_xmit_locked(struct net_device *dev);
|
||||
+
|
||||
+/* Call this get protocol version */
|
||||
+extern int ppp_channel_get_proto_version(struct ppp_channel *);
|
||||
+
|
||||
+/* Get the device index associated with a channel, or 0, if none */
|
||||
+extern int ppp_dev_index(struct ppp_channel *);
|
||||
+
|
||||
+/* Hold PPP channels for the PPP device */
|
||||
+extern int ppp_hold_channels(struct net_device *dev,
|
||||
+ struct ppp_channel *channels[],
|
||||
+ unsigned int chan_sz);
|
||||
+extern int __ppp_hold_channels(struct net_device *dev,
|
||||
+ struct ppp_channel *channels[],
|
||||
+ unsigned int chan_sz);
|
||||
+
|
||||
+/* Test if the ppp device is a multi-link ppp device */
|
||||
+extern int ppp_is_multilink(struct net_device *dev);
|
||||
+extern int __ppp_is_multilink(struct net_device *dev);
|
||||
+
|
||||
+/* Update statistics of the PPP net_device by incrementing related
|
||||
+ * statistics field value with corresponding parameter
|
||||
+ */
|
||||
+extern void ppp_update_stats(struct net_device *dev, unsigned long rx_packets,
|
||||
+ unsigned long rx_bytes, unsigned long tx_packets,
|
||||
+ unsigned long tx_bytes, unsigned long rx_errors,
|
||||
+ unsigned long tx_errors, unsigned long rx_dropped,
|
||||
+ unsigned long tx_dropped);
|
||||
+
|
||||
/* Called by the channel when it can send some more data. */
|
||||
extern void ppp_output_wakeup(struct ppp_channel *);
|
||||
|
||||
@@ -148,5 +193,17 @@ extern void ppp_update_stats(struct net_
|
||||
* that ppp_unregister_channel returns.
|
||||
*/
|
||||
|
||||
+/* QCA NSS Clients Support - Start */
|
||||
+/* PPP channel connection event types */
|
||||
+#define PPP_CHANNEL_DISCONNECT 0
|
||||
+#define PPP_CHANNEL_CONNECT 1
|
||||
+
|
||||
+/* Register the PPP channel connect notifier */
|
||||
+extern void ppp_channel_connection_register_notify(struct notifier_block *nb);
|
||||
+
|
||||
+/* Unregister the PPP channel connect notifier */
|
||||
+extern void ppp_channel_connection_unregister_notify(struct notifier_block *nb);
|
||||
+/* QCA NSS Clients Support - End */
|
||||
+
|
||||
#endif /* __KERNEL__ */
|
||||
#endif
|
||||
--- a/include/linux/if_pppol2tp.h
|
||||
+++ b/include/linux/if_pppol2tp.h
|
||||
@@ -12,4 +12,30 @@
|
||||
#include <linux/in6.h>
|
||||
#include <uapi/linux/if_pppol2tp.h>
|
||||
|
||||
+/* QCA NSS ECM support - Start */
|
||||
+/*
|
||||
+ * Holds L2TP channel info
|
||||
+ */
|
||||
+struct pppol2tp_common_addr {
|
||||
+ int tunnel_version; /* v2 or v3 */
|
||||
+ __u32 local_tunnel_id, remote_tunnel_id; /* tunnel id */
|
||||
+ __u32 local_session_id, remote_session_id; /* session id */
|
||||
+ struct sockaddr_in local_addr, remote_addr; /* ip address and port */
|
||||
+};
|
||||
+
|
||||
+/*
|
||||
+ * L2TP channel operations
|
||||
+ */
|
||||
+struct pppol2tp_channel_ops {
|
||||
+ struct ppp_channel_ops ops; /* ppp channel ops */
|
||||
+};
|
||||
+
|
||||
+/*
|
||||
+ * exported function which calls pppol2tp channel's get addressing
|
||||
+ * function
|
||||
+ */
|
||||
+extern int pppol2tp_channel_addressing_get(struct ppp_channel *,
|
||||
+ struct pppol2tp_common_addr *);
|
||||
+/* QCA NSS ECM support - End */
|
||||
+
|
||||
#endif
|
||||
--- a/net/l2tp/l2tp_ppp.c
|
||||
+++ b/net/l2tp/l2tp_ppp.c
|
||||
@@ -123,9 +123,17 @@ struct pppol2tp_session {
|
||||
};
|
||||
|
||||
static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb);
|
||||
-
|
||||
-static const struct ppp_channel_ops pppol2tp_chan_ops = {
|
||||
- .start_xmit = pppol2tp_xmit,
|
||||
+static int pppol2tp_get_channel_protocol(struct ppp_channel *);
|
||||
+static int pppol2tp_get_channel_protocol_ver(struct ppp_channel *);
|
||||
+static void pppol2tp_hold_chan(struct ppp_channel *);
|
||||
+static void pppol2tp_release_chan(struct ppp_channel *);
|
||||
+
|
||||
+static const struct pppol2tp_channel_ops pppol2tp_chan_ops = {
|
||||
+ .ops.start_xmit = pppol2tp_xmit,
|
||||
+ .ops.get_channel_protocol = pppol2tp_get_channel_protocol,
|
||||
+ .ops.get_channel_protocol_ver = pppol2tp_get_channel_protocol_ver,
|
||||
+ .ops.hold = pppol2tp_hold_chan,
|
||||
+ .ops.release = pppol2tp_release_chan,
|
||||
};
|
||||
|
||||
static const struct proto_ops pppol2tp_ops;
|
||||
@@ -373,6 +381,13 @@ static int pppol2tp_xmit(struct ppp_chan
|
||||
skb->data[0] = PPP_ALLSTATIONS;
|
||||
skb->data[1] = PPP_UI;
|
||||
|
||||
+ /* QCA NSS ECM support - start */
|
||||
+ /* set incoming interface as the ppp interface */
|
||||
+ if ((skb->protocol == htons(ETH_P_IP)) ||
|
||||
+ (skb->protocol == htons(ETH_P_IPV6)))
|
||||
+ skb->skb_iif = ppp_dev_index(chan);
|
||||
+ /* QCA NSS ECM support - End */
|
||||
+
|
||||
local_bh_disable();
|
||||
l2tp_xmit_skb(session, skb);
|
||||
local_bh_enable();
|
||||
@@ -818,7 +833,7 @@ static int pppol2tp_connect(struct socke
|
||||
po->chan.hdrlen = PPPOL2TP_L2TP_HDR_SIZE_NOSEQ;
|
||||
|
||||
po->chan.private = sk;
|
||||
- po->chan.ops = &pppol2tp_chan_ops;
|
||||
+ po->chan.ops = (struct ppp_channel_ops *)&pppol2tp_chan_ops.ops;
|
||||
po->chan.mtu = pppol2tp_tunnel_mtu(tunnel);
|
||||
|
||||
error = ppp_register_net_channel(sock_net(sk), &po->chan);
|
||||
@@ -1732,6 +1747,109 @@ static void __exit pppol2tp_exit(void)
|
||||
unregister_pernet_device(&pppol2tp_net_ops);
|
||||
}
|
||||
|
||||
+/* QCA NSS ECM support - Start */
|
||||
+/* pppol2tp_hold_chan() */
|
||||
+static void pppol2tp_hold_chan(struct ppp_channel *chan)
|
||||
+{
|
||||
+ struct sock *sk = (struct sock *)chan->private;
|
||||
+
|
||||
+ sock_hold(sk);
|
||||
+}
|
||||
+
|
||||
+/* pppol2tp_release_chan() */
|
||||
+static void pppol2tp_release_chan(struct ppp_channel *chan)
|
||||
+{
|
||||
+ struct sock *sk = (struct sock *)chan->private;
|
||||
+
|
||||
+ sock_put(sk);
|
||||
+}
|
||||
+
|
||||
+/* pppol2tp_get_channel_protocol()
|
||||
+ * Return the protocol type of the L2TP over PPP protocol
|
||||
+ */
|
||||
+static int pppol2tp_get_channel_protocol(struct ppp_channel *chan)
|
||||
+{
|
||||
+ return PX_PROTO_OL2TP;
|
||||
+}
|
||||
+
|
||||
+/* pppol2tp_get_channel_protocol_ver()
|
||||
+ * Return the protocol version of the L2TP over PPP protocol
|
||||
+ */
|
||||
+static int pppol2tp_get_channel_protocol_ver(struct ppp_channel *chan)
|
||||
+{
|
||||
+ struct sock *sk;
|
||||
+ struct l2tp_session *session;
|
||||
+ struct l2tp_tunnel *tunnel;
|
||||
+ int version = 0;
|
||||
+
|
||||
+ if (chan && chan->private)
|
||||
+ sk = (struct sock *)chan->private;
|
||||
+ else
|
||||
+ return -1;
|
||||
+
|
||||
+ /* Get session and tunnel contexts from the socket */
|
||||
+ session = pppol2tp_sock_to_session(sk);
|
||||
+ if (!session)
|
||||
+ return -1;
|
||||
+
|
||||
+ tunnel = session->tunnel;
|
||||
+ if (!tunnel) {
|
||||
+ sock_put(sk);
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ version = tunnel->version;
|
||||
+
|
||||
+ sock_put(sk);
|
||||
+
|
||||
+ return version;
|
||||
+}
|
||||
+
|
||||
+/* pppol2tp_get_addressing() */
|
||||
+static int pppol2tp_get_addressing(struct ppp_channel *chan,
|
||||
+ struct pppol2tp_common_addr *addr)
|
||||
+{
|
||||
+ struct sock *sk = (struct sock *)chan->private;
|
||||
+ struct l2tp_session *session;
|
||||
+ struct l2tp_tunnel *tunnel;
|
||||
+ struct inet_sock *isk = NULL;
|
||||
+ int err = -ENXIO;
|
||||
+
|
||||
+ /* Get session and tunnel contexts from the socket */
|
||||
+ session = pppol2tp_sock_to_session(sk);
|
||||
+ if (!session)
|
||||
+ return err;
|
||||
+
|
||||
+ tunnel = session->tunnel;
|
||||
+ if (!tunnel) {
|
||||
+ sock_put(sk);
|
||||
+ return err;
|
||||
+ }
|
||||
+ isk = inet_sk(tunnel->sock);
|
||||
+
|
||||
+ addr->local_tunnel_id = tunnel->tunnel_id;
|
||||
+ addr->remote_tunnel_id = tunnel->peer_tunnel_id;
|
||||
+ addr->local_session_id = session->session_id;
|
||||
+ addr->remote_session_id = session->peer_session_id;
|
||||
+
|
||||
+ addr->local_addr.sin_port = isk->inet_sport;
|
||||
+ addr->remote_addr.sin_port = isk->inet_dport;
|
||||
+ addr->local_addr.sin_addr.s_addr = isk->inet_saddr;
|
||||
+ addr->remote_addr.sin_addr.s_addr = isk->inet_daddr;
|
||||
+
|
||||
+ sock_put(sk);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/* pppol2tp_channel_addressing_get() */
|
||||
+int pppol2tp_channel_addressing_get(struct ppp_channel *chan,
|
||||
+ struct pppol2tp_common_addr *addr)
|
||||
+{
|
||||
+ return pppol2tp_get_addressing(chan, addr);
|
||||
+}
|
||||
+EXPORT_SYMBOL(pppol2tp_channel_addressing_get);
|
||||
+/* QCA NSS ECM support - End */
|
||||
+
|
||||
module_init(pppol2tp_init);
|
||||
module_exit(pppol2tp_exit);
|
||||
|
||||
--- a/drivers/net/ppp/ppp_generic.c
|
||||
+++ b/drivers/net/ppp/ppp_generic.c
|
||||
@@ -3743,6 +3743,32 @@ int ppp_is_multilink(struct net_device *
|
||||
}
|
||||
EXPORT_SYMBOL(ppp_is_multilink);
|
||||
|
||||
+/* __ppp_is_multilink()
|
||||
+ * Returns >0 if the device is a multilink PPP netdevice, 0 if not or < 0
|
||||
+ * if the device is not PPP. Caller should acquire ppp_lock before calling
|
||||
+ * this function
|
||||
+ */
|
||||
+int __ppp_is_multilink(struct net_device *dev)
|
||||
+{
|
||||
+ struct ppp *ppp;
|
||||
+ unsigned int flags;
|
||||
+
|
||||
+ if (!dev)
|
||||
+ return -1;
|
||||
+
|
||||
+ if (dev->type != ARPHRD_PPP)
|
||||
+ return -1;
|
||||
+
|
||||
+ ppp = netdev_priv(dev);
|
||||
+ flags = ppp->flags;
|
||||
+
|
||||
+ if (flags & SC_MULTILINK)
|
||||
+ return 1;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+EXPORT_SYMBOL(__ppp_is_multilink);
|
||||
+
|
||||
/* ppp_channel_get_protocol()
|
||||
* Call this to obtain the underlying protocol of the PPP channel,
|
||||
* e.g. PX_PROTO_OE
|
||||
@@ -3881,6 +3907,59 @@ int ppp_hold_channels(struct net_device
|
||||
}
|
||||
EXPORT_SYMBOL(ppp_hold_channels);
|
||||
|
||||
+/* __ppp_hold_channels()
|
||||
+ * Returns the PPP channels of the PPP device, storing each one into
|
||||
+ * channels[].
|
||||
+ *
|
||||
+ * channels[] has chan_sz elements.
|
||||
+ * This function returns the number of channels stored, up to chan_sz.
|
||||
+ * It will return < 0 if the device is not PPP.
|
||||
+ *
|
||||
+ * You MUST release the channels using ppp_release_channels().
|
||||
+ */
|
||||
+int __ppp_hold_channels(struct net_device *dev, struct ppp_channel *channels[],
|
||||
+ unsigned int chan_sz)
|
||||
+{
|
||||
+ struct ppp *ppp;
|
||||
+ int c;
|
||||
+ struct channel *pch;
|
||||
+
|
||||
+ if (!dev)
|
||||
+ return -1;
|
||||
+
|
||||
+ if (dev->type != ARPHRD_PPP)
|
||||
+ return -1;
|
||||
+
|
||||
+ ppp = netdev_priv(dev);
|
||||
+
|
||||
+ c = 0;
|
||||
+ list_for_each_entry(pch, &ppp->channels, clist) {
|
||||
+ struct ppp_channel *chan;
|
||||
+
|
||||
+ if (!pch->chan) {
|
||||
+ /* Channel is going / gone away */
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (c == chan_sz) {
|
||||
+ /* No space to record channel */
|
||||
+ return c;
|
||||
+ }
|
||||
+
|
||||
+ /* Hold the channel, if supported */
|
||||
+ chan = pch->chan;
|
||||
+ if (!chan->ops->hold)
|
||||
+ continue;
|
||||
+
|
||||
+ chan->ops->hold(chan);
|
||||
+
|
||||
+ /* Record the channel */
|
||||
+ channels[c++] = chan;
|
||||
+ }
|
||||
+ return c;
|
||||
+}
|
||||
+EXPORT_SYMBOL(__ppp_hold_channels);
|
||||
+
|
||||
/* ppp_release_channels()
|
||||
* Releases channels
|
||||
*/
|
||||
--- a/net/l2tp/l2tp_core.h
|
||||
+++ b/net/l2tp/l2tp_core.h
|
||||
@@ -235,6 +235,9 @@ struct l2tp_session *l2tp_session_get_by
|
||||
void l2tp_stats_update(struct l2tp_tunnel *tunnel, struct l2tp_session *session,
|
||||
struct l2tp_stats *stats);
|
||||
|
||||
+void l2tp_stats_update(struct l2tp_tunnel *tunnel, struct l2tp_session *session,
|
||||
+ struct l2tp_stats *stats);
|
||||
+
|
||||
/* Tunnel and session lifetime management.
|
||||
* Creation of a new instance is a two-step process: create, then register.
|
||||
* Destruction is triggered using the *_delete functions, and completes asynchronously.
|
|
@ -0,0 +1,22 @@
|
|||
--- a/net/ipv6/ip6_tunnel.c
|
||||
+++ b/net/ipv6/ip6_tunnel.c
|
||||
@@ -2417,7 +2417,7 @@ nla_put_failure:
|
||||
*/
|
||||
void ip6_update_offload_stats(struct net_device *dev, void *ptr)
|
||||
{
|
||||
- struct pcpu_sw_netstats *tstats = per_cpu_ptr(dev->tstats, 0);
|
||||
+ struct pcpu_sw_netstats *tstats = this_cpu_ptr(dev->tstats);
|
||||
const struct pcpu_sw_netstats *offload_stats =
|
||||
(struct pcpu_sw_netstats *)ptr;
|
||||
|
||||
--- a/net/ipv6/sit.c
|
||||
+++ b/net/ipv6/sit.c
|
||||
@@ -1736,7 +1736,7 @@ nla_put_failure:
|
||||
/* 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);
|
||||
+ struct pcpu_sw_netstats *tstats = this_cpu_ptr(dev->tstats);
|
||||
const struct pcpu_sw_netstats *offload_stats =
|
||||
(struct pcpu_sw_netstats *)ptr;
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
--- /dev/null
|
||||
+++ b/include/uapi/linux/tlshdr.h
|
||||
@@ -0,0 +1,21 @@
|
||||
+#ifndef _UAPI_LINUX_TLSHDR_H
|
||||
+#define _UAPI_LINUX_TLSHDR_H
|
||||
+
|
||||
+#include <linux/types.h>
|
||||
+
|
||||
+struct tlshdr {
|
||||
+ __u8 type;
|
||||
+ __be16 version;
|
||||
+ __be16 len;
|
||||
+} __attribute__((packed));
|
||||
+
|
||||
+#define TLSHDR_REC_TYPE_CCS 20 /* TLS packet is change cipher specification */
|
||||
+#define TLSHDR_REC_TYPE_ALERT 21 /* TLS packet is Alert */
|
||||
+#define TLSHDR_REC_TYPE_HANDSHAKE 22 /* TLS packet is Handshake */
|
||||
+#define TLSHDR_REC_TYPE_DATA 23 /* TLS packet is Application data */
|
||||
+
|
||||
+#define TLSHDR_VERSION_1_1 0x0302 /* TLS Header Version(tls 1.1) */
|
||||
+#define TLSHDR_VERSION_1_2 0x0303 /* TLS Header Version(tls 1.2) */
|
||||
+#define TLSHDR_VERSION_1_3 0x0304 /* TLS Header Version(tls 1.3) */
|
||||
+
|
||||
+#endif /* _UAPI_LINUX_TLSHDR_H */
|
|
@ -0,0 +1,876 @@
|
|||
--- a/include/linux/if_bridge.h
|
||||
+++ b/include/linux/if_bridge.h
|
||||
@@ -258,4 +258,17 @@ extern br_get_dst_hook_t __rcu *br_get_d
|
||||
extern struct net_device *br_fdb_bridge_dev_get_and_hold(struct net_bridge *br);
|
||||
/* QCA NSS bridge-mgr support - End */
|
||||
|
||||
+/* QCA qca-mcs support - Start */
|
||||
+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 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;
|
||||
+
|
||||
+typedef void (br_notify_hook_t)(int group, int event, const void *ptr);
|
||||
+extern br_notify_hook_t __rcu *br_notify_hook;
|
||||
+/* QCA qca-mcs support - End */
|
||||
+
|
||||
#endif
|
||||
--- a/net/bridge/br_fdb.c
|
||||
+++ b/net/bridge/br_fdb.c
|
||||
@@ -239,6 +239,8 @@ static void fdb_notify(struct net_bridge
|
||||
kfree_skb(skb);
|
||||
goto errout;
|
||||
}
|
||||
+
|
||||
+ __br_notify(RTNLGRP_NEIGH, type, fdb); /* QCA qca-mcs support */
|
||||
rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);
|
||||
return;
|
||||
errout:
|
||||
@@ -305,6 +307,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); /* QCA qca-mcs support */
|
||||
|
||||
/* 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
|
||||
--- a/net/bridge/br_private.h
|
||||
+++ b/net/bridge/br_private.h
|
||||
@@ -906,6 +906,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); /* QCA qca-mcs support */
|
||||
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,14 @@ struct nd_msg *br_is_nd_neigh_msg(struct
|
||||
bool br_is_neigh_suppress_enabled(const struct net_bridge_port *p, u16 vid);
|
||||
#define __br_get(__hook, __default, __args ...) \
|
||||
(__hook ? (__hook(__args)) : (__default)) /* QCA NSS ECM support */
|
||||
+
|
||||
+/* QCA qca-mcs support - Start */
|
||||
+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);
|
||||
+}
|
||||
+/* QCA qca-mcs support - End */
|
||||
#endif
|
||||
--- a/net/bridge/br_netlink.c
|
||||
+++ b/net/bridge/br_netlink.c
|
||||
@@ -656,6 +656,7 @@ void br_info_notify(int event, const str
|
||||
kfree_skb(skb);
|
||||
goto errout;
|
||||
}
|
||||
+ __br_notify(RTNLGRP_LINK, event, port); /* QCA qca-mcs support */
|
||||
rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC);
|
||||
return;
|
||||
errout:
|
||||
--- a/net/bridge/br.c
|
||||
+++ b/net/bridge/br.c
|
||||
@@ -472,6 +472,12 @@ static void __exit br_deinit(void)
|
||||
br_fdb_fini();
|
||||
}
|
||||
|
||||
+/* QCA qca-mcs support - Start */
|
||||
+/* Hook for bridge event notifications */
|
||||
+br_notify_hook_t __rcu *br_notify_hook __read_mostly;
|
||||
+EXPORT_SYMBOL_GPL(br_notify_hook);
|
||||
+/* QCA qca-mcs support - End */
|
||||
+
|
||||
module_init(br_init)
|
||||
module_exit(br_deinit)
|
||||
MODULE_LICENSE("GPL");
|
||||
--- a/net/bridge/br_device.c
|
||||
+++ b/net/bridge/br_device.c
|
||||
@@ -83,6 +83,13 @@ 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)) {
|
||||
+ /* QCA qca-mcs support - Start */
|
||||
+ 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;
|
||||
+ /* QCA qca-mcs support - End */
|
||||
+
|
||||
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,17 @@ br_netif_receive_skb(struct net *net, st
|
||||
return netif_receive_skb(skb);
|
||||
}
|
||||
|
||||
-static int br_pass_frame_up(struct sk_buff *skb)
|
||||
+/* QCA qca-mcs support - Start */
|
||||
+/* Hook for external Multicast handler */
|
||||
+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);
|
||||
+/* QCA qca-mcs support - End */
|
||||
+
|
||||
+int br_pass_frame_up(struct sk_buff *skb)
|
||||
{
|
||||
struct net_device *indev, *brdev = BR_INPUT_SKB_CB(skb)->brdev;
|
||||
struct net_bridge *br = netdev_priv(brdev);
|
||||
@@ -69,6 +79,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); /* QCA qca-mcs support */
|
||||
|
||||
/* note: already called with rcu_read_lock */
|
||||
int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||
@@ -82,6 +93,11 @@ int br_handle_frame_finish(struct net *n
|
||||
struct net_bridge_mcast *brmctx;
|
||||
struct net_bridge_vlan *vlan;
|
||||
struct net_bridge *br;
|
||||
+ /* QCA qca-mcs support - Start */
|
||||
+ 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);
|
||||
+ /* QCA qca-mcs support - End */
|
||||
u16 vid = 0;
|
||||
u8 state;
|
||||
|
||||
@@ -175,6 +191,12 @@ int br_handle_frame_finish(struct net *n
|
||||
|
||||
switch (pkt_type) {
|
||||
case BR_PKT_MULTICAST:
|
||||
+ /* QCA qca-mcs support - Start */
|
||||
+ multicast_handle_hook = rcu_dereference(br_multicast_handle_hook);
|
||||
+ if (!__br_get(multicast_handle_hook, true, p, skb))
|
||||
+ goto out;
|
||||
+ /* QCA qca-mcs support - End */
|
||||
+
|
||||
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)) {
|
||||
@@ -190,8 +212,15 @@ 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);
|
||||
- break;
|
||||
+ /* QCA qca-mcs support - Start */
|
||||
+ pdst = __br_get(get_dst_hook, NULL, p, &skb);
|
||||
+ if (pdst) {
|
||||
+ if (!skb)
|
||||
+ goto out;
|
||||
+ } else {
|
||||
+ /* QCA qca-mcs support - End */
|
||||
+ dst = br_fdb_find_rcu(br, eth_hdr(skb)->h_dest, vid);
|
||||
+ }
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -206,6 +235,13 @@ int br_handle_frame_finish(struct net *n
|
||||
dst->used = now;
|
||||
br_forward(dst->dst, skb, local_rcv, false);
|
||||
} else {
|
||||
+ /* QCA qca-mcs support - Start */
|
||||
+ if (pdst) {
|
||||
+ br_forward(pdst, skb, local_rcv, false);
|
||||
+ goto out;
|
||||
+ }
|
||||
+ /* QCA qca-mcs support - End */
|
||||
+
|
||||
if (!mcast_hit)
|
||||
br_flood(br, skb, pkt_type, local_rcv, false, vid);
|
||||
else
|
||||
--- a/include/linux/mroute.h
|
||||
+++ b/include/linux/mroute.h
|
||||
@@ -92,4 +92,44 @@ struct rtmsg;
|
||||
int ipmr_get_route(struct net *net, struct sk_buff *skb,
|
||||
__be32 saddr, __be32 daddr,
|
||||
struct rtmsg *rtm, u32 portid);
|
||||
+
|
||||
+/* QCA ECM qca-mcs support - Start */
|
||||
+#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);
|
||||
+/* QCA ECM qca-mcs support - End */
|
||||
#endif
|
||||
--- a/include/linux/mroute6.h
|
||||
+++ b/include/linux/mroute6.h
|
||||
@@ -137,4 +137,47 @@ static inline int ip6mr_sk_ioctl(struct
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
+
|
||||
+/* QCA qca-mcs support - Start */
|
||||
+#define IP6MR_MFC_EVENT_UPDATE 1
|
||||
+#define IP6MR_MFC_EVENT_DELETE 2
|
||||
+
|
||||
+/*
|
||||
+ * 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);
|
||||
+/* QCA qca-mcs support - End */
|
||||
#endif
|
||||
--- 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); /* QCA ECM qca-mcs support */
|
||||
+
|
||||
/* 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; /* QCA ECM qca-mcs support */
|
||||
|
||||
#ifdef CONFIG_IP_MROUTE_MULTIPLE_TABLES
|
||||
#define ipmr_for_each_table(mrt, net) \
|
||||
@@ -223,6 +229,80 @@ static int ipmr_rule_fill(struct fib_rul
|
||||
return 0;
|
||||
}
|
||||
|
||||
+/* QCA ECM qca-mcs support - Start */
|
||||
+/* 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();
|
||||
+}
|
||||
+/* QCA ECM qca-mcs support - End */
|
||||
+
|
||||
static const struct fib_rules_ops __net_initconst ipmr_rules_ops_template = {
|
||||
.family = RTNL_FAMILY_IPMR,
|
||||
.rule_size = sizeof(struct ipmr_rule),
|
||||
@@ -236,6 +316,156 @@ static const struct fib_rules_ops __net_
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
+/* QCA ECM qca-mcs support - Start */
|
||||
+/* 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;
|
||||
+ cache->_c.mfc_un.res.pkt += pkts_out;
|
||||
+ cache->_c.mfc_un.res.bytes += bytes_out;
|
||||
+
|
||||
+ 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);
|
||||
+/* QCA ECM qca-mcs support - End */
|
||||
+
|
||||
static int __net_init ipmr_rules_init(struct net *net)
|
||||
{
|
||||
struct fib_rules_ops *ops;
|
||||
@@ -1191,6 +1421,10 @@ 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);
|
||||
+ /* QCA ECM qca-mcs support - Start */
|
||||
+ /* Inform offload modules of the delete event */
|
||||
+ ipmr_sync_entry_delete(c->mfc_origin, c->mfc_mcastgrp);
|
||||
+ /* QCA ECM qca-mcs support - End */
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1221,6 +1455,10 @@ 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);
|
||||
+ /* QCA ECM qca-mcs support - Start */
|
||||
+ /* Inform offload modules of the update event */
|
||||
+ ipmr_sync_entry_update(mrt, c);
|
||||
+ /* QCA ECM qca-mcs support - End */
|
||||
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); /* QCA qca-mcs support */
|
||||
+
|
||||
/* 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,6 +104,13 @@ 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);
|
||||
+/* QCA qca-mcs support - Start */
|
||||
+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;
|
||||
+/* QCA qca-mcs support - End */
|
||||
|
||||
#ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES
|
||||
#define ip6mr_for_each_table(mrt, net) \
|
||||
@@ -375,6 +385,84 @@ static struct mfc6_cache_cmp_arg ip6mr_m
|
||||
.mf6c_mcastgrp = IN6ADDR_ANY_INIT,
|
||||
};
|
||||
|
||||
+/* QCA qca-mcs support - Start */
|
||||
+/* 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();
|
||||
+}
|
||||
+/* QCA qca-mcs support - End */
|
||||
+
|
||||
static struct mr_table_ops ip6mr_mr_table_ops = {
|
||||
.rht_params = &ip6mr_rht_params,
|
||||
.cmparg_any = &ip6mr_mr_table_ops_cmparg_any,
|
||||
@@ -697,6 +785,151 @@ static int call_ip6mr_mfc_entry_notifier
|
||||
&mfc->_c, tb_id, &net->ipv6.ipmr_seq);
|
||||
}
|
||||
|
||||
+/* QCA qca-mcs support - Start */
|
||||
+/* 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;
|
||||
+ cache->_c.mfc_un.res.pkt += pkts_out;
|
||||
+ cache->_c.mfc_un.res.bytes += bytes_out;
|
||||
+
|
||||
+ 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);
|
||||
+/* QCA qca-mcs support - End */
|
||||
+
|
||||
/* Delete a VIF entry */
|
||||
static int mif6_delete(struct mr_table *mrt, int vifi, int notify,
|
||||
struct list_head *head)
|
||||
@@ -1221,6 +1454,7 @@ static int ip6mr_mfc_delete(struct mr_ta
|
||||
int parent)
|
||||
{
|
||||
struct mfc6_cache *c;
|
||||
+ struct in6_addr mc_origin, mc_group; /* QCA qca-mcs support */
|
||||
|
||||
/* The entries are added/deleted only under RTNL */
|
||||
rcu_read_lock();
|
||||
@@ -1229,6 +1463,11 @@ static int ip6mr_mfc_delete(struct mr_ta
|
||||
rcu_read_unlock();
|
||||
if (!c)
|
||||
return -ENOENT;
|
||||
+
|
||||
+ /* QCA qca-mcs support - Start */
|
||||
+ memcpy(&mc_origin, &c->mf6c_origin, sizeof(struct in6_addr));
|
||||
+ memcpy(&mc_group, &c->mf6c_mcastgrp, sizeof(struct in6_addr));
|
||||
+ /* QCA qca-mcs support - End */
|
||||
rhltable_remove(&mrt->mfc_hash, &c->_c.mnode, ip6mr_rht_params);
|
||||
list_del_rcu(&c->_c.list);
|
||||
|
||||
@@ -1236,6 +1475,11 @@ 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);
|
||||
+ /* QCA qca-mcs support - Start */
|
||||
+ /* Inform offload modules of the delete event */
|
||||
+ ip6mr_sync_entry_delete(&mc_origin, &mc_group);
|
||||
+ /* QCA qca-mcs support - End */
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1457,6 +1701,10 @@ 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);
|
||||
+ /* QCA qca-mcs support - Start */
|
||||
+ /* Inform offload modules of the update event */
|
||||
+ ip6mr_sync_entry_update(mrt, c);
|
||||
+ /* QCA qca-mcs support - End */
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,127 @@
|
|||
--- a/crypto/authenc.c
|
||||
+++ b/crypto/authenc.c
|
||||
@@ -417,6 +417,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
|
||||
@@ -101,6 +101,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
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <crypto/aead.h>
|
||||
#include <crypto/authenc.h>
|
||||
+#include <crypto/algapi.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/module.h>
|
||||
#include <net/ip.h>
|
||||
@@ -658,6 +658,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;
|
||||
|
||||
@@ -669,6 +670,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);
|
||||
@@ -890,6 +896,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;
|
||||
@@ -897,6 +904,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
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include <crypto/aead.h>
|
||||
#include <crypto/authenc.h>
|
||||
+#include <crypto/algapi.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/module.h>
|
||||
#include <net/ip.h>
|
||||
@@ -696,6 +696,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;
|
||||
|
||||
@@ -707,6 +708,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);
|
||||
@@ -934,6 +940,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;
|
||||
@@ -945,6 +952,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;
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
From eee3a7956b943dd3e23a74fbb5bfe89405eb0782 Mon Sep 17 00:00:00 2001
|
||||
From: Andrea Righi <andrea.righi@canonical.com>
|
||||
Date: Mon, 6 Dec 2021 17:34:47 +0100
|
||||
Subject: UBUNTU: SAUCE: ipv6: fix NULL pointer dereference in ip6_output()
|
||||
|
||||
It is possible to trigger a NULL pointer dereference by running the srv6
|
||||
net kselftest (tools/testing/selftests/net/srv6_end_dt46_l3vpn_test.sh):
|
||||
|
||||
[ 249.051216] BUG: kernel NULL pointer dereference, address: 0000000000000378
|
||||
[ 249.052331] #PF: supervisor read access in kernel mode
|
||||
[ 249.053137] #PF: error_code(0x0000) - not-present page
|
||||
[ 249.053960] PGD 0 P4D 0
|
||||
[ 249.054376] Oops: 0000 [#1] PREEMPT SMP NOPTI
|
||||
[ 249.055083] CPU: 1 PID: 21 Comm: ksoftirqd/1 Tainted: G E 5.16.0-rc4 #2
|
||||
[ 249.056328] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.14.0-2 04/01/2014
|
||||
[ 249.057632] RIP: 0010:ip6_forward+0x53c/0xab0
|
||||
[ 249.058354] Code: 49 c7 44 24 20 00 00 00 00 48 83 e0 fe 48 8b 40 30 48 3d 70 b2 b5 81 0f 85 b5 04 00 00 e8 7c f2 ff ff 41 89 c5 e9 17 01 00 00 <44> 8b 93 78 03 00 00 45 85 d2 0f 85 92 fb ff ff 49 8b 54 24 10 48
|
||||
[ 249.061274] RSP: 0018:ffffc900000cbb30 EFLAGS: 00010246
|
||||
[ 249.062042] RAX: 0000000000000000 RBX: 0000000000000000 RCX: ffff8881051d3400
|
||||
[ 249.063141] RDX: ffff888104bda000 RSI: 00000000000002c0 RDI: 0000000000000000
|
||||
[ 249.064264] RBP: ffffc900000cbbc8 R08: 0000000000000000 R09: 0000000000000000
|
||||
[ 249.065376] R10: 0000000000000040 R11: 0000000000000000 R12: ffff888103409800
|
||||
[ 249.066498] R13: ffff8881051d3410 R14: ffff888102725280 R15: ffff888103525000
|
||||
[ 249.067619] FS: 0000000000000000(0000) GS:ffff88813bc80000(0000) knlGS:0000000000000000
|
||||
[ 249.068881] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
|
||||
[ 249.069777] CR2: 0000000000000378 CR3: 0000000104980000 CR4: 0000000000750ee0
|
||||
[ 249.070907] PKRU: 55555554
|
||||
[ 249.071337] Call Trace:
|
||||
[ 249.071730] <TASK>
|
||||
[ 249.072070] ? debug_smp_processor_id+0x17/0x20
|
||||
[ 249.072807] seg6_input_core+0x2bb/0x2d0
|
||||
[ 249.073436] ? _raw_spin_unlock_irqrestore+0x29/0x40
|
||||
[ 249.074225] seg6_input+0x3b/0x130
|
||||
[ 249.074768] lwtunnel_input+0x5e/0xa0
|
||||
[ 249.075357] ip_rcv+0x17b/0x190
|
||||
[ 249.075867] ? update_load_avg+0x82/0x600
|
||||
[ 249.076514] __netif_receive_skb_one_core+0x86/0xa0
|
||||
[ 249.077231] __netif_receive_skb+0x15/0x60
|
||||
[ 249.077843] process_backlog+0x97/0x160
|
||||
[ 249.078389] __napi_poll+0x31/0x170
|
||||
[ 249.078912] net_rx_action+0x229/0x270
|
||||
[ 249.079506] __do_softirq+0xef/0x2ed
|
||||
[ 249.080085] run_ksoftirqd+0x37/0x50
|
||||
[ 249.080663] smpboot_thread_fn+0x193/0x230
|
||||
[ 249.081312] kthread+0x17a/0x1a0
|
||||
[ 249.081847] ? smpboot_register_percpu_thread+0xe0/0xe0
|
||||
[ 249.082677] ? set_kthread_struct+0x50/0x50
|
||||
[ 249.083340] ret_from_fork+0x22/0x30
|
||||
[ 249.083926] </TASK>
|
||||
[ 249.090295] ---[ end trace 1998d7ba5965a365 ]---
|
||||
|
||||
It looks like commit 0857d6f8c759 ("ipv6: When forwarding count rx stats
|
||||
on the orig netdev") tries to determine the right netdev to account the
|
||||
rx stats, but in this particular case it's failing and the netdev is
|
||||
NULL.
|
||||
|
||||
Fallback to the previous method of determining the netdev interface (via
|
||||
skb->dev) to account the rx stats when the orig netdev can't be
|
||||
determined.
|
||||
|
||||
Fixes: 0857d6f8c759 ("ipv6: When forwarding count rx stats on the orig netdev")
|
||||
Signed-off-by: Andrea Righi <andrea.righi@canonical.com>
|
||||
(cherry picked from https://lore.kernel.org/lkml/20211206163447.991402-1-andrea.righi@canonical.com/T/#u)
|
||||
Signed-off-by: Andrea Righi <andrea.righi@canonical.com>
|
||||
---
|
||||
net/ipv6/ip6_output.c | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
--- a/net/ipv6/ip6_output.c
|
||||
+++ b/net/ipv6/ip6_output.c
|
||||
@@ -498,6 +498,9 @@ int ip6_forward(struct sk_buff *skb)
|
||||
u32 mtu;
|
||||
|
||||
idev = __in6_dev_get_safely(dev_get_by_index_rcu(net, IP6CB(skb)->iif));
|
||||
+ if (unlikely(!idev))
|
||||
+ idev = __in6_dev_get_safely(skb->dev);
|
||||
+
|
||||
if (net->ipv6.devconf_all->forwarding == 0)
|
||||
goto error;
|
||||
|
|
@ -0,0 +1,384 @@
|
|||
--- a/include/linux/cpuhotplug.h
|
||||
+++ b/include/linux/cpuhotplug.h
|
||||
@@ -94,6 +94,7 @@ enum cpuhp_state {
|
||||
CPUHP_RADIX_DEAD,
|
||||
CPUHP_PAGE_ALLOC,
|
||||
CPUHP_NET_DEV_DEAD,
|
||||
+ CPUHP_SKB_RECYCLER_DEAD,
|
||||
CPUHP_PCI_XGENE_DEAD,
|
||||
CPUHP_IOMMU_IOVA_DEAD,
|
||||
CPUHP_LUSTRE_CFS_DEAD,
|
||||
--- a/include/linux/skbuff.h
|
||||
+++ b/include/linux/skbuff.h
|
||||
@@ -1065,6 +1065,10 @@ struct sk_buff {
|
||||
/* only useable after checking ->active_extensions != 0 */
|
||||
struct skb_ext *extensions;
|
||||
#endif
|
||||
+
|
||||
+#ifdef CONFIG_DEBUG_OBJECTS_SKBUFF
|
||||
+ void *free_addr;
|
||||
+#endif
|
||||
};
|
||||
|
||||
/* if you move pkt_type around you also must adapt those constants */
|
||||
@@ -1250,7 +1254,7 @@ static inline void kfree_skb_list(struct sk_buff *segs)
|
||||
kfree_skb_list_reason(segs, SKB_DROP_REASON_NOT_SPECIFIED);
|
||||
}
|
||||
|
||||
-#ifdef CONFIG_TRACEPOINTS
|
||||
+#ifdef CONFIG_SKB_RECYCLER
|
||||
void consume_skb(struct sk_buff *skb);
|
||||
#else
|
||||
static inline void consume_skb(struct sk_buff *skb)
|
||||
@@ -1262,6 +1266,9 @@ static inline void consume_skb(struct sk_buff *skb)
|
||||
void __consume_stateless_skb(struct sk_buff *skb);
|
||||
void __kfree_skb(struct sk_buff *skb);
|
||||
extern struct kmem_cache *skbuff_cache;
|
||||
+extern void kfree_skbmem(struct sk_buff *skb);
|
||||
+extern void skb_release_data(struct sk_buff *skb, enum skb_drop_reason reason,
|
||||
+ bool napi_safe);
|
||||
|
||||
void kfree_skb_partial(struct sk_buff *skb, bool head_stolen);
|
||||
bool skb_try_coalesce(struct sk_buff *to, struct sk_buff *from,
|
||||
--- a/net/Kconfig
|
||||
+++ b/net/Kconfig
|
||||
@@ -369,6 +369,27 @@ config NET_FLOW_LIMIT
|
||||
with many clients some protection against DoS by a single (spoofed)
|
||||
flow that greatly exceeds average workload.
|
||||
|
||||
+config SKB_RECYCLER
|
||||
+ bool "Generic skb recycling"
|
||||
+ default y
|
||||
+ help
|
||||
+ SKB_RECYCLER is used to implement RX-to-RX skb recycling.
|
||||
+ This config enables the recycling scheme for bridging and
|
||||
+ routing workloads. It can reduce skbuff freeing or
|
||||
+ reallocation overhead.
|
||||
+
|
||||
+config SKB_RECYCLER_MULTI_CPU
|
||||
+ bool "Cross-CPU recycling for CPU-locked workloads"
|
||||
+ depends on SMP && SKB_RECYCLER
|
||||
+ default n
|
||||
+
|
||||
+config ALLOC_SKB_PAGE_FRAG_DISABLE
|
||||
+ bool "Disable page fragment based skbuff payload allocations"
|
||||
+ depends on !SKB_RECYCLER
|
||||
+ default n
|
||||
+ help
|
||||
+ Disable page fragment based allocations for skbuff payloads.
|
||||
+
|
||||
menu "Network testing"
|
||||
|
||||
config NET_PKTGEN
|
||||
--- a/net/core/Makefile
|
||||
+++ b/net/core/Makefile
|
||||
@@ -41,3 +41,4 @@ obj-$(CONFIG_NET_SOCK_MSG) += skmsg.o
|
||||
obj-$(CONFIG_BPF_SYSCALL) += sock_map.o
|
||||
obj-$(CONFIG_BPF_SYSCALL) += bpf_sk_storage.o
|
||||
obj-$(CONFIG_OF) += of_net.o
|
||||
+obj-$(CONFIG_SKB_RECYCLER) += skbuff_recycle.o
|
||||
--- a/net/core/dev.c
|
||||
+++ b/net/core/dev.c
|
||||
@@ -6016,10 +6016,16 @@ static int process_backlog(struct napi_struct *napi, int quota)
|
||||
|
||||
napi->weight = READ_ONCE(dev_rx_weight);
|
||||
while (again) {
|
||||
- struct sk_buff *skb;
|
||||
+ struct sk_buff *skb, *next_skb;
|
||||
|
||||
while ((skb = __skb_dequeue(&sd->process_queue))) {
|
||||
rcu_read_lock();
|
||||
+
|
||||
+ next_skb = skb_peek(&sd->process_queue);
|
||||
+ if (likely(next_skb)) {
|
||||
+ prefetch(next_skb->data);
|
||||
+ }
|
||||
+
|
||||
__netif_receive_skb(skb);
|
||||
rcu_read_unlock();
|
||||
input_queue_head_incr(sd);
|
||||
--- a/net/core/skbuff.c
|
||||
+++ b/net/core/skbuff.c
|
||||
@@ -87,6 +87,31 @@
|
||||
|
||||
#include "dev.h"
|
||||
#include "sock_destructor.h"
|
||||
+#include "skbuff_recycle.h"
|
||||
+
|
||||
+struct kmem_cache *skb_data_cache;
|
||||
+/*
|
||||
+ * For low memory profile, NSS_SKB_FIXED_SIZE_2K is enabled and
|
||||
+ * CONFIG_SKB_RECYCLER is disabled. For premium and enterprise profile
|
||||
+ * CONFIG_SKB_RECYCLER is enabled and NSS_SKB_FIXED_SIZE_2K is disabled.
|
||||
+ * Irrespective of NSS_SKB_FIXED_SIZE_2K enabled/disabled, the
|
||||
+ * CONFIG_SKB_RECYCLER and __LP64__ determines the value of SKB_DATA_CACHE_SIZE
|
||||
+ */
|
||||
+#if defined(CONFIG_SKB_RECYCLER)
|
||||
+/*
|
||||
+ * 2688 for 64bit arch, 2624 for 32bit arch
|
||||
+ */
|
||||
+#define SKB_DATA_CACHE_SIZE (SKB_DATA_ALIGN(SKB_RECYCLE_SIZE + NET_SKB_PAD) + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
|
||||
+#else
|
||||
+/*
|
||||
+ * 2368 for 64bit arch, 2176 for 32bit arch
|
||||
+ */
|
||||
+#if defined(__LP64__)
|
||||
+#define SKB_DATA_CACHE_SIZE ((SKB_DATA_ALIGN(1984 + NET_SKB_PAD)) + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
|
||||
+#else
|
||||
+#define SKB_DATA_CACHE_SIZE ((SKB_DATA_ALIGN(1856 + NET_SKB_PAD)) + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
|
||||
+#endif
|
||||
+#endif
|
||||
|
||||
struct kmem_cache *skbuff_cache __ro_after_init;
|
||||
static struct kmem_cache *skbuff_fclone_cache __ro_after_init;
|
||||
@@ -551,21 +576,20 @@ static void *kmalloc_reserve(unsigned int *size, gfp_t flags, int node,
|
||||
bool *pfmemalloc)
|
||||
{
|
||||
bool ret_pfmemalloc = false;
|
||||
- size_t obj_size;
|
||||
+ unsigned int obj_size = *size;
|
||||
void *obj;
|
||||
|
||||
obj_size = SKB_HEAD_ALIGN(*size);
|
||||
- if (obj_size <= SKB_SMALL_HEAD_CACHE_SIZE &&
|
||||
- !(flags & KMALLOC_NOT_NORMAL_BITS)) {
|
||||
- obj = kmem_cache_alloc_node(skb_small_head_cache,
|
||||
- flags | __GFP_NOMEMALLOC | __GFP_NOWARN,
|
||||
- node);
|
||||
- *size = SKB_SMALL_HEAD_CACHE_SIZE;
|
||||
+ if (obj_size > SZ_2K && obj_size <= SKB_DATA_CACHE_SIZE) {
|
||||
+ obj = kmem_cache_alloc_node(skb_data_cache,
|
||||
+ flags | __GFP_NOMEMALLOC | __GFP_NOWARN,
|
||||
+ node);
|
||||
+ *size = SKB_DATA_CACHE_SIZE;
|
||||
if (obj || !(gfp_pfmemalloc_allowed(flags)))
|
||||
goto out;
|
||||
/* Try again but now we are using pfmemalloc reserves */
|
||||
ret_pfmemalloc = true;
|
||||
- obj = kmem_cache_alloc_node(skb_small_head_cache, flags, node);
|
||||
+ obj = kmem_cache_alloc_node(skb_data_cache, flags, node);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -648,10 +671,12 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,
|
||||
* aligned memory blocks, unless SLUB/SLAB debug is enabled.
|
||||
* Both skb->head and skb_shared_info are cache line aligned.
|
||||
*/
|
||||
+ size = SKB_DATA_ALIGN(size);
|
||||
+ size += SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
|
||||
data = kmalloc_reserve(&size, gfp_mask, node, &pfmemalloc);
|
||||
if (unlikely(!data))
|
||||
goto nodata;
|
||||
- /* kmalloc_size_roundup() might give us more room than requested.
|
||||
+ /* kmalloc_reserve(size) might give us more room than requested.
|
||||
* Put skb_shared_info exactly at the end of allocated zone,
|
||||
* to allow max possible filling before reallocation.
|
||||
*/
|
||||
@@ -686,7 +711,7 @@ EXPORT_SYMBOL(__alloc_skb);
|
||||
/**
|
||||
* __netdev_alloc_skb - allocate an skbuff for rx on a specific device
|
||||
* @dev: network device to receive on
|
||||
- * @len: length to allocate
|
||||
+ * @length: length to allocate
|
||||
* @gfp_mask: get_free_pages mask, passed to alloc_skb
|
||||
*
|
||||
* Allocate a new &sk_buff and assign it a usage count of one. The
|
||||
@@ -696,29 +721,53 @@ EXPORT_SYMBOL(__alloc_skb);
|
||||
*
|
||||
* %NULL is returned if there is no free memory.
|
||||
*/
|
||||
-struct sk_buff *__netdev_alloc_skb(struct net_device *dev, unsigned int len,
|
||||
- gfp_t gfp_mask)
|
||||
+struct sk_buff *__netdev_alloc_skb(struct net_device *dev,
|
||||
+ unsigned int length, gfp_t gfp_mask)
|
||||
{
|
||||
- struct page_frag_cache *nc;
|
||||
struct sk_buff *skb;
|
||||
+ unsigned int len = length;
|
||||
+
|
||||
+#ifdef CONFIG_SKB_RECYCLER
|
||||
+ skb = skb_recycler_alloc(dev, length);
|
||||
+ if (likely(skb))
|
||||
+ return skb;
|
||||
+
|
||||
+ len = SKB_RECYCLE_SIZE;
|
||||
+ if (unlikely(length > SKB_RECYCLE_SIZE))
|
||||
+ len = length;
|
||||
+
|
||||
+ skb = __alloc_skb(len + NET_SKB_PAD, gfp_mask,
|
||||
+ SKB_ALLOC_RX, NUMA_NO_NODE);
|
||||
+ if (!skb)
|
||||
+ goto skb_fail;
|
||||
+ goto skb_success;
|
||||
+#else
|
||||
+ struct page_frag_cache *nc;
|
||||
bool pfmemalloc;
|
||||
+ bool page_frag_alloc_enable = true;
|
||||
void *data;
|
||||
|
||||
len += NET_SKB_PAD;
|
||||
|
||||
+
|
||||
+#ifdef CONFIG_ALLOC_SKB_PAGE_FRAG_DISABLE
|
||||
+ page_frag_alloc_enable = false;
|
||||
+#endif
|
||||
/* If requested length is either too small or too big,
|
||||
* we use kmalloc() for skb->head allocation.
|
||||
*/
|
||||
if (len <= SKB_WITH_OVERHEAD(1024) ||
|
||||
len > SKB_WITH_OVERHEAD(PAGE_SIZE) ||
|
||||
- (gfp_mask & (__GFP_DIRECT_RECLAIM | GFP_DMA))) {
|
||||
+ (gfp_mask & (__GFP_DIRECT_RECLAIM | GFP_DMA)) ||
|
||||
+ !page_frag_alloc_enable) {
|
||||
skb = __alloc_skb(len, gfp_mask, SKB_ALLOC_RX, NUMA_NO_NODE);
|
||||
if (!skb)
|
||||
goto skb_fail;
|
||||
goto skb_success;
|
||||
}
|
||||
|
||||
- len = SKB_HEAD_ALIGN(len);
|
||||
+ len += SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
|
||||
+ len = SKB_DATA_ALIGN(len);
|
||||
|
||||
if (sk_memalloc_socks())
|
||||
gfp_mask |= __GFP_MEMALLOC;
|
||||
@@ -747,6 +796,7 @@ struct sk_buff *__netdev_alloc_skb(struct net_device *dev, unsigned int len,
|
||||
if (pfmemalloc)
|
||||
skb->pfmemalloc = 1;
|
||||
skb->head_frag = 1;
|
||||
+#endif
|
||||
|
||||
skb_success:
|
||||
skb_reserve(skb, NET_SKB_PAD);
|
||||
@@ -817,7 +867,8 @@ struct sk_buff *__napi_alloc_skb(struct napi_struct *napi, unsigned int len,
|
||||
data = page_frag_alloc_1k(&nc->page_small, gfp_mask);
|
||||
pfmemalloc = NAPI_SMALL_PAGE_PFMEMALLOC(nc->page_small);
|
||||
} else {
|
||||
- len = SKB_HEAD_ALIGN(len);
|
||||
+ len += SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
|
||||
+ len = SKB_DATA_ALIGN(len);
|
||||
|
||||
data = page_frag_alloc(&nc->page, len, gfp_mask);
|
||||
pfmemalloc = nc->page.pfmemalloc;
|
||||
@@ -975,7 +1026,7 @@ static void skb_free_head(struct sk_buff *skb, bool napi_safe)
|
||||
}
|
||||
}
|
||||
|
||||
-static void skb_release_data(struct sk_buff *skb, enum skb_drop_reason reason,
|
||||
+void skb_release_data(struct sk_buff *skb, enum skb_drop_reason reason,
|
||||
bool napi_safe)
|
||||
{
|
||||
struct skb_shared_info *shinfo = skb_shinfo(skb);
|
||||
@@ -1018,7 +1069,7 @@ static void skb_release_data(struct sk_buff *skb, enum skb_drop_reason reason,
|
||||
/*
|
||||
* Free an skbuff by memory without cleaning the state.
|
||||
*/
|
||||
-static void kfree_skbmem(struct sk_buff *skb)
|
||||
+void kfree_skbmem(struct sk_buff *skb)
|
||||
{
|
||||
struct sk_buff_fclones *fclones;
|
||||
|
||||
@@ -1282,7 +1333,6 @@ void skb_tx_error(struct sk_buff *skb)
|
||||
}
|
||||
EXPORT_SYMBOL(skb_tx_error);
|
||||
|
||||
-#ifdef CONFIG_TRACEPOINTS
|
||||
/**
|
||||
* consume_skb - free an skbuff
|
||||
* @skb: buffer to free
|
||||
@@ -1291,13 +1341,48 @@ EXPORT_SYMBOL(skb_tx_error);
|
||||
* Functions identically to kfree_skb, but kfree_skb assumes that the frame
|
||||
* is being dropped after a failure and notes that
|
||||
*/
|
||||
+#ifdef CONFIG_SKB_RECYCLER
|
||||
void consume_skb(struct sk_buff *skb)
|
||||
{
|
||||
if (!skb_unref(skb))
|
||||
return;
|
||||
+ prefetch(&skb->destructor);
|
||||
+
|
||||
+ /*Tian: Not sure if we need to continue using this since
|
||||
+ * since unref does the work in 5.4
|
||||
+ */
|
||||
+
|
||||
+ /*
|
||||
+ if (likely(atomic_read(&skb->users) == 1))
|
||||
+ smp_rmb();
|
||||
+ else if (likely(!atomic_dec_and_test(&skb->users)))
|
||||
+ return;
|
||||
+ */
|
||||
|
||||
+ /* If possible we'd like to recycle any skb rather than just free it,
|
||||
+ * but in order to do that we need to release any head state too.
|
||||
+ * We don't want to do this later because we'll be in a pre-emption
|
||||
+ * disabled state.
|
||||
+ */
|
||||
+ skb_release_head_state(skb);
|
||||
+
|
||||
+ /* Can we recycle this skb? If we can then it will be much faster
|
||||
+ * for us to recycle this one later than to allocate a new one
|
||||
+ * from scratch.
|
||||
+ */
|
||||
+ if (likely(skb->head) && likely(skb_recycler_consume(skb)))
|
||||
+ return;
|
||||
+
|
||||
+#ifdef CONFIG_TRACEPOINTS
|
||||
trace_consume_skb(skb, __builtin_return_address(0));
|
||||
- __kfree_skb(skb);
|
||||
+#endif
|
||||
+ /* We're not recycling so now we need to do the rest of what we would
|
||||
+ * have done in __kfree_skb (above and beyond the skb_release_head_state
|
||||
+ * that we already did).
|
||||
+ */
|
||||
+ if (likely(skb->head))
|
||||
+ skb_release_data(skb, SKB_CONSUMED, false);
|
||||
+ kfree_skbmem(skb);
|
||||
}
|
||||
EXPORT_SYMBOL(consume_skb);
|
||||
#endif
|
||||
@@ -2107,6 +2192,8 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
|
||||
if (skb_pfmemalloc(skb))
|
||||
gfp_mask |= __GFP_MEMALLOC;
|
||||
|
||||
+ size = SKB_DATA_ALIGN(size);
|
||||
+ size += SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
|
||||
data = kmalloc_reserve(&size, gfp_mask, NUMA_NO_NODE, NULL);
|
||||
if (!data)
|
||||
goto nodata;
|
||||
@@ -4854,6 +4941,10 @@ static void skb_extensions_init(void) {}
|
||||
|
||||
void __init skb_init(void)
|
||||
{
|
||||
+ skb_data_cache = kmem_cache_create_usercopy("skb_data_cache",
|
||||
+ SKB_DATA_CACHE_SIZE,
|
||||
+ 0, SLAB_PANIC, 0, SKB_DATA_CACHE_SIZE,
|
||||
+ NULL);
|
||||
skbuff_cache = kmem_cache_create_usercopy("skbuff_head_cache",
|
||||
sizeof(struct sk_buff),
|
||||
0,
|
||||
@@ -4879,6 +4970,7 @@ void __init skb_init(void)
|
||||
SKB_SMALL_HEAD_HEADROOM,
|
||||
NULL);
|
||||
skb_extensions_init();
|
||||
+ skb_recycler_init();
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -6382,6 +6474,8 @@ static int pskb_carve_inside_header(struct sk_buff *skb, const u32 off,
|
||||
if (skb_pfmemalloc(skb))
|
||||
gfp_mask |= __GFP_MEMALLOC;
|
||||
|
||||
+ size = SKB_DATA_ALIGN(size);
|
||||
+ size += SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
|
||||
data = kmalloc_reserve(&size, gfp_mask, NUMA_NO_NODE, NULL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
@@ -6498,6 +6592,8 @@ static int pskb_carve_inside_nonlinear(struct sk_buff *skb, const u32 off,
|
||||
if (skb_pfmemalloc(skb))
|
||||
gfp_mask |= __GFP_MEMALLOC;
|
||||
|
||||
+ size = SKB_DATA_ALIGN(size);
|
||||
+ size += SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
|
||||
data = kmalloc_reserve(&size, gfp_mask, NUMA_NO_NODE, NULL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
|
@ -0,0 +1,99 @@
|
|||
--- a/arch/arm64/boot/dts/qcom/ipq6010-wax214.dts
|
||||
+++ b/arch/arm64/boot/dts/qcom/ipq6010-wax214.dts
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
chosen {
|
||||
stdout-path = "serial0:115200n8";
|
||||
- bootargs-append = " root=/dev/ubiblock0_1";
|
||||
+ bootargs-append = " coherent_pool=2M swiotlb=noforce root=/dev/ubiblock0_1";
|
||||
};
|
||||
|
||||
keys {
|
||||
--- a/arch/arm64/boot/dts/qcom/ipq8070-cax1800.dts
|
||||
+++ b/arch/arm64/boot/dts/qcom/ipq8070-cax1800.dts
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
chosen {
|
||||
stdout-path = "serial0:115200n8";
|
||||
- bootargs-append = " root=/dev/ubiblock0_1";
|
||||
+ bootargs-append = " coherent_pool=2M swiotlb=noforce root=/dev/ubiblock0_1";
|
||||
};
|
||||
|
||||
keys {
|
||||
--- a/arch/arm64/boot/dts/qcom/ipq8070-rm2-6.dts
|
||||
+++ b/arch/arm64/boot/dts/qcom/ipq8070-rm2-6.dts
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
chosen {
|
||||
stdout-path = "serial0:115200n8";
|
||||
- bootargs-append = " root=/dev/ubiblock0_1";
|
||||
+ bootargs-append = " coherent_pool=2M swiotlb=noforce root=/dev/ubiblock0_1";
|
||||
};
|
||||
|
||||
keys {
|
||||
--- a/arch/arm64/boot/dts/qcom/ipq8071-ax3600.dtsi
|
||||
+++ b/arch/arm64/boot/dts/qcom/ipq8071-ax3600.dtsi
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
chosen {
|
||||
stdout-path = "serial0:115200n8";
|
||||
- bootargs-append = " root=/dev/ubiblock0_0";
|
||||
+ bootargs-append = " coherent_pool=2M swiotlb=noforce root=/dev/ubiblock0_0";
|
||||
};
|
||||
|
||||
keys {
|
||||
--- a/arch/arm64/boot/dts/qcom/ipq8071-mf269.dts
|
||||
+++ b/arch/arm64/boot/dts/qcom/ipq8071-mf269.dts
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
chosen {
|
||||
stdout-path = "serial0:115200n8";
|
||||
- bootargs-append = " root=/dev/ubiblock0_0";
|
||||
+ bootargs-append = " coherent_pool=2M swiotlb=noforce root=/dev/ubiblock0_0";
|
||||
};
|
||||
|
||||
keys {
|
||||
--- a/arch/arm64/boot/dts/qcom/ipq8072-ax880.dts
|
||||
+++ b/arch/arm64/boot/dts/qcom/ipq8072-ax880.dts
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
chosen {
|
||||
stdout-path = "serial0:115200n8";
|
||||
- bootargs-append = " root=/dev/ubiblock0_1";
|
||||
+ bootargs-append = " coherent_pool=2M swiotlb=noforce root=/dev/ubiblock0_1";
|
||||
};
|
||||
|
||||
keys {
|
||||
--- a/arch/arm64/boot/dts/qcom/ipq8072-wax218.dts
|
||||
+++ b/arch/arm64/boot/dts/qcom/ipq8072-wax218.dts
|
||||
@@ -27,7 +27,7 @@
|
||||
* Netgear's U-Boot adds "ubi.mtd=rootfs root=mtd:ubi_rootfs"
|
||||
* That fails to create a UBI block device, so add it here.
|
||||
*/
|
||||
- bootargs-append = " ubi.block=0,rootfs root=/dev/ubiblock0_1";
|
||||
+ bootargs-append = " coherent_pool=2M swiotlb=noforce ubi.block=0,rootfs root=/dev/ubiblock0_1";
|
||||
};
|
||||
|
||||
keys {
|
||||
--- a/arch/arm64/boot/dts/qcom/ipq8072-wpq873.dts
|
||||
+++ b/arch/arm64/boot/dts/qcom/ipq8072-wpq873.dts
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
chosen {
|
||||
stdout-path = "serial0:115200n8";
|
||||
- bootargs-append = " root=/dev/ubiblock0_1";
|
||||
+ bootargs-append = " coherent_pool=2M swiotlb=noforce root=/dev/ubiblock0_1";
|
||||
};
|
||||
|
||||
keys {
|
||||
--- a/arch/arm64/boot/dts/qcom/ipq8174-mx4200.dtsi
|
||||
+++ b/arch/arm64/boot/dts/qcom/ipq8174-mx4200.dtsi
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
chosen {
|
||||
stdout-path = "serial0:115200n8";
|
||||
- bootargs-append = " root=/dev/ubiblock0_0";
|
||||
+ bootargs-append = " coherent_pool=2M swiotlb=noforce root=/dev/ubiblock0_0";
|
||||
};
|
||||
|
||||
keys {
|
|
@ -0,0 +1,10 @@
|
|||
--- a/crypto/algapi.c
|
||||
+++ b/crypto/algapi.c
|
||||
@@ -341,7 +341,6 @@ __crypto_register_alg(struct crypto_alg
|
||||
}
|
||||
|
||||
if (!strcmp(q->cra_driver_name, alg->cra_name) ||
|
||||
- !strcmp(q->cra_driver_name, alg->cra_driver_name) ||
|
||||
!strcmp(q->cra_name, alg->cra_driver_name))
|
||||
goto err;
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
--- a/drivers/mtd/mtdblock.c
|
||||
+++ b/drivers/mtd/mtdblock.c
|
||||
@@ -261,10 +261,6 @@ static int mtdblock_open(struct mtd_blkt
|
||||
return 0;
|
||||
}
|
||||
|
||||
- if (mtd_type_is_nand(mbd->mtd))
|
||||
- pr_warn_ratelimited("%s: MTD device '%s' is NAND, please consider using UBI block devices instead.\n",
|
||||
- mbd->tr->name, mbd->mtd->name);
|
||||
-
|
||||
/* OK, it's not open. Create cache info for it */
|
||||
mtdblk->count = 1;
|
||||
mutex_init(&mtdblk->cache_mutex);
|
Loading…
Reference in a new issue