Merge Official Source
Signed-off-by: Tianling Shen <cnsztl@immortalwrt.org>
This commit is contained in:
@@ -93,6 +93,7 @@ zyxel,nbg6616)
|
||||
ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x10000" "0x10000"
|
||||
;;
|
||||
aruba,ap-105|\
|
||||
aruba,ap-115|\
|
||||
aruba,ap-175|\
|
||||
dongwon,dw02-412h-64m|\
|
||||
dongwon,dw02-412h-128m|\
|
||||
|
||||
@@ -197,7 +197,7 @@ $(eval $(call KernelPackage,nf-flow))
|
||||
define KernelPackage/nf-socket
|
||||
SUBMENU:=$(NF_MENU)
|
||||
TITLE:=Netfilter socket lookup support
|
||||
KCONFIG:= $(KCOFNIG_NF_SOCKET)
|
||||
KCONFIG:= $(KCONFIG_NF_SOCKET)
|
||||
FILES:=$(foreach mod,$(NF_SOCKET-m),$(LINUX_DIR)/net/$(mod).ko)
|
||||
AUTOLOAD:=$(call AutoProbe,$(notdir $(NF_SOCKET-m)))
|
||||
endef
|
||||
@@ -208,7 +208,7 @@ $(eval $(call KernelPackage,nf-socket))
|
||||
define KernelPackage/nf-tproxy
|
||||
SUBMENU:=$(NF_MENU)
|
||||
TITLE:=Netfilter tproxy support
|
||||
KCONFIG:= $(KCOFNIG_NF_TPROXY)
|
||||
KCONFIG:= $(KCONFIG_NF_TPROXY)
|
||||
FILES:=$(foreach mod,$(NF_TPROXY-m),$(LINUX_DIR)/net/$(mod).ko)
|
||||
AUTOLOAD:=$(call AutoProbe,$(notdir $(NF_TPROXY-m)))
|
||||
endef
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
From cdf461888f900c3a149b10a04d72b4a590ecdec3 Mon Sep 17 00:00:00 2001
|
||||
From: David Bauer <mail@david-bauer.net>
|
||||
Date: Tue, 16 May 2023 23:11:32 +0200
|
||||
Subject: [PATCH] mac80211: always use mac80211 loss detection
|
||||
|
||||
ath10k does not report excessive loss in case of broken block-ack
|
||||
sessions. The loss is communicated to the host-os, but ath10k does not
|
||||
trigger a low-ack events by itself.
|
||||
|
||||
The mac80211 framework for loss detection however detects this
|
||||
circumstance well in case of ath10k. So use it regardless of ath10k's
|
||||
own loss detection mechanism.
|
||||
|
||||
Patching this in mac80211 does allow this hack to be used with any
|
||||
flavor of ath10k/ath11k.
|
||||
|
||||
Signed-off-by: David Bauer <mail@david-bauer.net>
|
||||
---
|
||||
net/mac80211/status.c | 6 ------
|
||||
1 file changed, 6 deletions(-)
|
||||
|
||||
--- a/net/mac80211/status.c
|
||||
+++ b/net/mac80211/status.c
|
||||
@@ -794,12 +794,6 @@ static void ieee80211_lost_packet(struct
|
||||
unsigned long pkt_time = STA_LOST_PKT_TIME;
|
||||
unsigned int pkt_thr = STA_LOST_PKT_THRESHOLD;
|
||||
|
||||
- /* If driver relies on its own algorithm for station kickout, skip
|
||||
- * mac80211 packet loss mechanism.
|
||||
- */
|
||||
- if (ieee80211_hw_check(&sta->local->hw, REPORTS_LOW_ACK))
|
||||
- return;
|
||||
-
|
||||
/* This packet was aggregated but doesn't carry status info */
|
||||
if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
|
||||
!(info->flags & IEEE80211_TX_STAT_AMPDU))
|
||||
239
target/linux/ath79/dts/qca9558_aruba_ap-115.dts
Normal file
239
target/linux/ath79/dts/qca9558_aruba_ap-115.dts
Normal file
@@ -0,0 +1,239 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
|
||||
|
||||
#include "qca955x.dtsi"
|
||||
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/input/input.h>
|
||||
|
||||
/ {
|
||||
compatible = "aruba,ap-115", "qca,qca9558";
|
||||
model = "Aruba AP-115";
|
||||
|
||||
aliases {
|
||||
led-boot = &led_power_green;
|
||||
led-failsafe = &led_power_red;
|
||||
led-running = &led_power_green;
|
||||
led-upgrade = &led_power_red;
|
||||
label-mac-device = ð0;
|
||||
};
|
||||
|
||||
chosen {
|
||||
bootargs = "console=ttyS0,9600n8";
|
||||
};
|
||||
|
||||
/**
|
||||
* Currently unused GPIOs in OpenWrt:
|
||||
*
|
||||
* TPM-CLK: 19
|
||||
* TPM-IO: 20
|
||||
* ETH-PHY-Interrupt: 11
|
||||
* Power-DC: 22
|
||||
* Power-PoE: 23
|
||||
* Power-PoE-8023af: 17
|
||||
*/
|
||||
|
||||
leds {
|
||||
compatible = "gpio-leds";
|
||||
|
||||
led_power_green: power-green {
|
||||
label = "green:power";
|
||||
gpios = <&gpio 4 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
|
||||
led_power_red: power-red {
|
||||
label = "red:power";
|
||||
gpios = <&gpio 2 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
|
||||
radio-24-green {
|
||||
label = "green:radio-24";
|
||||
gpios = <&gpio 13 GPIO_ACTIVE_LOW>;
|
||||
linux,default-trigger = "phy0tpt";
|
||||
};
|
||||
|
||||
radio-24-amber {
|
||||
label = "amber:radio-24";
|
||||
gpios = <&gpio 0 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
|
||||
radio-5-green {
|
||||
label = "green:radio-5";
|
||||
gpios = <&gpio 1 GPIO_ACTIVE_LOW>;
|
||||
linux,default-trigger = "phy1tpt";
|
||||
};
|
||||
|
||||
radio-5-amber {
|
||||
label = "amber:radio-5";
|
||||
gpios = <&gpio 21 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
};
|
||||
|
||||
keys {
|
||||
compatible = "gpio-keys";
|
||||
|
||||
reset {
|
||||
label = "reset";
|
||||
linux,code = <KEY_RESTART>;
|
||||
gpios = <&gpio 18 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
};
|
||||
|
||||
reg_usb_vbus {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "usb_vbus";
|
||||
regulator-min-microvolt = <5000000>;
|
||||
regulator-max-microvolt = <5000000>;
|
||||
gpio = <&gpio 3 GPIO_ACTIVE_HIGH>;
|
||||
enable-active-high;
|
||||
regulator-always-on;
|
||||
};
|
||||
};
|
||||
|
||||
&pcie0 {
|
||||
status = "okay";
|
||||
|
||||
ath9k: wifi@0,0 {
|
||||
compatible = "pci168c,0033";
|
||||
reg = <0x0000 0 0 0 0>;
|
||||
qca,no-eeprom;
|
||||
|
||||
nvmem-cells = <&macaddr_oemdata_1d>;
|
||||
nvmem-cell-names = "mac-address";
|
||||
|
||||
mac-address-increment = <1>;
|
||||
};
|
||||
};
|
||||
|
||||
&pinmux {
|
||||
/**
|
||||
* Ugly hack ahead!
|
||||
*
|
||||
* GPIO05: Bank1-CS / Bank2-CLK
|
||||
* GPIO14: Bank1-CLK / Bank2-CS
|
||||
*
|
||||
* We can not support this with OpenWrt, as this
|
||||
* would require us to influence the pinmux based on the CS.
|
||||
*
|
||||
* We force-select Bank 1. Remember to blame Aruba for that.
|
||||
*/
|
||||
cs0_pin5: spi-cs0-pin5 {
|
||||
pinctrl-single,bits = <0x4 0x900 0xff00>;
|
||||
};
|
||||
|
||||
clk_pin14: spi-cs1-pin14 {
|
||||
pinctrl-single,bits = <0xc 0x0a0000 0xff0000>;
|
||||
};
|
||||
};
|
||||
|
||||
&spi {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&cs0_pin5 &clk_pin14>;
|
||||
status = "okay";
|
||||
|
||||
flash@0 {
|
||||
compatible = "jedec,spi-nor";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <25000000>;
|
||||
|
||||
partitions {
|
||||
compatible = "fixed-partitions";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
partition@1 {
|
||||
label = "flash-full";
|
||||
reg = <0x0 0x1000000>;
|
||||
read-only;
|
||||
};
|
||||
|
||||
uboot: partition@0 {
|
||||
label = "u-boot";
|
||||
reg = <0x000000 0x040000>;
|
||||
read-only;
|
||||
};
|
||||
|
||||
/* Here be dragons */
|
||||
|
||||
partition@100000 {
|
||||
compatible = "denx,uimage";
|
||||
label = "firmware";
|
||||
reg = <0x100000 0xe00000>;
|
||||
};
|
||||
|
||||
oemdata: partition@fe0000 {
|
||||
label = "oemdata";
|
||||
reg = <0xfe0000 0x010000>;
|
||||
read-only;
|
||||
};
|
||||
|
||||
partition@ff0000 {
|
||||
label = "u-boot-env";
|
||||
reg = <0xff0000 0x10000>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&wmac {
|
||||
status = "okay";
|
||||
|
||||
qca,no-eeprom;
|
||||
nvmem-cells = <&macaddr_oemdata_1d>;
|
||||
nvmem-cell-names = "mac-address";
|
||||
};
|
||||
|
||||
&mdio0 {
|
||||
status = "okay";
|
||||
|
||||
phy0: ethernet-phy@0 {
|
||||
reg = <0>;
|
||||
|
||||
reset-gpios = <&gpio 12 GPIO_ACTIVE_LOW>;
|
||||
reset-assert-us = <10000>;
|
||||
reset-deassert-us = <10000>;
|
||||
|
||||
eee-broken-100tx;
|
||||
eee-broken-1000t;
|
||||
};
|
||||
};
|
||||
|
||||
ð0 {
|
||||
status = "okay";
|
||||
|
||||
nvmem-cells = <&macaddr_oemdata_1d>;
|
||||
nvmem-cell-names = "mac-address";
|
||||
|
||||
phy-handle = <&phy0>;
|
||||
phy-mode = "rgmii-id";
|
||||
|
||||
pll-data = <0xa6000000 0xa0000101 0xa0001313>;
|
||||
|
||||
gmac-config {
|
||||
device = <&gmac>;
|
||||
ge0-sgmii = <0>;
|
||||
txen-delay = <3>;
|
||||
txd-delay = <3>;
|
||||
rxdv-delay = <3>;
|
||||
rxd-delay = <3>;
|
||||
rgmii-enabled = <1>;
|
||||
};
|
||||
};
|
||||
|
||||
&oemdata {
|
||||
compatible = "nvmem-cells";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
macaddr_oemdata_1d: macaddr@1d {
|
||||
reg = <0x1d 0x6>;
|
||||
};
|
||||
};
|
||||
|
||||
&usb_phy0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&usb0 {
|
||||
dr_mode = "host";
|
||||
status = "okay";
|
||||
};
|
||||
@@ -12,6 +12,9 @@ case "$FIRMWARE" in
|
||||
8dev,lima)
|
||||
caldata_extract "art" 0x1000 0x800
|
||||
;;
|
||||
aruba,ap-115)
|
||||
caldata_extract "oemdata" 0x1000 0x440
|
||||
;;
|
||||
asus,pl-ac56|\
|
||||
asus,rp-ac51|\
|
||||
asus,rp-ac66)
|
||||
@@ -79,6 +82,9 @@ case "$FIRMWARE" in
|
||||
;;
|
||||
"ath9k-eeprom-pci-0000:00:00.0.bin")
|
||||
case $board in
|
||||
aruba,ap-115)
|
||||
caldata_extract "oemdata" 0x5000 0x440
|
||||
;;
|
||||
avm,fritz300e)
|
||||
caldata_extract_reverse "urloader" 0x1541 0x440
|
||||
;;
|
||||
|
||||
@@ -413,6 +413,21 @@ define Device/aruba_ap-105
|
||||
endef
|
||||
TARGET_DEVICES += aruba_ap-105
|
||||
|
||||
define Device/aruba_ap-115
|
||||
SOC := qca9558
|
||||
DEVICE_VENDOR := Aruba
|
||||
DEVICE_MODEL := AP-115
|
||||
IMAGE_SIZE := 16000k
|
||||
DEVICE_PACKAGES := kmod-usb2
|
||||
LOADER_TYPE := bin
|
||||
LOADER_FLASH_OFFS := 0x102000
|
||||
COMPILE := loader-$(1).bin
|
||||
COMPILE/loader-$(1).bin := loader-okli-compile
|
||||
KERNEL := kernel-bin | append-dtb | lzma | uImage lzma -M 0x4f4b4c49 | loader-okli $(1) 8128 | uImage none
|
||||
KERNEL_INITRAMFS := kernel-bin | append-dtb | lzma | loader-kernel
|
||||
endef
|
||||
TARGET_DEVICES += aruba_ap-115
|
||||
|
||||
define Device/aruba_ap-175
|
||||
SOC := ar7161
|
||||
DEVICE_VENDOR := Aruba
|
||||
|
||||
@@ -6,6 +6,10 @@
|
||||
board_config_update
|
||||
|
||||
case "$(board_name)" in
|
||||
arcadyan,ar7516)
|
||||
ucidef_set_led_netdev "wan" "WAN" "green:wan" "wan"
|
||||
ucidef_set_led_netdev "wlan0" "WiFi" "green:wifi" "phy0-ap0"
|
||||
;;
|
||||
nucom,r5010unv2 |\
|
||||
sercomm,ad1018)
|
||||
ucidef_set_led_usbport "usb" "USB" "green:usb" "usb1-port1" "usb2-port1"
|
||||
|
||||
@@ -5,6 +5,10 @@
|
||||
board_config_update
|
||||
|
||||
case "$(board_name)" in
|
||||
arcadyan,ar7516)
|
||||
ucidef_set_bridge_device switch
|
||||
ucidef_set_interfaces_lan_wan "lan1 lan2 lan3" "wan"
|
||||
;;
|
||||
comtrend,ar-5381u |\
|
||||
comtrend,ar-5387un |\
|
||||
nucom,r5010unv2)
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
. /lib/functions.sh
|
||||
|
||||
case "$(board_name)" in
|
||||
arcadyan,ar7516 |\
|
||||
comtrend,ar-5381u |\
|
||||
comtrend,ar-5387un |\
|
||||
nucom,r5010unv2)
|
||||
|
||||
186
target/linux/bmips/dts/bcm6328-arcadyan-ar7516.dts
Normal file
186
target/linux/bmips/dts/bcm6328-arcadyan-ar7516.dts
Normal file
@@ -0,0 +1,186 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "bcm6328.dtsi"
|
||||
|
||||
/ {
|
||||
model = "Arcadyan AR7516";
|
||||
compatible = "arcadyan,ar7516", "brcm,bcm6328";
|
||||
|
||||
aliases {
|
||||
led-failsafe = &led_upgrade_green;
|
||||
led-upgrade = &led_upgrade_green;
|
||||
};
|
||||
|
||||
keys {
|
||||
compatible = "gpio-keys-polled";
|
||||
poll-interval = <100>;
|
||||
|
||||
reset {
|
||||
label = "reset";
|
||||
gpios = <&gpio 23 GPIO_ACTIVE_LOW>;
|
||||
linux,code = <KEY_RESTART>;
|
||||
debounce-interval = <60>;
|
||||
};
|
||||
|
||||
wps {
|
||||
label = "wps";
|
||||
gpios = <&gpio 24 GPIO_ACTIVE_LOW>;
|
||||
linux,code = <KEY_WPS_BUTTON>;
|
||||
debounce-interval = <60>;
|
||||
};
|
||||
};
|
||||
|
||||
bcm43227-sprom {
|
||||
compatible = "brcm,bcma-sprom";
|
||||
|
||||
pci-bus = <1>;
|
||||
pci-dev = <0>;
|
||||
|
||||
nvmem-cells = <&macaddr_cfe_6a0>;
|
||||
nvmem-cell-names = "mac-address";
|
||||
mac-address-increment = <1>;
|
||||
|
||||
brcm,sprom = "brcm/bcm43227-sprom.bin";
|
||||
};
|
||||
};
|
||||
|
||||
&ehci {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
ðernet {
|
||||
status = "okay";
|
||||
|
||||
nvmem-cells = <&macaddr_cfe_6a0>;
|
||||
nvmem-cell-names = "mac-address";
|
||||
};
|
||||
|
||||
&hsspi {
|
||||
status = "okay";
|
||||
|
||||
flash@0 {
|
||||
compatible = "jedec,spi-nor";
|
||||
spi-max-frequency = <16666667>;
|
||||
spi-tx-bus-width = <2>;
|
||||
spi-rx-bus-width = <2>;
|
||||
reg = <0>;
|
||||
|
||||
partitions {
|
||||
compatible = "fixed-partitions";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
cfe: partition@0 {
|
||||
label = "cfe";
|
||||
reg = <0x000000 0x010000>;
|
||||
read-only;
|
||||
};
|
||||
|
||||
partition@10000 {
|
||||
compatible = "brcm,bcm963xx-imagetag";
|
||||
label = "firmware";
|
||||
reg = <0x010000 0x7e0000>;
|
||||
};
|
||||
|
||||
partition@7f0000 {
|
||||
label = "nvram";
|
||||
reg = <0x7f0000 0x010000>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&leds {
|
||||
status = "okay";
|
||||
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_ephy0_act_led &pinctrl_ephy1_act_led
|
||||
&pinctrl_ephy2_act_led &pinctrl_ephy3_act_led
|
||||
&pinctrl_leds>;
|
||||
|
||||
led_upgrade_green: led@1 {
|
||||
reg = <1>;
|
||||
label = "green:upgrade";
|
||||
};
|
||||
|
||||
led@6 {
|
||||
reg = <6>;
|
||||
active-low;
|
||||
label = "green:wan";
|
||||
};
|
||||
|
||||
led@7 {
|
||||
reg = <7>;
|
||||
active-low;
|
||||
label = "green:wifi";
|
||||
};
|
||||
};
|
||||
|
||||
&ohci {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&pcie {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&pinctrl {
|
||||
pinctrl_leds: leds {
|
||||
function = "led";
|
||||
pins = "gpio1", "gpio6", "gpio7";
|
||||
};
|
||||
};
|
||||
|
||||
&switch0 {
|
||||
ports {
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
label = "lan1";
|
||||
|
||||
phy-handle = <&phy1>;
|
||||
phy-mode = "mii";
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
label = "lan2";
|
||||
|
||||
phy-handle = <&phy2>;
|
||||
phy-mode = "mii";
|
||||
};
|
||||
|
||||
port@2 {
|
||||
reg = <2>;
|
||||
label = "lan3";
|
||||
|
||||
phy-handle = <&phy3>;
|
||||
phy-mode = "mii";
|
||||
};
|
||||
|
||||
port@3 {
|
||||
reg = <3>;
|
||||
label = "wan";
|
||||
|
||||
phy-handle = <&phy4>;
|
||||
phy-mode = "mii";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&uart0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&usbh {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&cfe {
|
||||
compatible = "nvmem-cells";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
macaddr_cfe_6a0: macaddr@6a0 {
|
||||
reg = <0x6a0 0x6>;
|
||||
};
|
||||
};
|
||||
@@ -1,5 +1,18 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
define Device/arcadyan_ar7516
|
||||
$(Device/bcm63xx-cfe)
|
||||
DEVICE_VENDOR := Arcadyan
|
||||
DEVICE_MODEL := AR7516
|
||||
CHIP_ID := 6328
|
||||
CFE_BOARD_ID := AR7516AAW
|
||||
FLASH_MB := 8
|
||||
DEVICE_PACKAGES += $(USB2_PACKAGES) \
|
||||
$(B43_PACKAGES) broadcom-43227-sprom \
|
||||
kmod-leds-bcm6328
|
||||
endef
|
||||
TARGET_DEVICES += arcadyan_ar7516
|
||||
|
||||
define Device/comtrend_ar-5381u
|
||||
$(Device/bcm63xx-cfe)
|
||||
DEVICE_VENDOR := Comtrend
|
||||
|
||||
@@ -1,846 +0,0 @@
|
||||
From 11c3fae5afa6cac444d12622e2cf5af60a99c1ef Mon Sep 17 00:00:00 2001
|
||||
From: OpenWrt community <openwrt-devel@lists.openwrt.org>
|
||||
Date: Wed, 13 Jul 2022 13:43:15 +0200
|
||||
Subject: [PATCH] net/bridge: add bridge offload
|
||||
|
||||
---
|
||||
include/linux/if_bridge.h | 1 +
|
||||
net/bridge/Makefile | 2 +-
|
||||
net/bridge/br.c | 8 +
|
||||
net/bridge/br_device.c | 2 +
|
||||
net/bridge/br_fdb.c | 5 +
|
||||
net/bridge/br_forward.c | 3 +
|
||||
net/bridge/br_if.c | 6 +-
|
||||
net/bridge/br_input.c | 5 +
|
||||
net/bridge/br_offload.c | 438 ++++++++++++++++++++++++++++++++
|
||||
net/bridge/br_private.h | 22 +-
|
||||
net/bridge/br_private_offload.h | 23 ++
|
||||
net/bridge/br_stp.c | 3 +
|
||||
net/bridge/br_sysfs_br.c | 35 +++
|
||||
net/bridge/br_sysfs_if.c | 2 +
|
||||
net/bridge/br_vlan_tunnel.c | 3 +
|
||||
15 files changed, 555 insertions(+), 3 deletions(-)
|
||||
create mode 100644 net/bridge/br_offload.c
|
||||
create mode 100644 net/bridge/br_private_offload.h
|
||||
|
||||
--- a/include/linux/if_bridge.h
|
||||
+++ b/include/linux/if_bridge.h
|
||||
@@ -59,6 +59,7 @@ struct br_ip_list {
|
||||
#define BR_MRP_LOST_IN_CONT BIT(19)
|
||||
#define BR_TX_FWD_OFFLOAD BIT(20)
|
||||
#define BR_BPDU_FILTER BIT(21)
|
||||
+#define BR_OFFLOAD BIT(22)
|
||||
|
||||
#define BR_DEFAULT_AGEING_TIME (300 * HZ)
|
||||
|
||||
--- a/net/bridge/Makefile
|
||||
+++ b/net/bridge/Makefile
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
obj-$(CONFIG_BRIDGE) += bridge.o
|
||||
|
||||
-bridge-y := br.o br_device.o br_fdb.o br_forward.o br_if.o br_input.o \
|
||||
+bridge-y := br.o br_device.o br_fdb.o br_forward.o br_if.o br_input.o br_offload.o \
|
||||
br_ioctl.o br_stp.o br_stp_bpdu.o \
|
||||
br_stp_if.o br_stp_timer.o br_netlink.o \
|
||||
br_netlink_tunnel.o br_arp_nd_proxy.o
|
||||
--- a/net/bridge/br.c
|
||||
+++ b/net/bridge/br.c
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <net/switchdev.h>
|
||||
|
||||
#include "br_private.h"
|
||||
+#include "br_private_offload.h"
|
||||
|
||||
/*
|
||||
* Handle changes in state of network devices enslaved to a bridge.
|
||||
@@ -381,6 +382,10 @@ static int __init br_init(void)
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
+ err = br_offload_init();
|
||||
+ if (err)
|
||||
+ goto err_out0;
|
||||
+
|
||||
err = register_pernet_subsys(&br_net_ops);
|
||||
if (err)
|
||||
goto err_out1;
|
||||
@@ -430,6 +435,8 @@ err_out3:
|
||||
err_out2:
|
||||
unregister_pernet_subsys(&br_net_ops);
|
||||
err_out1:
|
||||
+ br_offload_fini();
|
||||
+err_out0:
|
||||
br_fdb_fini();
|
||||
err_out:
|
||||
stp_proto_unregister(&br_stp_proto);
|
||||
@@ -452,6 +459,7 @@ static void __exit br_deinit(void)
|
||||
#if IS_ENABLED(CONFIG_ATM_LANE)
|
||||
br_fdb_test_addr_hook = NULL;
|
||||
#endif
|
||||
+ br_offload_fini();
|
||||
br_fdb_fini();
|
||||
}
|
||||
|
||||
--- a/net/bridge/br_device.c
|
||||
+++ b/net/bridge/br_device.c
|
||||
@@ -524,6 +524,8 @@ void br_dev_setup(struct net_device *dev
|
||||
br->bridge_hello_time = br->hello_time = 2 * HZ;
|
||||
br->bridge_forward_delay = br->forward_delay = 15 * HZ;
|
||||
br->bridge_ageing_time = br->ageing_time = BR_DEFAULT_AGEING_TIME;
|
||||
+ br->offload_cache_size = 128;
|
||||
+ br->offload_cache_reserved = 8;
|
||||
dev->max_mtu = ETH_MAX_MTU;
|
||||
|
||||
br_netfilter_rtable_init(br);
|
||||
--- a/net/bridge/br_fdb.c
|
||||
+++ b/net/bridge/br_fdb.c
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <net/switchdev.h>
|
||||
#include <trace/events/bridge.h>
|
||||
#include "br_private.h"
|
||||
+#include "br_private_offload.h"
|
||||
|
||||
static const struct rhashtable_params br_fdb_rht_params = {
|
||||
.head_offset = offsetof(struct net_bridge_fdb_entry, rhnode),
|
||||
@@ -518,6 +519,8 @@ static struct net_bridge_fdb_entry *fdb_
|
||||
fdb->key.vlan_id = vid;
|
||||
fdb->flags = flags;
|
||||
fdb->updated = fdb->used = jiffies;
|
||||
+ INIT_HLIST_HEAD(&fdb->offload_in);
|
||||
+ INIT_HLIST_HEAD(&fdb->offload_out);
|
||||
if (rhashtable_lookup_insert_fast(&br->fdb_hash_tbl,
|
||||
&fdb->rhnode,
|
||||
br_fdb_rht_params)) {
|
||||
@@ -794,6 +797,8 @@ static void fdb_notify(struct net_bridge
|
||||
struct sk_buff *skb;
|
||||
int err = -ENOBUFS;
|
||||
|
||||
+ br_offload_fdb_update(fdb);
|
||||
+
|
||||
if (swdev_notify)
|
||||
br_switchdev_fdb_notify(br, fdb, type);
|
||||
|
||||
--- a/net/bridge/br_forward.c
|
||||
+++ b/net/bridge/br_forward.c
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <linux/if_vlan.h>
|
||||
#include <linux/netfilter_bridge.h>
|
||||
#include "br_private.h"
|
||||
+#include "br_private_offload.h"
|
||||
|
||||
/* Don't forward packets to originating port or forwarding disabled */
|
||||
static inline int should_deliver(const struct net_bridge_port *p,
|
||||
@@ -32,6 +33,8 @@ static inline int should_deliver(const s
|
||||
|
||||
int br_dev_queue_push_xmit(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
+ br_offload_output(skb);
|
||||
+
|
||||
skb_push(skb, ETH_HLEN);
|
||||
if (!is_skb_forwardable(skb->dev, skb))
|
||||
goto drop;
|
||||
--- a/net/bridge/br_if.c
|
||||
+++ b/net/bridge/br_if.c
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <net/net_namespace.h>
|
||||
|
||||
#include "br_private.h"
|
||||
+#include "br_private_offload.h"
|
||||
|
||||
/*
|
||||
* Determine initial path cost based on speed.
|
||||
@@ -428,7 +429,7 @@ static struct net_bridge_port *new_nbp(s
|
||||
p->path_cost = port_cost(dev);
|
||||
p->priority = 0x8000 >> BR_PORT_BITS;
|
||||
p->port_no = index;
|
||||
- p->flags = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD;
|
||||
+ p->flags = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD | BR_OFFLOAD;
|
||||
br_init_port(p);
|
||||
br_set_state(p, BR_STATE_DISABLED);
|
||||
br_stp_port_timer_init(p);
|
||||
@@ -771,6 +772,9 @@ void br_port_flags_change(struct net_bri
|
||||
|
||||
if (mask & BR_NEIGH_SUPPRESS)
|
||||
br_recalculate_neigh_suppress_enabled(br);
|
||||
+
|
||||
+ if (mask & BR_OFFLOAD)
|
||||
+ br_offload_port_state(p);
|
||||
}
|
||||
|
||||
bool br_port_flag_is_set(const struct net_device *dev, unsigned long flag)
|
||||
--- a/net/bridge/br_input.c
|
||||
+++ b/net/bridge/br_input.c
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <linux/rculist.h>
|
||||
#include "br_private.h"
|
||||
#include "br_private_tunnel.h"
|
||||
+#include "br_private_offload.h"
|
||||
|
||||
static int
|
||||
br_netif_receive_skb(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||
@@ -171,6 +172,7 @@ int br_handle_frame_finish(struct net *n
|
||||
dst->used = now;
|
||||
br_forward(dst->dst, skb, local_rcv, false);
|
||||
} else {
|
||||
+ br_offload_skb_disable(skb);
|
||||
if (!mcast_hit)
|
||||
br_flood(br, skb, pkt_type, local_rcv, false);
|
||||
else
|
||||
@@ -304,6 +306,9 @@ static rx_handler_result_t br_handle_fra
|
||||
memset(skb->cb, 0, sizeof(struct br_input_skb_cb));
|
||||
|
||||
p = br_port_get_rcu(skb->dev);
|
||||
+ if (br_offload_input(p, skb))
|
||||
+ return RX_HANDLER_CONSUMED;
|
||||
+
|
||||
if (p->flags & BR_VLAN_TUNNEL)
|
||||
br_handle_ingress_vlan_tunnel(skb, p, nbp_vlan_group_rcu(p));
|
||||
|
||||
--- /dev/null
|
||||
+++ b/net/bridge/br_offload.c
|
||||
@@ -0,0 +1,438 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0-only
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/workqueue.h>
|
||||
+#include "br_private.h"
|
||||
+#include "br_private_offload.h"
|
||||
+
|
||||
+static DEFINE_SPINLOCK(offload_lock);
|
||||
+
|
||||
+struct bridge_flow_key {
|
||||
+ u8 dest[ETH_ALEN];
|
||||
+ u8 src[ETH_ALEN];
|
||||
+#ifdef CONFIG_BRIDGE_VLAN_FILTERING
|
||||
+ u16 vlan_tag;
|
||||
+ bool vlan_present;
|
||||
+#endif
|
||||
+};
|
||||
+
|
||||
+struct bridge_flow {
|
||||
+ struct net_bridge_port *port;
|
||||
+ struct rhash_head node;
|
||||
+ struct bridge_flow_key key;
|
||||
+#ifdef CONFIG_BRIDGE_VLAN_FILTERING
|
||||
+ bool vlan_out_present;
|
||||
+ u16 vlan_out;
|
||||
+#endif
|
||||
+
|
||||
+ unsigned long used;
|
||||
+ struct net_bridge_fdb_entry *fdb_in, *fdb_out;
|
||||
+ struct hlist_node fdb_list_in, fdb_list_out;
|
||||
+
|
||||
+ struct rcu_head rcu;
|
||||
+};
|
||||
+
|
||||
+static const struct rhashtable_params flow_params = {
|
||||
+ .automatic_shrinking = true,
|
||||
+ .head_offset = offsetof(struct bridge_flow, node),
|
||||
+ .key_len = sizeof(struct bridge_flow_key),
|
||||
+ .key_offset = offsetof(struct bridge_flow, key),
|
||||
+};
|
||||
+
|
||||
+static struct kmem_cache *offload_cache __read_mostly;
|
||||
+
|
||||
+static void
|
||||
+flow_rcu_free(struct rcu_head *head)
|
||||
+{
|
||||
+ struct bridge_flow *flow;
|
||||
+
|
||||
+ flow = container_of(head, struct bridge_flow, rcu);
|
||||
+ kmem_cache_free(offload_cache, flow);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+__br_offload_flow_free(struct bridge_flow *flow)
|
||||
+{
|
||||
+ flow->used = 0;
|
||||
+ hlist_del(&flow->fdb_list_in);
|
||||
+ hlist_del(&flow->fdb_list_out);
|
||||
+
|
||||
+ call_rcu(&flow->rcu, flow_rcu_free);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+br_offload_flow_free(struct bridge_flow *flow)
|
||||
+{
|
||||
+ if (rhashtable_remove_fast(&flow->port->offload.rht, &flow->node,
|
||||
+ flow_params) != 0)
|
||||
+ return;
|
||||
+
|
||||
+ __br_offload_flow_free(flow);
|
||||
+}
|
||||
+
|
||||
+static bool
|
||||
+br_offload_flow_fdb_refresh_time(struct bridge_flow *flow,
|
||||
+ struct net_bridge_fdb_entry *fdb)
|
||||
+{
|
||||
+ if (!time_after(flow->used, fdb->updated))
|
||||
+ return false;
|
||||
+
|
||||
+ fdb->updated = flow->used;
|
||||
+
|
||||
+ return true;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static void
|
||||
+br_offload_flow_refresh_time(struct bridge_flow *flow)
|
||||
+{
|
||||
+ br_offload_flow_fdb_refresh_time(flow, flow->fdb_in);
|
||||
+ br_offload_flow_fdb_refresh_time(flow, flow->fdb_out);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+br_offload_destroy_cb(void *ptr, void *arg)
|
||||
+{
|
||||
+ struct bridge_flow *flow = ptr;
|
||||
+
|
||||
+ __br_offload_flow_free(flow);
|
||||
+}
|
||||
+
|
||||
+static bool
|
||||
+br_offload_need_gc(struct net_bridge_port *p)
|
||||
+{
|
||||
+ return (atomic_read(&p->offload.rht.nelems) +
|
||||
+ p->br->offload_cache_reserved) >= p->br->offload_cache_size;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+br_offload_gc_work(struct work_struct *work)
|
||||
+{
|
||||
+ struct rhashtable_iter hti;
|
||||
+ struct net_bridge_port *p;
|
||||
+ struct bridge_flow *gc_flow = NULL;
|
||||
+ struct bridge_flow *flow;
|
||||
+ unsigned long gc_used;
|
||||
+
|
||||
+ p = container_of(work, struct net_bridge_port, offload.gc_work);
|
||||
+
|
||||
+ if (!br_offload_need_gc(p))
|
||||
+ return;
|
||||
+
|
||||
+ rhashtable_walk_enter(&p->offload.rht, &hti);
|
||||
+ rhashtable_walk_start(&hti);
|
||||
+ while ((flow = rhashtable_walk_next(&hti)) != NULL) {
|
||||
+ unsigned long used;
|
||||
+
|
||||
+ if (IS_ERR(flow))
|
||||
+ continue;
|
||||
+
|
||||
+ used = READ_ONCE(flow->used);
|
||||
+ if (!used)
|
||||
+ continue;
|
||||
+
|
||||
+ if (gc_flow && !time_before(used, gc_used))
|
||||
+ continue;
|
||||
+
|
||||
+ gc_flow = flow;
|
||||
+ gc_used = used;
|
||||
+ }
|
||||
+ rhashtable_walk_stop(&hti);
|
||||
+ rhashtable_walk_exit(&hti);
|
||||
+
|
||||
+ if (!gc_flow)
|
||||
+ return;
|
||||
+
|
||||
+ spin_lock_bh(&offload_lock);
|
||||
+ if (br_offload_need_gc(p) && gc_flow &&
|
||||
+ gc_flow->used == gc_used)
|
||||
+ br_offload_flow_free(gc_flow);
|
||||
+ if (p->offload.enabled && br_offload_need_gc(p))
|
||||
+ queue_work(system_long_wq, work);
|
||||
+ spin_unlock_bh(&offload_lock);
|
||||
+
|
||||
+}
|
||||
+
|
||||
+void br_offload_port_state(struct net_bridge_port *p)
|
||||
+{
|
||||
+ struct net_bridge_port_offload *o = &p->offload;
|
||||
+ bool enabled = true;
|
||||
+ bool flush = false;
|
||||
+
|
||||
+ if (p->state != BR_STATE_FORWARDING ||
|
||||
+ !(p->flags & BR_OFFLOAD))
|
||||
+ enabled = false;
|
||||
+
|
||||
+ spin_lock_bh(&offload_lock);
|
||||
+ if (o->enabled == enabled)
|
||||
+ goto out;
|
||||
+
|
||||
+ if (enabled) {
|
||||
+ if (!o->gc_work.func)
|
||||
+ INIT_WORK(&o->gc_work, br_offload_gc_work);
|
||||
+ rhashtable_init(&o->rht, &flow_params);
|
||||
+ } else {
|
||||
+ flush = true;
|
||||
+ rhashtable_free_and_destroy(&o->rht, br_offload_destroy_cb, o);
|
||||
+ }
|
||||
+
|
||||
+ o->enabled = enabled;
|
||||
+
|
||||
+out:
|
||||
+ spin_unlock_bh(&offload_lock);
|
||||
+
|
||||
+ if (flush)
|
||||
+ flush_work(&o->gc_work);
|
||||
+}
|
||||
+
|
||||
+void br_offload_fdb_update(const struct net_bridge_fdb_entry *fdb)
|
||||
+{
|
||||
+ struct bridge_flow *f;
|
||||
+ struct hlist_node *tmp;
|
||||
+
|
||||
+ spin_lock_bh(&offload_lock);
|
||||
+
|
||||
+ hlist_for_each_entry_safe(f, tmp, &fdb->offload_in, fdb_list_in)
|
||||
+ br_offload_flow_free(f);
|
||||
+
|
||||
+ hlist_for_each_entry_safe(f, tmp, &fdb->offload_out, fdb_list_out)
|
||||
+ br_offload_flow_free(f);
|
||||
+
|
||||
+ spin_unlock_bh(&offload_lock);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+br_offload_prepare_key(struct net_bridge_port *p, struct bridge_flow_key *key,
|
||||
+ struct sk_buff *skb)
|
||||
+{
|
||||
+ memset(key, 0, sizeof(*key));
|
||||
+ memcpy(key, eth_hdr(skb), 2 * ETH_ALEN);
|
||||
+#ifdef CONFIG_BRIDGE_VLAN_FILTERING
|
||||
+ if (!br_opt_get(p->br, BROPT_VLAN_ENABLED))
|
||||
+ return;
|
||||
+
|
||||
+ if (!skb_vlan_tag_present(skb) || skb->vlan_proto != p->br->vlan_proto)
|
||||
+ return;
|
||||
+
|
||||
+ key->vlan_present = true;
|
||||
+ key->vlan_tag = skb_vlan_tag_get_id(skb);
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
+void br_offload_output(struct sk_buff *skb)
|
||||
+{
|
||||
+ struct net_bridge_port_offload *o;
|
||||
+ struct br_input_skb_cb *cb = (struct br_input_skb_cb *)skb->cb;
|
||||
+ struct net_bridge_port *p, *inp;
|
||||
+ struct net_device *dev;
|
||||
+ struct net_bridge_fdb_entry *fdb_in, *fdb_out;
|
||||
+ struct net_bridge_vlan_group *vg;
|
||||
+ struct bridge_flow_key key;
|
||||
+ struct bridge_flow *flow;
|
||||
+ u16 vlan;
|
||||
+
|
||||
+ if (!cb->offload)
|
||||
+ return;
|
||||
+
|
||||
+ rcu_read_lock();
|
||||
+
|
||||
+ p = br_port_get_rcu(skb->dev);
|
||||
+ if (!p)
|
||||
+ goto out;
|
||||
+
|
||||
+ o = &p->offload;
|
||||
+ if (!o->enabled)
|
||||
+ goto out;
|
||||
+
|
||||
+ if (atomic_read(&p->offload.rht.nelems) >= p->br->offload_cache_size)
|
||||
+ goto out;
|
||||
+
|
||||
+ dev = dev_get_by_index_rcu(dev_net(p->br->dev), cb->input_ifindex);
|
||||
+ if (!dev)
|
||||
+ goto out;
|
||||
+
|
||||
+ inp = br_port_get_rcu(dev);
|
||||
+ if (!inp)
|
||||
+ goto out;
|
||||
+
|
||||
+ vg = nbp_vlan_group_rcu(inp);
|
||||
+ vlan = cb->input_vlan_present ? cb->input_vlan_tag : br_get_pvid(vg);
|
||||
+ fdb_in = br_fdb_find_rcu(p->br, eth_hdr(skb)->h_source, vlan);
|
||||
+ if (!fdb_in || !fdb_in->dst)
|
||||
+ goto out;
|
||||
+
|
||||
+ vg = nbp_vlan_group_rcu(p);
|
||||
+ vlan = skb_vlan_tag_present(skb) ? skb_vlan_tag_get_id(skb) : br_get_pvid(vg);
|
||||
+ fdb_out = br_fdb_find_rcu(p->br, eth_hdr(skb)->h_dest, vlan);
|
||||
+ if (!fdb_out || !fdb_out->dst)
|
||||
+ goto out;
|
||||
+
|
||||
+ br_offload_prepare_key(p, &key, skb);
|
||||
+#ifdef CONFIG_BRIDGE_VLAN_FILTERING
|
||||
+ key.vlan_present = cb->input_vlan_present;
|
||||
+ key.vlan_tag = cb->input_vlan_tag;
|
||||
+#endif
|
||||
+
|
||||
+ flow = kmem_cache_alloc(offload_cache, GFP_ATOMIC);
|
||||
+ flow->port = inp;
|
||||
+ memcpy(&flow->key, &key, sizeof(key));
|
||||
+
|
||||
+#ifdef CONFIG_BRIDGE_VLAN_FILTERING
|
||||
+ flow->vlan_out_present = skb_vlan_tag_present(skb);
|
||||
+ flow->vlan_out = skb_vlan_tag_get(skb);
|
||||
+#endif
|
||||
+
|
||||
+ flow->fdb_in = fdb_in;
|
||||
+ flow->fdb_out = fdb_out;
|
||||
+ flow->used = jiffies;
|
||||
+
|
||||
+ spin_lock_bh(&offload_lock);
|
||||
+ if (!o->enabled ||
|
||||
+ atomic_read(&p->offload.rht.nelems) >= p->br->offload_cache_size ||
|
||||
+ rhashtable_insert_fast(&inp->offload.rht, &flow->node, flow_params)) {
|
||||
+ kmem_cache_free(offload_cache, flow);
|
||||
+ goto out_unlock;
|
||||
+ }
|
||||
+
|
||||
+ hlist_add_head(&flow->fdb_list_in, &fdb_in->offload_in);
|
||||
+ hlist_add_head(&flow->fdb_list_out, &fdb_out->offload_out);
|
||||
+
|
||||
+ if (br_offload_need_gc(p))
|
||||
+ queue_work(system_long_wq, &p->offload.gc_work);
|
||||
+
|
||||
+out_unlock:
|
||||
+ spin_unlock_bh(&offload_lock);
|
||||
+
|
||||
+out:
|
||||
+ rcu_read_unlock();
|
||||
+}
|
||||
+
|
||||
+bool br_offload_input(struct net_bridge_port *p, struct sk_buff *skb)
|
||||
+{
|
||||
+ struct net_bridge_port_offload *o = &p->offload;
|
||||
+ struct br_input_skb_cb *cb = (struct br_input_skb_cb *)skb->cb;
|
||||
+ struct bridge_flow_key key;
|
||||
+ struct net_bridge_port *dst;
|
||||
+ struct bridge_flow *flow;
|
||||
+ unsigned long now = jiffies;
|
||||
+ bool ret = false;
|
||||
+
|
||||
+ if (skb->len < sizeof(key))
|
||||
+ return false;
|
||||
+
|
||||
+ if (!o->enabled)
|
||||
+ return false;
|
||||
+
|
||||
+ if (is_multicast_ether_addr(eth_hdr(skb)->h_dest))
|
||||
+ return false;
|
||||
+
|
||||
+ br_offload_prepare_key(p, &key, skb);
|
||||
+
|
||||
+ rcu_read_lock();
|
||||
+ flow = rhashtable_lookup(&o->rht, &key, flow_params);
|
||||
+ if (!flow) {
|
||||
+ cb->offload = 1;
|
||||
+#ifdef CONFIG_BRIDGE_VLAN_FILTERING
|
||||
+ cb->input_vlan_present = key.vlan_present != 0;
|
||||
+ cb->input_vlan_tag = key.vlan_tag;
|
||||
+#endif
|
||||
+ cb->input_ifindex = p->dev->ifindex;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ if (flow->fdb_in->dst != p)
|
||||
+ goto out;
|
||||
+
|
||||
+ dst = flow->fdb_out->dst;
|
||||
+ if (!dst)
|
||||
+ goto out;
|
||||
+
|
||||
+ ret = true;
|
||||
+#ifdef CONFIG_BRIDGE_VLAN_FILTERING
|
||||
+ if (!flow->vlan_out_present && key.vlan_present) {
|
||||
+ __vlan_hwaccel_clear_tag(skb);
|
||||
+ } else if (flow->vlan_out_present) {
|
||||
+ if (skb_vlan_tag_present(skb) &&
|
||||
+ skb->vlan_proto != p->br->vlan_proto) {
|
||||
+ /* Protocol-mismatch, empty out vlan_tci for new tag */
|
||||
+ skb_push(skb, ETH_HLEN);
|
||||
+ skb = vlan_insert_tag_set_proto(skb, skb->vlan_proto,
|
||||
+ skb_vlan_tag_get(skb));
|
||||
+ if (unlikely(!skb))
|
||||
+ goto out;
|
||||
+
|
||||
+ skb_pull(skb, ETH_HLEN);
|
||||
+ skb_reset_mac_len(skb);
|
||||
+ }
|
||||
+
|
||||
+ __vlan_hwaccel_put_tag(skb, p->br->vlan_proto,
|
||||
+ flow->vlan_out);
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
+ skb->dev = dst->dev;
|
||||
+ skb_push(skb, ETH_HLEN);
|
||||
+
|
||||
+ if (skb_warn_if_lro(skb) || !is_skb_forwardable(skb->dev, skb)) {
|
||||
+ kfree_skb(skb);
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ if (now - flow->used >= HZ) {
|
||||
+ flow->used = now;
|
||||
+ br_offload_flow_refresh_time(flow);
|
||||
+ }
|
||||
+
|
||||
+ skb_forward_csum(skb);
|
||||
+ dev_queue_xmit(skb);
|
||||
+
|
||||
+out:
|
||||
+ rcu_read_unlock();
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+br_offload_check_gc(struct net_bridge *br)
|
||||
+{
|
||||
+ struct net_bridge_port *p;
|
||||
+
|
||||
+ spin_lock_bh(&br->lock);
|
||||
+ list_for_each_entry(p, &br->port_list, list)
|
||||
+ if (br_offload_need_gc(p))
|
||||
+ queue_work(system_long_wq, &p->offload.gc_work);
|
||||
+ spin_unlock_bh(&br->lock);
|
||||
+}
|
||||
+
|
||||
+
|
||||
+int br_offload_set_cache_size(struct net_bridge *br, unsigned long val,
|
||||
+ struct netlink_ext_ack *extack)
|
||||
+{
|
||||
+ br->offload_cache_size = val;
|
||||
+ br_offload_check_gc(br);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+int br_offload_set_cache_reserved(struct net_bridge *br, unsigned long val,
|
||||
+ struct netlink_ext_ack *extack)
|
||||
+{
|
||||
+ br->offload_cache_reserved = val;
|
||||
+ br_offload_check_gc(br);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+int __init br_offload_init(void)
|
||||
+{
|
||||
+ offload_cache = kmem_cache_create("bridge_offload_cache",
|
||||
+ sizeof(struct bridge_flow),
|
||||
+ 0, SLAB_HWCACHE_ALIGN, NULL);
|
||||
+ if (!offload_cache)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+void br_offload_fini(void)
|
||||
+{
|
||||
+ kmem_cache_destroy(offload_cache);
|
||||
+}
|
||||
--- a/net/bridge/br_private.h
|
||||
+++ b/net/bridge/br_private.h
|
||||
@@ -268,7 +268,13 @@ struct net_bridge_fdb_entry {
|
||||
unsigned long updated ____cacheline_aligned_in_smp;
|
||||
unsigned long used;
|
||||
|
||||
- struct rcu_head rcu;
|
||||
+ union {
|
||||
+ struct {
|
||||
+ struct hlist_head offload_in;
|
||||
+ struct hlist_head offload_out;
|
||||
+ };
|
||||
+ struct rcu_head rcu;
|
||||
+ };
|
||||
};
|
||||
|
||||
#define MDB_PG_FLAGS_PERMANENT BIT(0)
|
||||
@@ -343,6 +349,12 @@ struct net_bridge_mdb_entry {
|
||||
struct rcu_head rcu;
|
||||
};
|
||||
|
||||
+struct net_bridge_port_offload {
|
||||
+ struct rhashtable rht;
|
||||
+ struct work_struct gc_work;
|
||||
+ bool enabled;
|
||||
+};
|
||||
+
|
||||
struct net_bridge_port {
|
||||
struct net_bridge *br;
|
||||
struct net_device *dev;
|
||||
@@ -403,6 +415,7 @@ struct net_bridge_port {
|
||||
u16 backup_redirected_cnt;
|
||||
|
||||
struct bridge_stp_xstats stp_xstats;
|
||||
+ struct net_bridge_port_offload offload;
|
||||
};
|
||||
|
||||
#define kobj_to_brport(obj) container_of(obj, struct net_bridge_port, kobj)
|
||||
@@ -519,6 +532,9 @@ struct net_bridge {
|
||||
struct kobject *ifobj;
|
||||
u32 auto_cnt;
|
||||
|
||||
+ u32 offload_cache_size;
|
||||
+ u32 offload_cache_reserved;
|
||||
+
|
||||
#ifdef CONFIG_NET_SWITCHDEV
|
||||
/* Counter used to make sure that hardware domains get unique
|
||||
* identifiers in case a bridge spans multiple switchdev instances.
|
||||
@@ -553,6 +569,10 @@ struct br_input_skb_cb {
|
||||
#ifdef CONFIG_NETFILTER_FAMILY_BRIDGE
|
||||
u8 br_netfilter_broute:1;
|
||||
#endif
|
||||
+ u8 offload:1;
|
||||
+ u8 input_vlan_present:1;
|
||||
+ u16 input_vlan_tag;
|
||||
+ int input_ifindex;
|
||||
|
||||
#ifdef CONFIG_NET_SWITCHDEV
|
||||
/* Set if TX data plane offloading is used towards at least one
|
||||
--- /dev/null
|
||||
+++ b/net/bridge/br_private_offload.h
|
||||
@@ -0,0 +1,23 @@
|
||||
+#ifndef __BR_OFFLOAD_H
|
||||
+#define __BR_OFFLOAD_H
|
||||
+
|
||||
+bool br_offload_input(struct net_bridge_port *p, struct sk_buff *skb);
|
||||
+void br_offload_output(struct sk_buff *skb);
|
||||
+void br_offload_port_state(struct net_bridge_port *p);
|
||||
+void br_offload_fdb_update(const struct net_bridge_fdb_entry *fdb);
|
||||
+int br_offload_init(void);
|
||||
+void br_offload_fini(void);
|
||||
+int br_offload_set_cache_size(struct net_bridge *br, unsigned long val,
|
||||
+ struct netlink_ext_ack *extack);
|
||||
+int br_offload_set_cache_reserved(struct net_bridge *br, unsigned long val,
|
||||
+ struct netlink_ext_ack *extack);
|
||||
+
|
||||
+static inline void br_offload_skb_disable(struct sk_buff *skb)
|
||||
+{
|
||||
+ struct br_input_skb_cb *cb = (struct br_input_skb_cb *)skb->cb;
|
||||
+
|
||||
+ if (cb->offload)
|
||||
+ cb->offload = 0;
|
||||
+}
|
||||
+
|
||||
+#endif
|
||||
--- a/net/bridge/br_stp.c
|
||||
+++ b/net/bridge/br_stp.c
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include "br_private.h"
|
||||
#include "br_private_stp.h"
|
||||
+#include "br_private_offload.h"
|
||||
|
||||
/* since time values in bpdu are in jiffies and then scaled (1/256)
|
||||
* before sending, make sure that is at least one STP tick.
|
||||
@@ -52,6 +53,8 @@ void br_set_state(struct net_bridge_port
|
||||
(unsigned int) p->port_no, p->dev->name,
|
||||
br_port_state_names[p->state]);
|
||||
|
||||
+ br_offload_port_state(p);
|
||||
+
|
||||
if (p->br->stp_enabled == BR_KERNEL_STP) {
|
||||
switch (p->state) {
|
||||
case BR_STATE_BLOCKING:
|
||||
--- a/net/bridge/br_sysfs_br.c
|
||||
+++ b/net/bridge/br_sysfs_br.c
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <linux/sched/signal.h>
|
||||
|
||||
#include "br_private.h"
|
||||
+#include "br_private_offload.h"
|
||||
|
||||
/* IMPORTANT: new bridge options must be added with netlink support only
|
||||
* please do not add new sysfs entries
|
||||
@@ -930,6 +931,38 @@ static ssize_t vlan_stats_per_port_store
|
||||
static DEVICE_ATTR_RW(vlan_stats_per_port);
|
||||
#endif
|
||||
|
||||
+static ssize_t offload_cache_size_show(struct device *d,
|
||||
+ struct device_attribute *attr,
|
||||
+ char *buf)
|
||||
+{
|
||||
+ struct net_bridge *br = to_bridge(d);
|
||||
+ return sprintf(buf, "%u\n", br->offload_cache_size);
|
||||
+}
|
||||
+
|
||||
+static ssize_t offload_cache_size_store(struct device *d,
|
||||
+ struct device_attribute *attr,
|
||||
+ const char *buf, size_t len)
|
||||
+{
|
||||
+ return store_bridge_parm(d, buf, len, br_offload_set_cache_size);
|
||||
+}
|
||||
+static DEVICE_ATTR_RW(offload_cache_size);
|
||||
+
|
||||
+static ssize_t offload_cache_reserved_show(struct device *d,
|
||||
+ struct device_attribute *attr,
|
||||
+ char *buf)
|
||||
+{
|
||||
+ struct net_bridge *br = to_bridge(d);
|
||||
+ return sprintf(buf, "%u\n", br->offload_cache_reserved);
|
||||
+}
|
||||
+
|
||||
+static ssize_t offload_cache_reserved_store(struct device *d,
|
||||
+ struct device_attribute *attr,
|
||||
+ const char *buf, size_t len)
|
||||
+{
|
||||
+ return store_bridge_parm(d, buf, len, br_offload_set_cache_reserved);
|
||||
+}
|
||||
+static DEVICE_ATTR_RW(offload_cache_reserved);
|
||||
+
|
||||
static struct attribute *bridge_attrs[] = {
|
||||
&dev_attr_forward_delay.attr,
|
||||
&dev_attr_hello_time.attr,
|
||||
@@ -984,6 +1017,8 @@ static struct attribute *bridge_attrs[]
|
||||
&dev_attr_vlan_stats_enabled.attr,
|
||||
&dev_attr_vlan_stats_per_port.attr,
|
||||
#endif
|
||||
+ &dev_attr_offload_cache_size.attr,
|
||||
+ &dev_attr_offload_cache_reserved.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
--- a/net/bridge/br_sysfs_if.c
|
||||
+++ b/net/bridge/br_sysfs_if.c
|
||||
@@ -241,6 +241,7 @@ BRPORT_ATTR_FLAG(broadcast_flood, BR_BCA
|
||||
BRPORT_ATTR_FLAG(neigh_suppress, BR_NEIGH_SUPPRESS);
|
||||
BRPORT_ATTR_FLAG(isolated, BR_ISOLATED);
|
||||
BRPORT_ATTR_FLAG(bpdu_filter, BR_BPDU_FILTER);
|
||||
+BRPORT_ATTR_FLAG(offload, BR_OFFLOAD);
|
||||
|
||||
#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
|
||||
static ssize_t show_multicast_router(struct net_bridge_port *p, char *buf)
|
||||
@@ -295,6 +296,7 @@ static const struct brport_attribute *br
|
||||
&brport_attr_isolated,
|
||||
&brport_attr_bpdu_filter,
|
||||
&brport_attr_backup_port,
|
||||
+ &brport_attr_offload,
|
||||
NULL
|
||||
};
|
||||
|
||||
--- a/net/bridge/br_vlan_tunnel.c
|
||||
+++ b/net/bridge/br_vlan_tunnel.c
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include "br_private.h"
|
||||
#include "br_private_tunnel.h"
|
||||
+#include "br_private_offload.h"
|
||||
|
||||
static inline int br_vlan_tunid_cmp(struct rhashtable_compare_arg *arg,
|
||||
const void *ptr)
|
||||
@@ -180,6 +181,7 @@ void br_handle_ingress_vlan_tunnel(struc
|
||||
skb_dst_drop(skb);
|
||||
|
||||
__vlan_hwaccel_put_tag(skb, p->br->vlan_proto, vlan->vid);
|
||||
+ br_offload_skb_disable(skb);
|
||||
}
|
||||
|
||||
int br_handle_egress_vlan_tunnel(struct sk_buff *skb,
|
||||
@@ -201,6 +203,7 @@ int br_handle_egress_vlan_tunnel(struct
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
+ br_offload_skb_disable(skb);
|
||||
tunnel_dst = rcu_dereference(vlan->tinfo.tunnel_dst);
|
||||
if (tunnel_dst && dst_hold_safe(&tunnel_dst->dst))
|
||||
skb_dst_set(skb, &tunnel_dst->dst);
|
||||
Reference in New Issue
Block a user