DSA

DSA

来源  https://www.right.com.cn/forum/thread-5807504-1-1.html

教程 https://openwrt.org/docs/guide-user/network/dsa/dsa-mini-tutorial#multiple_networks_using_vlan_tagging

参考 https://openwrt.org/docs/guide-user/network/vlan/switch_configuration

参考  https://www.cisco.com/c/en/us/td/docs/switches/datacenter/sw/5_x/nx-os/layer2/configuration/guide/Cisco_Nexus_7000_Series_NX-OS_Layer_2_Switching_Configuration_Guide_Release_5-x_chapter4.html

 

新版openwrt很多固件上找不到交换机插件,不支持swconfig配置vlan,从网上找到一篇dsa配置dot1q网络的方法,可以参考一下,原链接有图,更直观

原链接:https://forum.openwrt.org/t/mini-tutorial-for-dsa-network-config/96998
 
介绍
DSA 代表分布式交换机架构,是用于网络交换机的 Linux 内核子系统。它是 OpenWrt  swconfig 框架的上游替代品,许多新路由器使用 DSA 驱动程序而不是 swconfig 驱动程序。
 DSA 中,每个交换机端口都是一个单独的 Linux 接口。这意味着ip/ifconfig命令将显示接口等lan1lan2wan等。
DSA 交换机端口可以用作独立接口(WAN 的通用解决方案),也可以使用 Linux 桥接接口进行桥接。在后一种情况下,交换机仍然能够在硬件级别路由流量,因此不会影响性能。
每个端口最多只能是一个网桥的一部分。
简单的端口桥接
在最简单的情况下,交换机端口使用 Linux 桥接接口进行桥接,OpenWrt 使用 IP 协议配置该接口。
在这种情况下,连接到桥接端口的所有设备都可以相互通信,也可以与路由器本身通信。
SyntaxMember Port Is
lanx untagged ~PVID
lanx:u untagged
lanx:t tagged
lanx:* PVID untagged
lanx:u* PVID untagged
lanx:t* PVID tagged
例子:
 
config device
        option name 'br-lan'
        option type 'bridge'
        list ports 'lan1'
        list ports 'lan2'
        list ports 'lan3'
        list ports 'lan4'
 
 
config interface 'lan'
        option device 'br-lan'
        option proto 'static'
        option ipaddr '192.168.1.1'
        option netmask'255.255.255.0'
 
多个网络(使用网桥)
通过使用多个桥接接口,可以将交换机设置为将选定的端口分组到单独的网络中。使用分离的防火墙区域,连接到不同端口组的设备将无法相互通信。
例子:
 
config device
        option name 'br-home'
        option type 'bridge'
        list ports 'lan1'
        list ports 'lan2'
 
config device
        option name 'office'
        option type 'bridge'
        list ports 'lan3'
        list ports 'lan4'
 
config interface 'home'
        option device 'br-home'
        option proto 'static'
        option ipaddr '192.168.1.1'
        option netmask'255.255.255.0'
 
config interface 'office'
        option device 'office'
        option proto 'static'
        option ipaddr '192.168.13.1'
        option netmask'255.255.255.0'
 
多个网络(使用 VLAN
还可以使用具有多个 VLAN 的单个网桥来分隔(分组)端口。这需要将接口分配给正确的软件 VLAN
例子:
 
config device
        option name 'br-lan'
        option type 'bridge'
        list ports 'lan1'
        list ports 'lan2'
        list ports 'lan3'
        list ports 'lan4'
 
config bridge-vlan
        option device 'br-lan'
        option vlan '1'
        list ports 'lan1'
        list ports 'lan2'
 
config bridge-vlan
        option device 'br-lan'
        option vlan '2'
        list ports 'lan3'
        list ports 'lan4'
 
 
config interface 'home'
        option device 'br-lan.1'
        option proto 'static'
        option ipaddr '192.168.1.1'
        option netmask'255.255.255.0'
 
config interface 'office'
        option device 'br-lan.2'
        option proto 'static'
        option ipaddr '192.168.13.1'
        option netmask'255.255.255.0'
 
VLAN 标记的流量
通过正确的桥接 VLAN 配置,选定端口也可以使用 VLAN 标记的流量。它还需要将 OpenWrt 接口分配给正确的软件 VLAN
例子:
端口lan4使用 VLAN 1 的标记数据包并具有 PVID 2
 
config device
        option name 'br-lan'
        option type 'bridge'
        list ports 'lan1'
        list ports 'lan2'
        list ports 'lan3'
        list ports 'lan4'
 
config bridge-vlan
        option device 'br-lan'
        option vlan '1'
        list ports 'lan1'
        list ports 'lan2'
        list ports 'lan3'
        list ports 'lan4:t'
 
config bridge-vlan
        option device 'br-lan'
        option vlan '2'
        list ports 'lan4:u*'
 
config interface 'lan'
        option device 'br-lan.1'
        option proto 'static'
        option ipaddr '192.168.1.1'
        option netmask'255.255.255.0'

 

=================

mini-tutorial-for-dsa-network-config

see https://forum.openwrt.org/t/mini-tutorial-for-dsa-network-config/96998

Update from 2021-05-31:

  • Option ifname was renamed to device
  • This tutorial is valid for 21.02-rc2 (or newer) and recent snapshots

Introduction

DSA stands for Distributed Switch Architecture and is Linux kernel subsystem for network switches. It's an upstream replacement for OpenWrt's swconfig framework and many new routers use DSA drivers instead of swconfig drivers.

In DSA each switch port is a separated Linux interface. It means ip / ifconfig command will show interfaces like lan1lan2wan, etc.

DSA switch ports can be used as standalone interfaces (common solution for WAN) or can be bridged using Linux bridge interface. In the later case switch will still be able to route traffic on the hardware level so it won't affect performance.

Each port can be part of maximum of one bridge only.

Simple ports bridging

In the simplest scenario switch ports are simply bridged using Linux bridge interface and OpenWrt configures that interface with an IP protocol.

In such case all devices connected to bridged ports can communicate each other and router itself.

Example:

 

config device
	option name 'br-lan'
	option type 'bridge'
	list ports 'lan1'
	list ports 'lan2'
	list ports 'lan3'
	list ports 'lan4'

 

 

config interface 'lan'
	option device 'br-lan'
	option proto 'static'
	option ipaddr '192.168.1.1'
	option netmask '255.255.255.0'

 

Multiple networks (using bridges)

A switch can be setup to group selected ports into separated networks by using multiple bridge interfaces. With separated firewall zones devices connected to different port groups won't be able to communicate each other.

Example:

 

config device
	option name 'br-home'
	option type 'bridge'
	list ports 'lan1'
	list ports 'lan2'

config device
	option name 'office'
	option type 'bridge'
	list ports 'lan3'
	list ports 'lan4'

 

 

 
config interface 'home'
	option device 'br-home'
	option proto 'static'
	option ipaddr '192.168.1.1'
	option netmask '255.255.255.0'

config interface 'office'
	option device 'office'
	option proto 'static'
	option ipaddr '192.168.13.1'
	option netmask '255.255.255.0'

 

Multiple networks (using VLANs)

Ports can also be separated (grouped) using single bridge with multiple VLANs. That requires assigning interfaces to correct software VLANs.

Example:

config device
	option name 'br-lan'
	option type 'bridge'
	list ports 'lan1'
	list ports 'lan2'
	list ports 'lan3'
	list ports 'lan4'

config bridge-vlan
	option device 'br-lan'
	option vlan '1'
	list ports 'lan1'
	list ports 'lan2'

config bridge-vlan
	option device 'br-lan'
	option vlan '2'
	list ports 'lan3'
	list ports 'lan4'

 

config interface 'home'
	option device 'br-lan.1'
	option proto 'static'
	option ipaddr '192.168.1.1'
	option netmask '255.255.255.0'

config interface 'office'
	option device 'br-lan.2'
	option proto 'static'
	option ipaddr '192.168.13.1'
	option netmask '255.255.255.0'

 

VLAN tagged traffic

With proper bridge VLAN configuration it's also possible for selected port to use VLAN tagged traffic. It also requires assigning OpenWrt interface to the correct software VLAN.

Example:

Port lan4 uses tagged packets for VLAN 1 and has PVID 2.

config device
	option name 'br-lan'
	option type 'bridge'
	list ports 'lan1'
	list ports 'lan2'
	list ports 'lan3'
	list ports 'lan4'

config bridge-vlan
	option device 'br-lan'
	option vlan '1'
	list ports 'lan1'
	list ports 'lan2'
	list ports 'lan3'
	list ports 'lan4:t'

config bridge-vlan
	option device 'br-lan'
	option vlan '2'
	list ports 'lan4:u*'

 

config interface 'lan'
	option device 'br-lan.1'
	option proto 'static'
	option ipaddr '192.168.1.1'
	option netmask '255.255.255.0'

 

=================

DSA with multiple WAN VLAN priorities

see https://forum.openwrt.org/t/dsa-with-multiple-wan-vlan-priorities/126544

 

I've recently upgraded my Linksys WRT1900ACS from OpenWrt 19.07 to 21.02.3. I've had to rewrite my /etc/config/network to work with the new DSA configuration and I've got most of what I need working, except for IPTV.

My ISP requires that internet traffic be sent over 802.1q VLAN 10 priority 0, and that IPTV is over VLAN 20, priority 4. The IPTV set-top box is plugged into lan1.

In OpenWrt 19.07, I've accomplished this by:

  • Defining eth1.21, connected to swconfig port 3 (DSA = lan1)
  • Defining eth0.20, connected to swconfig port 4 (DSA = wan)
  • Defining a bridge for eth0.20 and 1.21
  • Using ip link set link eth0.20 dev eth0 type vlan egress-qos-map 0:4 1:4 2:4 3:4 4:4 5:4 6:4 7:4 as a hotplug.d/iface script that runs on ifup.

The idea is to take the traffic from the set-top box, add the 802.1q header (VLAN 20, priority 4), and send the packet onwards to the ISP. This set up works well. Internet works correctly, and IPTV works correctly as well.

In OpenWrt 21.02, after porting the equivalent configuration (internet configuration omitted for brevity):

 
config device
        option name 'br-lan'
        option type 'bridge'
        list ports 'lan1'
        list ports 'lan2'
        list ports 'lan3'
        list ports 'lan4'

config bridge-vlan
        option device 'br-lan'
        option vlan '21'
        list ports 'lan1'

config device
        option name 'br-iptv'
        option type 'bridge'
        list ports 'wan.20'
        list ports 'br-lan.21'

and using the same ip link set link wan.20 dev wan type vlan egress-qos-map 0:4 1:4 2:4 3:4 4:4 5:4 6:4 7:4 command, I notice several things:

  1. When I try to perform a DHCP configuration of br-iptv, the configuration as described does not receive any DHCP responses. According to tcpdump, capturing wan and filtering by vlan 20 shows the correct 802.1q field: priority 4 and VLAN 20. However, the priority field doesn't seem to be properly set when the ethernet frame is sent over the wire (which can explain why I don't get any DHCP response). I get a DHCP response immediately when I configure:
 
config device
	option name 'wan.20'
	option type '8021q'
	option vid '20'
	option ifname 'wan'
	list egress_qos_mapping '0:4'

in place of using ip link. However, this now causes my normal internet access to break (presumably because it is now set to VLAN 10, priority 4 for the internet-facing VLAN 10). No other internet traffic is then possible, all packets are dropped on my ISP side.

Regardless which way I set the egress_qos_mapping, the VLAN configuration seems correct:

 
# cat /proc/net/vlan/wan.10 /proc/net/vlan/wan.20
wan.10  VID: 10  REORDER_HDR: 1  dev->priv_flags: 1121
         total frames received         7368
          total bytes received      7803993
      Broadcast/Multicast Rcvd            0

      total frames transmitted         3856
       total bytes transmitted       628469
Device: wan
INGRESS priority mappings: 0:0  1:0  2:0  3:0  4:0  5:0  6:0 7:0
 EGRESS priority mappings:
wan.20  VID: 20  REORDER_HDR: 1  dev->priv_flags: 1221
         total frames received            3
          total bytes received          706
      Broadcast/Multicast Rcvd            1

      total frames transmitted           10
       total bytes transmitted         1520
Device: wan
INGRESS priority mappings: 0:0  1:0  2:0  3:0  4:0  5:0  6:0 7:0
 EGRESS priority mappings: 0:4

Does setting the egress_qos_mapping apply to all VLANs in the hardware switch? This doesn't seem to be the behaviour from 19.07.

  1. tcpdump-ing both br-iptv and wan.20 at the same time when powering on the IPTV set-top box shows the correct DHCP configuration packets being sent by the set-top box, and it shows up in the br-iptv dump. However wan.20 never sees the packet. I can confirm this by temporary breaking my internet access (in point 1) and rebooting the set-top box, but it still does not obtain any IP address from my ISP.

Am I misconfiguring something, or has DSA fundamentally changed what is possible in terms of the network setup? Any guidance would be much appreciated.

 

=================

netifd调试总结(OpenWrt 22.03)

https://blog.csdn.net/u010687717/article/details/124570805

 

1.调试

1.1 gdb调试

如下所示,修改配置(问题:有些东西打印不出来,比如ifname,提示 ifname = <error reading variable>)

 

1.2 D打印

在/etc/init.d/network中增加如下内容就能使用“logread -e netifd”看到D打印的内容,“-d 15"表示打开以下所有模块的打印,如果”-d 1",那就只打印DEBUG_SYSTEM:

enum {
	DEBUG_SYSTEM	= 0,
	DEBUG_DEVICE	= 1,
	DEBUG_INTERFACE	= 2,
	DEBUG_WIRELESS	= 3,
};

注意:D打印的内容是"daemon.err netifd[10824]"开头的,而netifd使用的syslog级别为L_CRIT,L_WARNING,L_NOTICE,L_INFO,L_DEBUG,感觉是特意避开err级别,避免跟D混淆。

1.3 syslog打印

如果将上面的启动参数修改为“procd_set_param command /sbin/netifd -l 5 -d 15”,则代码及对应的打印内容如下所示:

DPRINTF("connected as %08x\n", ubus_ctx->local_id);
netifd_log_message(L_DEBUG, "connected as %08x\n", ubus_ctx->local_id);
netifd_log_message(L_INFO, "connected as %08x\n", ubus_ctx->local_id);
netifd_log_message(L_NOTICE, "connected as %08x\n", ubus_ctx->local_id);
netifd_log_message(L_WARNING, "connected as %08x\n", ubus_ctx->local_id);
netifd_log_message(L_CRIT, "connected as %08x\n", ubus_ctx->local_id);
daemon.err netifd[17096]: netifd_ubus_init(1364): connected as 0d6fc15a
daemon.debug netifd: connected as 0d6fc15a
daemon.info netifd: connected as 0d6fc15a
daemon.notice netifd: connected as 0d6fc15a
daemon.warn netifd: connected as 0d6fc15a
daemon.crit netifd: connected as 0d6fc15a

1.4 命令行获取IP

ifstatus WAN1 | jsonfilter -e '@["ipv4-address"][0].address'

2 初始化过程分析(BPI-R64)

2.1 创建CPU口和mdio驱动初始化

kernel_init->kernel_init_freeable->do_basic_setup->do_initcalls->do_one_initcall
  ->mtk_driver_init(mtk_eth_soc.c中通过module_platform_driver注册)
    ->platform_driver_register->__platform_driver_register->driver_register->bus_add_driver->driver_attach->bus_for_each_dev
      ->__driver_attach->device_driver_attach->driver_probe_device->really_probe
        ->platform_drv_probe(paltform.c中通过__platform_driver_register注册)->mtk_probe

2.1.1 创建CPU口

  1. 创建CPU口
mtk_probe->mtk_add_mac->alloc_etherdev->alloc_etherdev_mq->alloc_etherdev_mqs->alloc_netdev_mqs(此时接口名称为'eth%d')
  1. 将netdev与DTS关联起来
mtk_probe->mtk_add_mac(其中eth->netdev[id]->dev.of_node = np;关联起来,在设备初始化时match)

2.2.2 mdio驱动初始化

mtk_probe->mtk_mdio_init(读DTS)->of_mdiobus_register->of_mdiobus_register_device->mdio_device_register->device_add
            ->bus_probe_device->device_initial_probe->__device_attach->bus_for_each_drv->__device_attach_driver
              ->driver_probe_device->really_probe->mdio_probe(mdio.h中通过mdio_module_init注册)
                ->mt7530_probe(drivers\net\dsa\mt7530.c中通过mdio_module_driver(mt7530_mdio_driver)注册)
                  ->dsa_register_switch->dsa_switch_probe->dsa_switch_parse_of->dsa_switch_parse_ports_of->dsa_port_parse_of
                    ->of_find_net_device_by_node(DTS中port@6调用,因为此时接口没有注册,所以class_find_device返回NULL,进而dsa_port_parse_of返回-EPROBE_DEFER,驱动初始化完成)

2.2.3 注册CPU口

注册时,会自动给CPU口命名为命名为eth0和eth1

mtk_probe->register_netdev->register_netdevice->dev_get_valid_name->dev_alloc_name_ns->__dev_alloc_name

2.2 创建用户口(mdio设备初始化)

获取接口名称
deferred_probe_work_func(具体何时调用不清楚)->bus_probe_device->device_initial_probe->__device_attach->bus_for_each_drv
  ->__device_attach_driver->driver_probe_device->really_probe->mdio_probe(mdio.h中通过mdio_module_init注册)
   ->mt7530_probe(drivers\net\dsa\mt7530.c中通过mdio_module_driver(mt7530_mdio_driver)注册)
     ->dsa_register_switch->dsa_switch_probe
     	其中->dsa_switch_parse_of->dsa_switch_parse_ports_of->dsa_port_parse_of->dsa_port_parse_user(从DTS中读取接口名称)
     	另外->dsa_tree_setup->dsa_tree_setup_switches->dsa_port_setup->dsa_slave_create(创建lan1~lan4及wan口。)

2.3 生成/etc/config/network

config_generate根据target\linux\mediatek\mt7622\base-files\etc\board.d\02_network生成/etc/config/network,具体实现的参考链接如下:OpenWrt file/bin/config_generate network初始化分析

3 支持的device类型

LuCI类型UCI类型对应结构体使用场景
Network device N/A simple_device_type 对应真实物理端口,好像不创建也不影响功能。。。
Bridge device bridge bridge_device_type 基于桥设备创建桥接口,比如br-lan
VLAN(802.1q) 8021q vlan8021q_device_type 基于802.1q设备创建接口,比如创建802.1q的路由连接
VLAN(802.1ad) 8021ad vlan8021ad_device_type 基于802.1ad设备创建接口,比如创建802.1ad的路由连接
MAC VLAN macvlan macvlan_device_type  
Virtual Ethernet veth veth_device_type  

所有类型都通过device_type_add来添加。

3.1 802.1q

  • 创建带VLAN的device

  • 创建interface,这样在WAN侧抓到的报文就是带VLAN 100的

  • 对应的UCI配置如下:

config device
        option type '8021q'
        option ifname 'wan'
        option vid '100'
        option name 'wan.100'

config interface 'WAN'
        option proto 'dhcp'
        option device 'wan.100'

3.2 MAC VLAN

  • 创建带MAC VLAN的device,wanmac1也用同样方法创建

  • 创建interface,WAN1使用相同方法创建

  • 对应的UCI配置如下:
config device
        option type 'macvlan'
        option ifname 'wan'
        option mode 'bridge'
        option name 'wanmac0'

config device
        option type 'macvlan'
        option ifname 'wan'
        option mode 'bridge'
        option name 'wanmac1'

config interface 'WAN0'
        option proto 'dhcp'
        option device 'wanmac0'

config interface 'WAN1'
        option proto 'dhcp'
        option device 'wanmac1'
  • 两个MAC VLAN桥模式的WAN连接通信
    执行如下命令,参考链接:https://unix.stackexchange.com/questions/398671/communication-problem-between-macvlan-interfaces-when-sockets-are-bound-to-devic
device0=`ifstatus WAN0 | jsonfilter -e '@["device"]'`
device1=`ifstatus WAN1 | jsonfilter -e '@["device"]'`
ip0=`ifstatus WAN0 | jsonfilter -e '@["ipv4-address"][0].address'`
ip1=`ifstatus WAN1 | jsonfilter -e '@["ipv4-address"][0].address'`

ip route del default
ip route del `ip route|grep "$device0"` 
ip route del `ip route|grep "$device1"` 
ip rule del pref 0
ip rule add pref 200 to "$ip1" lookup 100
ip rule add pref 200 to "$ip0" lookup 101
ip route add default dev "$device0" table 100
ip route add default dev "$device1" table 101
ip rule add pref 1000 lookup local
ip rule add pref 100 to "$ip0" iif "$device0" lookup local
ip rule add pref 100 to "$ip1" iif "$device1" lookup local

ping -I $device0 $ip1 #此时能ping通


4 监听内核接口状态的变化

1、system_init中调用create_event_socket创建监听netlink的socket

2、当接口link up或者link down时,在内核中调用netif_carrier_on,最终会走到netdev_state_change,
再通过rtmsg_ifinfo发出netlink消息。

3、在system_init中注册的cb_rtnl_event监听到消息之后,做相应的处理。

 

=================

Debian for MT7621 折腾记 (2) - 实现 MT7530 DSA

https://blog.hackpascal.net/2019/10/debian-for-mt7621-%e6%8a%98%e8%85%be%e8%ae%b0-2-%e5%ae%9e%e7%8e%b0-mt7530-dsa/


OpenWrt 自带的 swconfig 功能对于 Debian 来说,就不是那么好用了。除此之外,Linux 对交换机的支持就只剩 DSA 了。幸好 MT7530 有 DSA 驱动。
但是 MT7530 的 DSA 驱动是给 MT7623 用的,里面硬编码了很多 MT7623 的设置,还用到了很多 MT7621 中不存在的东西,例如 Power domain。
这些都需要全部去掉,并为 MT7621 添加所需的代码。
此外,用于 MT7621 的以太网驱动 mtk_soc_eth 也一团糟,里面杂揉了各个芯片的代码,不纯粹,不适合拿给 DSA 用。因此也需要进行修改。

1. 修改 mtk_soc_eth

我选择对 ARM 版的 mtk_soc_eth 下手。

1.1 加入 MT7621 支持

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
--- a/drivers/net/ethernet/mediatek/Kconfig
+++ b/drivers/net/ethernet/mediatek/Kconfig
@@ -1,6 +1,6 @@
 config NET_VENDOR_MEDIATEK
        bool "MediaTek ethernet driver"
-       depends on ARCH_MEDIATEK
+       depends on ARCH_MEDIATEK || SOC_MT7621
        ---help---
          If you have a Mediatek SoC with ethernet, say Y.
  
 
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -76,7 +76,6 @@ static int mtk_mdio_busy_wait(struct mtk
                        return 0;
                if (time_after(jiffies, t_start + PHY_IAC_TIMEOUT))
                        break;
-               usleep_range(10, 20);
        }
  
        dev_err(eth->dev, "mdio: MDIO timeout\n");
@@ -1748,6 +1747,34 @@ static void mtk_tx_timeout(struct net_de
        schedule_work(&eth->pending_work);
 }
  
+static irqreturn_t mtk_handle_irq_tx_rx(int irq, void *_eth)
+{
+       struct mtk_eth *eth = _eth;
+       u32 tx_status, rx_status;
+
+       tx_status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
+
+       if (tx_status & MTK_TX_DONE_INT) {
+               if (likely(napi_schedule_prep(&eth->tx_napi))) {
+                       mtk_tx_irq_disable(eth, MTK_TX_DONE_INT);
+                       __napi_schedule(&eth->tx_napi);
+               }
+               mtk_w32(eth, tx_status, MTK_QMTK_INT_STATUS);
+       }
+
+       rx_status = mtk_r32(eth, MTK_PDMA_INT_STATUS);
+
+       if (rx_status & MTK_RX_DONE_INT) {
+               if (likely(napi_schedule_prep(&eth->rx_napi))) {
+                       mtk_rx_irq_disable(eth, MTK_RX_DONE_INT);
+                       __napi_schedule(&eth->rx_napi);
+               }
+               mtk_w32(eth, rx_status, MTK_PDMA_INT_STATUS);
+       }
+
+       return IRQ_HANDLED;
+}
+
 static irqreturn_t mtk_handle_irq_rx(int irq, void *_eth)
 {
        struct mtk_eth *eth = _eth;
@@ -1950,14 +1977,16 @@ static int mtk_hw_init(struct mtk_eth *e
        }
        regmap_write(eth->ethsys, ETHSYS_SYSCFG0, val);
  
-       /* Set GE2 driving and slew rate */
-       regmap_write(eth->pctl, GPIO_DRV_SEL10, 0xa00);
+       if (eth->pctl) {
+               /* Set GE2 driving and slew rate */
+               regmap_write(eth->pctl, GPIO_DRV_SEL10, 0xa00);
  
-       /* set GE2 TDSEL */
-       regmap_write(eth->pctl, GPIO_OD33_CTRL8, 0x5);
+               /* set GE2 TDSEL */
+               regmap_write(eth->pctl, GPIO_OD33_CTRL8, 0x5);
  
-       /* set GE2 TUNE */
-       regmap_write(eth->pctl, GPIO_BIAS_CTRL, 0x0);
+               /* set GE2 TUNE */
+               regmap_write(eth->pctl, GPIO_BIAS_CTRL, 0x0);
+       }
  
        /* Set linkdown as the default for each GMAC. Its own MCR would be set
         * up with the more appropriate value when mtk_phy_link_adjust call is
@@ -2536,14 +2565,16 @@ static int mtk_probe(struct platform_dev
                }
        }
  
-       eth->pctl = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
-                                                   "mediatek,pctl");
-       if (IS_ERR(eth->pctl)) {
-               dev_err(&pdev->dev, "no pctl regmap found\n");
-               return PTR_ERR(eth->pctl);
+       if (eth->soc->require_pctl) {
+               eth->pctl = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+                                                           "mediatek,pctl");
+               if (IS_ERR(eth->pctl)) {
+                       dev_info(&pdev->dev, "no pctl regmap found\n");
+                       return PTR_ERR(eth->pctl);
+               }
        }
  
-       for (i = 0; i < 3; i++) {
+       for (i = 0; i < eth->soc->irq_num; i++) {
                eth->irq[i] = platform_get_irq(pdev, i);
                if (eth->irq[i] < 0) {
                        dev_err(&pdev->dev, "no IRQ%d resource found\n", i);
@@ -2591,15 +2622,22 @@ static int mtk_probe(struct platform_dev
                        goto err_deinit_hw;
        }
  
-       err = devm_request_irq(eth->dev, eth->irq[1], mtk_handle_irq_tx, 0,
-                              dev_name(eth->dev), eth);
-       if (err)
-               goto err_free_dev;
+       if (eth->soc->irq_num > 1) {
+               err = devm_request_irq(eth->dev, eth->irq[1], mtk_handle_irq_tx, 0,
+                                      dev_name(eth->dev), eth);
+               if (err)
+                       goto err_free_dev;
  
-       err = devm_request_irq(eth->dev, eth->irq[2], mtk_handle_irq_rx, 0,
-                              dev_name(eth->dev), eth);
-       if (err)
-               goto err_free_dev;
+               err = devm_request_irq(eth->dev, eth->irq[2], mtk_handle_irq_rx, 0,
+                                      dev_name(eth->dev), eth);
+               if (err)
+                       goto err_free_dev;
+       } else {
+               err = devm_request_irq(eth->dev, eth->irq[0], mtk_handle_irq_tx_rx, 0,
+                                      dev_name(eth->dev), eth);
+               if (err)
+                       goto err_free_dev;
+       }
  
        err = mtk_mdio_init(eth);
        if (err)
@@ -2666,23 +2704,37 @@ static int mtk_remove(struct platform_de
  
 static const struct mtk_soc_data mt2701_data = {
        .caps = MTK_GMAC1_TRGMII,
-       .required_clks = MT7623_CLKS_BITMAP
+       .required_clks = MT7623_CLKS_BITMAP,
+       .require_pctl = true,
+       .irq_num = 3,
 };
  
 static const struct mtk_soc_data mt7622_data = {
        .caps = MTK_DUAL_GMAC_SHARED_SGMII | MTK_GMAC1_ESW,
-       .required_clks = MT7622_CLKS_BITMAP
+       .required_clks = MT7622_CLKS_BITMAP,
+       .require_pctl = false,
+       .irq_num = 3,
 };
  
 static const struct mtk_soc_data mt7623_data = {
        .caps = MTK_GMAC1_TRGMII,
-       .required_clks = MT7623_CLKS_BITMAP
+       .required_clks = MT7623_CLKS_BITMAP,
+       .require_pctl = true,
+       .irq_num = 3,
+};
+
+static const struct mtk_soc_data mt7621_data = {
+       .caps = MTK_GMAC1_TRGMII,
+       .required_clks = MT7621_CLKS_BITMAP,
+       .require_pctl = false,
+       .irq_num = 1,
 };
  
 const struct of_device_id of_mtk_match[] = {
        { .compatible = "mediatek,mt2701-eth", .data = &mt2701_data},
        { .compatible = "mediatek,mt7622-eth", .data = &mt7622_data},
        { .compatible = "mediatek,mt7623-eth", .data = &mt7623_data},
+       { .compatible = "mediatek,mt7621-eth", .data = &mt7621_data},
        {},
 };
 MODULE_DEVICE_TABLE(of, of_mtk_match);
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -486,6 +486,8 @@ enum mtk_clks_map {
                                 BIT(MTK_CLK_SGMII_CDR_FB) | \
                                 BIT(MTK_CLK_SGMII_CK) | \
                                 BIT(MTK_CLK_ETH2PLL))
+#define MT7621_CLKS_BITMAP     0
+
 enum mtk_dev_state {
        MTK_HW_INIT,
        MTK_RESETTING
@@ -575,6 +577,8 @@ struct mtk_rx_ring {
 struct mtk_soc_data {
        u32             caps;
        u32             required_clks;
+       bool            require_pctl;
+       u32             irq_num;
 };
  
 /* currently no SoC has more than 2 macs */
 };
  
 /* currently no SoC has more than 2 macs */

1.2 从 mediatek 这个 target 中提取 mtk_soc_eth 相关的改动

0027-net-next-mediatek-fix-DQL-support.patch
0035-net-mediatek-disable-RX-VLan-offloading.patch
0042-net-next-mediatek-honour-special-tag-bit-inside-RX-D.patch
0043-net-next-mediatek-enable-special-tag-indication-for-.patch
0051-net-mediatek-increase-tx_timeout.patch
0063-atomic-sleep.patch

2. 修改 DSA 驱动

2.1 从 mediatek 这个 target 中提取 DSA 相关的改动

0032-net-dsa-mediatek-add-support-for-GMAC2-wired-to-ext-.patch
0033-dsa-multi-cpu.patch
0044-net-next-dsa-mediatek-tell-GDMA-when-we-are-turning-.patch
0045-net-dsa-mediatek-turn-into-platform-driver.patch

2.2 针对 MT7621 进行修改

2.2.1 去除 MT7623 TRGMII 相关的设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -76,58 +76,6 @@ static const struct mt7530_mib_desc mt75
 };
  
 static int
-mt7623_trgmii_write(struct mt7530_priv *priv,  u32 reg, u32 val)
-{
-       int ret;
-
-       ret =  regmap_write(priv->ethernet, TRGMII_BASE(reg), val);
-       if (ret < 0)
-               dev_err(priv->dev,
-                       "failed to priv write register\n");
-       return ret;
-}
-
-static u32
-mt7623_trgmii_read(struct mt7530_priv *priv, u32 reg)
-{
-       int ret;
-       u32 val;
-
-       ret = regmap_read(priv->ethernet, TRGMII_BASE(reg), &val);
-       if (ret < 0) {
-               dev_err(priv->dev,
-                       "failed to priv read register\n");
-               return ret;
-       }
-
-       return val;
-}
-
-static void
-mt7623_trgmii_rmw(struct mt7530_priv *priv, u32 reg,
-                 u32 mask, u32 set)
-{
-       u32 val;
-
-       val = mt7623_trgmii_read(priv, reg);
-       val &= ~mask;
-       val |= set;
-       mt7623_trgmii_write(priv, reg, val);
-}
-
-static void
-mt7623_trgmii_set(struct mt7530_priv *priv, u32 reg, u32 val)
-{
-       mt7623_trgmii_rmw(priv, reg, 0, val);
-}
-
-static void
-mt7623_trgmii_clear(struct mt7530_priv *priv, u32 reg, u32 val)
-{
-       mt7623_trgmii_rmw(priv, reg, val, 0);
-}
-
-static int
 core_read_mmd_indirect(struct mt7530_priv *priv, int prtad, int devad)
 {
        struct mii_bus *bus = priv->bus;
@@ -515,24 +463,6 @@ mt7530_pad_clk_setup(struct dsa_switch *
                for (i = 0 ; i < NUM_TRGMII_CTRL; i++)
                        mt7530_rmw(priv, MT7530_TRGMII_RD(i),
                                   RD_TAP_MASK, RD_TAP(16));
-       else
-               mt7623_trgmii_set(priv, GSW_INTF_MODE, INTF_MODE_TRGMII);
-
-       return 0;
-}
-
-static int
-mt7623_pad_clk_setup(struct dsa_switch *ds)
-{
-       struct mt7530_priv *priv = ds->priv;
-       int i;
-
-       for (i = 0 ; i < NUM_TRGMII_CTRL; i++)
-               mt7623_trgmii_write(priv, GSW_TRGMII_TD_ODT(i),
-                                   TD_DM_DRVP(8) | TD_DM_DRVN(8));
-
-       mt7623_trgmii_set(priv, GSW_TRGMII_RCK_CTRL, RX_RST | RXC_DQSISEL);
-       mt7623_trgmii_clear(priv, GSW_TRGMII_RCK_CTRL, RX_RST);
  
        return 0;
 }
@@ -619,12 +549,6 @@ static void mt7530_adjust_link(struct ds
  
                /* Setup TX circuit incluing relevant PAD and driving */
                mt7530_pad_clk_setup(ds, phydev->interface);
-
-               /* Setup RX circuit, relevant PAD and driving on the host
-                * which must be placed after the setup on the device side is
-                * all finished.
-                */
-               mt7623_pad_clk_setup(ds);
        } else {
                u16 lcl_adv = 0, rmt_adv = 0;
                u8 flowctrl;

2.2.2 添加 MT7621 TRGMII 相关的设置

目前 Upstream 并没有完善的 TRGMII 支持,因此暂时先用 RGMII。毕竟 MT7621 的 TRGMII 只有 1.2Gbps,只比 RGMII 的 1Gbps 快了一点,影响不大。
这个先留着,等以后再补充。

3. 修改 DTS 文件

3.1 修改 mt7621.dtsi

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
--- a/target/linux/ramips/dts/mt7621.dtsi
+++ b/target/linux/ramips/dts/mt7621.dtsi
@@ -406,22 +406,38 @@
                        0x1e003800 0x800>;
        };
  
+       ethsys: ethsys@1e000000 {
+               compatible = "mediatek,mt7621-ethsys", "syscon";
+               reg = <0x1e000000 0x8000>;
+       };
+
        ethernet: ethernet@1e100000 {
-               compatible = "mediatek,mt7621-eth";
+               compatible = "mediatek,mt7621-eth", "syscon";
                reg = <0x1e100000 0x10000>;
  
                #address-cells = <1>;
                #size-cells = <1>;
  
+               mediatek,ethsys = <&ethsys>;
+
                resets = <&rstctrl 6 &rstctrl 23>;
                reset-names = "fe", "eth";
  
                interrupt-parent = <&gic>;
                interrupts = <GIC_SHARED 3 IRQ_TYPE_LEVEL_HIGH>;
  
-               mediatek,switch = <&gsw>;
+               gmac0: mac@0 {
+                       compatible = "mediatek,eth-mac";
+                       reg = <0>;
+                       phy-mode = "rgmii";
+                       fixed-link {
+                               speed = <1000>;
+                               full-duplex;
+                               pause;
+                       };
+               };
  
-               mdio-bus {
+               mdio: mdio-bus {
                        #address-cells = <1>;
                        #size-cells = <0>;
  
@@ -430,16 +446,6 @@
                                phy-mode = "rgmii";
                        };
                };
-
-               hnat: hnat@0 {
-                       compatible = "mediatek,mt7623-hnat";
-                       reg = <0 0x10000>;
-                       mtketh-ppd = "eth0";
-                       mtketh-lan = "eth0";
-                       mtketh-wan = "eth0";
-                       resets = <&rstctrl 0>;
-                       reset-names = "mtketh";
-               };
        };
  
        gsw: gsw@1e110000 {

3.2 修改对应板子的 dts

这里用的是 CreativeBox 这个板子。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
--- a/target/linux/ramips/dts/CreativeBox-v1.dts
+++ b/target/linux/ramips/dts/CreativeBox-v1.dts
@@ -86,6 +86,10 @@
                        gpios = <&gpio0 27 GPIO_ACTIVE_HIGH>;
                };
        };
+
+       mt7530: switch@0 {
+               compatible = "mediatek,mt7530";
+       };
 };
  
 &sdhci {
@@ -115,6 +119,67 @@
        mtd-mac-address = <&factory 0xe000>;
 };
  
+&mt7530 {
+       compatible = "mediatek,mt7530";
+
+       #address-cells = <1>;
+       #size-cells = <0>;
+
+       mediatek,mcm;
+       resets = <&rstctrl 2>;
+       reset-names = "mcm";
+
+       dsa,mii-bus = <&mdio>;
+
+       ports {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               reg = <0>;
+
+               port@0 {
+                       reg = <0>;
+                       label = "lan0";
+                       cpu = <&cpu_port0>;
+               };
+
+               port@1 {
+                       reg = <1>;
+                       label = "lan1";
+                       cpu = <&cpu_port0>;
+               };
+
+               port@2 {
+                       reg = <2>;
+                       label = "lan2";
+                       cpu = <&cpu_port0>;
+               };
+
+               port@3 {
+                       reg = <3>;
+                       label = "lan3";
+                       cpu = <&cpu_port0>;
+               };
+
+               port@4 {
+                       reg = <4>;
+                       label = "wan";
+                       cpu = <&cpu_port0>;
+               };
+
+               cpu_port0: port@6 {
+                       reg = <6>;
+                       label = "cpu";
+                       ethernet = <&gmac0>;
+                       phy-mode = "rgmii";
+
+                       fixed-link {
+                               speed = <1000>;
+                               full-duplex;
+                       };
+               };
+       };
+};
+
 &pinctrl {
        state_default: pinctrl0 {
                gpio {

4. 修改 OpenWrt 中的网络配置

这里仅仅是为了在 OpenWrt 中测试 DSA 是否正常工作
修改 target/linux/ramips/base-files/etc/board.d/02_network,将对应板子的脚本语句修改为:
1
ucidef_set_interfaces_lan_wan "lan0 lan1 lan2 lan3" "wan"

5. 开启 kernel 网络子系统的 DSA 功能

Networking support   --->   Networking options   --->   Distributed Switch Architecture
Device Drivers   --->   Network device support   --->   Distributed Switch Architecture drivers   --->   Mediatek MT7530 Ethernet switch support
6. 编译测试

 

=================

Linksys wrt1200ac + openwrt在新DSA驱动架构下的vlan设置

https://zhuanlan.zhihu.com/p/24884136

编辑于 2017-01-14 23:58

 

关于openwrt上vlan的设置,我在大约三年前曾经分享过两篇心得:

通过使用swconfig命令配置vlan,解决internet和iptv流量共用一根网线的问题,互不干扰。后来家里设备有所变化,3700v4刷上了openwrt,老旧的TPLink WR1041N也换成了Netgear r6300v2,运行Tomato Shibby,但vlan的配置并没有什么不同。顺便提一句,在web UI易用性上,Tomato仍然是开源固件中的王者。


今天要分享一些有趣的后续。2016年上半年我一时手痒,入手了Linksys wrt1200ac,打算换掉年迈的主路由3700v4,但因为种种原因一直懒得动手。这几天终于决定挤出点时间把wrt1200ac配置起来。

首先是选择合适的openwrt版本。入手wrt1200ac后不久,我就自己从openwrt git代码编译了一版Chaos Calmer,刷上运行也没什么问题。不过从论坛讨论历史来看,有不少有用的补丁都因为种种原因并没有进入openwrt主干,而是各路大神在维护自己的版本。我最初想使用openwrt论坛用户davidc502自行编译的版本(需要FQ),但他从来不放出自己的补丁和config文件源码,我也就一直比较犹豫。最近发现论坛用户sera一直在发布更新自己的补丁包,并且也很热心的回答其他用户的提问,就决定利用他的补丁自己编译。从目前运行情况来看一切正常。

然后首要解决的问题是vlan配置。sera在论坛帖子中提到过,他发布的补丁已经默认使用新的DSA(Distributed Switch Architecture)交换机驱动架构,之前openwrt一直使用的swconfig不再支持。DSA的细节我不打算深入解释,对我这样的普通用户而言,直观可见的变化在于:

  • 传统的openwrt上,不同的lan口并不是可见的网卡,用户通过swconfig命令来管理交换机设备
  • 在DSA驱动架构下,lan口变成了独立可见的lan1, lan2, lan3, lan4网卡。交换机设备不再对用户可见
  • openwrt上vlan的配置方式已经和普通桌面/server Linux统一,用标准的iproute2包来管理,不再需要专用的swconfig

听起来是不是更容易了?不一定。先回顾一下我家里二级路由用的vlan设置:

lan口2接电信iptv机顶盒,被分在vlan 3。lan口3, 4接普通上网设备,分在vlan 1。lan口1是trunk port,接上级路由。上图中的wan口和vlan 2并没有使用,请忽略。重复一遍,lan口2, 3, 4都是untagged port,或者说access port,也就是说进出这几个端口的流量都不带vlan tag。只有lan口1会在和上级路由通信时自动打上vlan 1或3的tag。

 

这个配置对于swconfig而言非常简单,定义两个vlan,把不同的port标记为tagged或untagged即可。

但使用iproute2包中的ip命令,就无法完成这样的配置。因为ip并不直接支持把trunk port和untagged port划到同一个vlan!

具体的说,ip命令通过在普通网络设备上创建"别名"设备来创建vlan,例如假设有块网卡eth0:

ip link add name eth0.5 link eth0 type vlan id 5

这样会创建一个新的eth0.5的网卡,被划分到vlan 5下。所有在eth0物理端口上收到以太网包,如果带有vlan 5的tag,会被送给eth0.5这块网卡,而所有untagged的包还是会送给eth0。

也就是说,使用ip命令,只能建立进出流量都带tag的虚拟网卡,而无法直接把某块网卡直接加到某个vlan,也无法让这块网卡上收发的untagged数据在送到vlan中其他设备上时自动添加vlan tag。

以我非常有限的网络知识,觉得这个问题可以用网桥来解决。仍然使用ip命令来建立一个新的网桥设备,在trunk port对应的设备上建立vlan设备,并把vlan设备和untagged port对应的设备加入到同一个网桥:

# 新建网桥
ip link add name br0 type bridge

# 在lan1设备上新建vlan设备lan1.3并启用
ip link add name lan1.3 link lan1 type vlan id 3
ip link set lan1.3 up

# 将lan1.3加入到网桥
ip link set dev lan1.3 master br0

# 将lan3设备加入到网桥
ip link set dev lan3 master br0

然而这样还不行。虽然网桥会在设备间转发数据,但从lan3来的以太网包仍然没有vlan tag,lan1.3设备不会理睬;同样来自lan1.3的以太网包因为有vlan tag,也不会被lan3所连接的普通设备(IPTV机顶盒)所接受。

奇妙的是,似乎很少有人有这种需求。我只能Google到几条看起来有用的讨论,例如[Bridge] using bridges to connect vlans and untagged data。基本上都是需要使用ebtables规则来处理。我觉得使用ebtables一来麻烦,二来可能因为数据包要经过CPU处理而影响性能。

还好,我还搜到了这个短短的讨论串:Untagged vlan sub-interface。里面给出了重要的线索:iproute2包里其实还有一个叫做bridge的命令,看起来正是我需要的。

# 指定lan3在网桥中收发的数据都自动增加/去除vlan 3的tag
bridge vlan add dev lan3 vid 3 pvid untagged self

# 指定lan1.3在网桥中收发的数据都携带vlan 3的tag
bridge vlan add dev lan1.3 vid 3 self

# 查看网桥各端口设备的vlan设置情况
bridge vlan

# 以下为bridge vlan命令的输出,已略去无关内容
port	vlan ids
...
lan3	None
lan3	 3 PVID Egress Untagged
...
lan1	None
lan1	 3
...
lan1.3	None
lan1.3	 3
...
br0	None

解释一下,关键的命令

bridge vlan add dev lan3 vid3 pvid untagged self

pvid表示来自lan3网口(也就是IPTV)的以太网包会被自动加上vlan tag,而untagged表示来自网桥并经过lan3网口送出(到IPTV)的以太网包会被自动去除vlan tag。


接上网线,打开电视和IPTV,还是显示连接失败。用tcpdump -i lan1.3上有没有数据进出,发现有提示lan1.3设备没有up,手动up之;还是不行,用ifconfig给网桥br0加上IP地址,终于在IPTV上看到正常的用户界面了。(本人不确定这一步是不是必需,还望专家指正)

但无论选什么台,都没有画面,只有各级菜单界面是正常的。这个比较好解决,IPTV的视频数据是多播(multicast)来的,既然用户界面正常,只是没有画面,多半是网桥上还需要额外的多播设置。查了一下,果然linux网桥默认的multicast snooping(即IGMP snooping)是打开的,运行

echo 0 > /sys/class/net/br0/bridge/multicast_snooping

关闭之,节目画面正常啦。因为对Linux switch驱动并不了解,不清楚这样的设置下有多少是经由wrt1200ac的硬件完成,有多少部分需要CPU参与,我特意开着top看了一会儿IPTV节目,在观看大约10Mbps码率的视频流的情况下,wrt1200ac的CPU空闲率大致在92%到97%之间波动,与不开启IPTV时并无区别。

虽然需要的命令看起来不少,不过vlan设备和网桥的建立仍然可以在openwrt中使用uci命令或直接在/etc/config/network中配置,openwrt会正确处理。只有bridge vlan和设置多播开关一共三条命令需要写到rc.local里。重要的是,使用ip+bridge命令的配置方式对于运行openwrt或其他任何Linux发行版本的x86软路由也是适用的。

对了,提醒一下,openwrt下iproute2的bridge命令并未与ip命令一起打包,而是以ip-bridge的名字单独打包。openwrt中名为bridge的包也不是bridge命令,而是传统的brctl命令。

 

================== End

 

posted @ 2022-06-27 01:32  lsgxeva  阅读(1877)  评论(0编辑  收藏  举报