RSTP(Rapid Spanning Tree Protocol,快速生成树协议)是STP(Spanning Tree Protocol,生成树协议)的一个改进版本,主要区别在于RSTP通过引入新的机制来加快网络的收敛速度。具体来说:
- 端口角色的增加和优化:RSTP增加了Backup端口和边缘端口两种角色。共有5中端口角色,而STP只有3种。这些额外的端口角色简化了生成树协议的理解和部署。
- 端口状态的优化:RSTP将端口状态从STP的5种减少到3种,分别是:Discarding、Learning和Forwarding状态,这种简化使得端口状态的装换更加快速和直接。
- BPDE(Bridge Protocol Data Unit)格式和处理的优化:RSTP改变了BPDU的格式,充分利用了BPDU中Flag字段,明确了端口角色,并增加了P/A机制位的标识,这种优化提高了BPDU的处理效率,从而加快了网络的收敛速度。
- 收敛速度的优化:RSTP引入了边缘端口机制、根端口快速切换机制以及Proposal/Agreement机制,这些机制共同作用,显著提高了网络在拓扑变化时的收敛速度。相比之下,STP的收敛依赖于计时器,且收敛速度较慢。
STP协议端口状态
STP端口的物种状态分别是:
Disabled(禁用):端口处于禁用状态,不参与STP计算,也不转发数据帧。
Blocking(阻塞):端口接收数据帧,但不允许转发这些数据帧,只用于接收BPDU(Bridge Protocol Data Unit,桥协议数据单元)、执行STP计算。
Listening(监听):端口处理监听状态,接收数据帧,并且准备进行状态转移。
Learning(学习):端口开始从其他接口学习到的数据中学习MAC地址,并添加到端口的MAC地址表中。
Forwarding(转发):端口转发数据帧,作为桥接网络中的一个活动端口,可以转发数据帧到其他端口。
STP环路检测原理
设备通过发送环路检测报文并检测其是否返回本设备(不要求收、发端口为同一端口)以确认是否存在环路,若某端口收到了由本设备发出的环路检测报文,就认定该端口所在链路存在环路。
BPDU的主要参数
Root Identifier(根ID):发送此配置BPDU的交换机所认为的根交换机的交换机标识。
Root Path Cost(到根的路径开销):从发送此配置BPDU的交换机到达根交换机的最短路径总开销,含交换机根端口的开销,不含发送此配置的BPDU的端口的开销。
Bridge Identifier(桥ID):发送此配置BPDU的交换机的STP交换机标识。
Port Identifier(端口ID):发送此配置的BPDU的交换机端口的STP端口标识
比较次序:Root Identifier > Root Path Cost> Bridge Identifier>Port Identifier
值越小越优先
Bridge ID
- 桥ID是交换机的STP标示符,一共8个字节,由2个自己的优先级和6个字节的MAC地址构成;
- 桥优先级缺省为32768,可以手工修改。
- MAC地址为交换机的背板MAC
- 网络中Bridge ID最小的交换价将成为根桥;
Path cost
路径开销是一个端口量,是STP/RSTP协议用于选择链路的参考值;
端口路径开销的默认值及取值范围由选定的路径开销算法决定,路径开销与端口的带宽成反比。
华为网络设备支持的路径开销计算标准:802.1d-1998、802.1t、legacy等。
Port ID
•端口ID (2字节)= 端口优先级(1字节)+ 端口编号(1字节)
•缺省优先级128,范围0-255,越小越优。
选举过程
下面以一个实例进行说明
从上图中可以看到,运行了生成树算法之后,S4选择阻塞F0/0,S5选择阻塞F0/2,应该是看到非根桥转发的BPDU后做的选择
非根桥转发的BPDU
传统生成树中只有根桥才能产生配置BPDU,非根桥只是转发根桥产生的BPDU。试想一下如果仅仅只是转发根桥的BPDU,不对BPDU做任何更改,就像转发常规数据帧一样。这样的话S4和S5怎么判断阻塞的端口,又凭啥要阻塞我的端口。这就引出了关键点---非根桥转发的BPDU。
可以看出非根桥转发根桥BPDU时做了如下修改:
1,根路径开销;
2,发送者网桥ID;
3,端口标识;
通过三个步骤来分解S4和S5阻塞端口的过程
第一步:S2和S3看到的BPDU
S2和S3看到报文后,发现自己的MAC地址不如人家,就放弃竞选根桥了,只好去选根端口了,只要接收不到更小的BID,那就赶紧定下来根端口,报文中的根路径开销决定了S2和S3的根端口。
第二步:S4看到的BPDU
当S4看到BPDU后发现自己和根桥的ID比,根本不如人家,那我只好来定夺根端口了,S2告诉我到S1的开销是19,S3告诉我到S1的开销也是19,那当然是选择S2的那条路了(S2的端口ID小于S3的端口ID),S3的这条路只能堵上。网桥ID决定了S4的根端口,路径开销决定了阻塞端口。
第三步:S5看到的BPDU
当S5看到途中的BPDU后也没什么想法了,MAC地址比根桥的大太多了,只好选根端口了。S5的F0/3和F0/2收到S4发来的BPDU报文里唯一的不同只有端口ID,那就只有比较端口ID了,哪个端口接收到的端口ID大就阻塞该端口。端口ID决定了S5的根端口,路径开销决定了阻塞端口。
如何判断内核支持STP还是RSTP?
从内核中定义的宏可以看出,内核中只支持STP,并不支持RSTP,RSTP需要在用户层来实现:
STP协议头:
RSTP协议头
MSTP
多生成树协议MSTP(Multiple Spanning Tree Protocol)是IEEE 802.1s中定义的一种新型生成树协议。该协议主要是解决了传统stp和rstp,在同一局域网内所有的vlan共享一个生成树,无法在vlan间实现数据流量的负载均衡,以及产生次优路径的问题。
在每个广播域中选举出一个根网桥
在选举开始的时候,所有的交换机都会认为自己是根桥,他们产生并相互发送自己的BPDU。比较BPDU重Bridge-id:优先级+MAC地址,越小越优先。
Bridge-id: 优先级+MAC地址 优先级:范围0-65535,必须设置成 4096的倍数,最小是0 优先级的默认值是 32768, 越小越优先.
当根桥选举完成后,只有根桥自己能够产生BPDU,其他的非根桥负责接收和转发来自根桥的BPDU。
在非根交换机上,选出根端口
比较到达根桥的路径开销
如下图,SW1的端口2比端口1路径开销小,SW2的端口2比端口1开销小。开销小的端口为根端口。
比较Sender-BID
如果开销值相同:比较端口接收到的BPDU中 Sender-BID这一参数。例如此图,SW4的两个接口到根桥的开销值是相同的,比较Sender-BID,端口2的对端交换机BPDU更优先,从而SW4的端口2是根端口
比较Sender-PID
如果交换机的各个接口接收到BPDU中的 Sender-BID也相同,则比较 BPDU中的 Sender-PID,例如此图,SW5的两个端口,对端交换机的3端口PID更优先,所以SW5的2端口选为根端口。
- 如果交换机的各个接口接收到BPDU中的 Sender-PID也相同,例如使用了HUB集线器,则比较交换机本身端口的PID
比较交换机本身端口的PID
如果交换机的各个接口接收到BPDU中的 Sender-PID也相同,例如使用了HUB集线器,则比较交换机本身端口的PID
选出指定端口
在剩余的链路上,选举出指定端口
1)根端口对面的端口,就是指定端口;
2)在剩余链路上,选举指定端口
选举方法如下:
- 比较端口所在交换机到达根桥的路径开销,越小越优先
- 如果端口所在交换机到根桥的开销相同,则比较端口所在交换机的BID
- 如果所在交换机的BID也相同,则比较交换机的PID
应用层实现
STP
执行brctl show命令可以看到STP协议是否开启。
root@jenet:~# brctl show
bridge name bridge id STP enabled interfaces
br0 8000.5c857ea0aab9 no lan
wan
STP协议是在内核中实现的,brctl通过API获取内核参数:
static int br_cmd_show(int argc, char *const* argv)
{
int i;
printf("bridge name\tbridge id\t\tSTP enabled\tinterfaces\n");
if (argc == 1)
br_foreach_bridge(show_bridge, NULL);
else
for(i = 2; i <= argc; i++)
show_bridge(argv[i - 1], NULL);
return 0;
}
在如下函数中获取桥信息时,一并获取STP启用状态:
info->stp_enabled = fetch_int(path, "stp_state");
int br_get_bridge_info(const char *bridge, struct bridge_info *info)
{
DIR *dir;
char path[SYSFS_PATH_MAX];
snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/bridge", bridge);
dir = opendir(path);
if (dir == NULL) {
dprintf("path '%s' is not a directory\n", path);
goto fallback;
}
memset(info, 0, sizeof(*info));
fetch_id(path, "root_id", &info->designated_root);
fetch_id(path, "bridge_id", &info->bridge_id);
info->root_path_cost = fetch_int(path, "root_path_cost");
fetch_tv(path, "max_age", &info->max_age);
fetch_tv(path, "hello_time", &info->hello_time);
fetch_tv(path, "forward_delay", &info->forward_delay);
fetch_tv(path, "max_age", &info->bridge_max_age);
fetch_tv(path, "hello_time", &info->bridge_hello_time);
fetch_tv(path, "forward_delay", &info->bridge_forward_delay);
fetch_tv(path, "ageing_time", &info->ageing_time);
fetch_tv(path, "hello_timer", &info->hello_timer_value);
fetch_tv(path, "tcn_timer", &info->tcn_timer_value);
fetch_tv(path, "topology_change_timer",
&info->topology_change_timer_value);;
fetch_tv(path, "gc_timer", &info->gc_timer_value);
info->root_port = fetch_int(path, "root_port");
info->stp_enabled = fetch_int(path, "stp_state");
info->topology_change = fetch_int(path, "topology_change");
info->topology_change_detected = fetch_int(path, "topology_change_detected");
closedir(dir);
return 0;
fallback:
return old_get_bridge_info(bridge, info);
}
在设备中查看如下:
RSTP
RSTP启动涉及到三个文件:
rstpctl:rstp客户端,用来和rstpd通信。
rstpd: rstp协议的守护进程,用来处理BPDT。
bridge-stp:通过rstpctl来管理rstpd的脚本文件。
rstpctl
#define RSTP_SERVER_SOCK_NAME ".rstp_server"
在ctl_client_init()函数中创建一个unix套接字连接rstpd进程的socket。
int ctl_client_init(void)
{
struct sockaddr_un sa_svr;
int s;
TST(strlen(RSTP_SERVER_SOCK_NAME) < sizeof(sa_svr.sun_path), -1);
s = socket(PF_UNIX, SOCK_DGRAM, 0);
if (s < 0) {
ERROR("Couldn't open unix socket: %m");
return -1;
}
set_socket_address(&sa_svr, RSTP_SERVER_SOCK_NAME);
struct sockaddr_un sa;
char tmpname[64];
sprintf(tmpname, "RSTPCTL_%d", getpid());
set_socket_address(&sa, tmpname);
/* We need this bind. The autobind on connect isn't working properly.
The server doesn't get a proper sockaddr in recvmsg if we don't do this.
*/
if (bind(s, (struct sockaddr *)&sa, sizeof(sa)) != 0) {
ERROR("Couldn't bind socket: %m");
close(s);
return -1;
}
if (connect(s, (struct sockaddr *)&sa_svr, sizeof(sa_svr)) != 0) {
ERROR("Couldn't connect to server");
close(s);
return -1;
}
fd = s;
return 0;
}
通过rstpctl设置命令的处理函数定义如下:
static const struct command commands[] = {
{0, 32, "showbridge", cmd_showbridge,
"[<bridge> ... ]\t\tshow bridge state"},
{1, 32, "showport", cmd_showport,
"<bridge> [<port> ... ]\tshow port state"},
{1, 32, "showportdetail", cmd_showportdetail,
"<bridge> [<port> ... ]\tshow port state (detail)"},
{2, 0, "rstp", cmd_rstp,
"<bridge> {on|off}\tenable/disable rstpd control"},
{2, 0, "setbridgestate", cmd_setbridgestate,
"<bridge> {on|off}\tstart/stop rstp (when enabled)"},
{2, 0, "setbridgeprio", cmd_setbridgeprio,
"<bridge> <priority>\tset bridge priority (0-61440)"},
{2, 0, "sethello", cmd_setbridgehello,
"<bridge> <hellotime>\tset bridge hello time (1-10)"},
{2, 0, "setmaxage", cmd_setbridgemaxage,
"<bridge> <maxage>\tset bridge max age (6-40)"},
{2, 0, "setfdelay", cmd_setbridgefdelay,
"<bridge> <fwd_delay>\tset bridge forward delay (4-30)"},
{2, 0, "setforcevers", cmd_setbridgeforcevers,
"<bridge> {normal|slow}\tnormal RSTP or force to STP"},
{3, 0, "setportprio", cmd_setportprio,
"<bridge> <port> <priority>\tset port priority (0-240)"},
{3, 0, "setportpathcost", cmd_setportpathcost,
"<bridge> <port> <cost>\tset port path cost"},
{3, 0, "setportedge", cmd_setportedge,
"<bridge> <port> {yes|no}\tconfigure if it is an edge port"},
{3, 0, "setportnonstp", cmd_setportnonstp,
"<bridge> <port> {yes|no}\tdisable STP for the port"},
{3, 0, "setportp2p", cmd_setportp2p,
"<bridge> <port> {yes|no|auto}\tset whether p2p connection"},
{2, 0, "portmcheck", cmd_portmcheck,
"<bridge> <port>\ttry to get back from STP to RSTP mode"},
{1, 0, "debuglevel", cmd_debuglevel, "<level>\t\tLevel of verbosity"},
};
开启rstp命令的函数为:
static int cmd_rstp(int argc, char *const *argv)
{
int stp, r;
int br_index = get_index(argv[1], "bridge");
if (!strcmp(argv[2], "on") || !strcmp(argv[2], "yes")
|| !strcmp(argv[2], "1"))
stp = 1;
else if (!strcmp(argv[2], "off") || !strcmp(argv[2], "no")
|| !strcmp(argv[2], "0"))
stp = 0;
else {
fprintf(stderr, "expect on/off for argument\n");
return 1;
}
r = CTL_enable_bridge_rstp(br_index, stp);
if (r) {
fprintf(stderr, "Failed to enable/disable RSTP: %s\n",
CTL_error_explanation(r));
return -1;
}
return 0;
}
如果开启了STP,则开启RSTP会失败
在init_bridge_stp函数中判断是否开启了STP
int init_bridge_stp(struct ifdata *br)
{
if (br->stp_up) {
ERROR("STP already started");
return 0;
}
/* Init STP state */
TST(init_rstplib_instance(br) == 0, -1);
struct ifdata *p = br->port_list;
while (p) {
if (add_port_stp(p) != 0)
break;
p = p->port_next;
}
if (p) {
struct ifdata *q = br->port_list;
while (q != p) {
remove_port_stp(q);
q = q->port_next;
}
/* Clear bridge STP state */
clear_rstplib_instance(br);
return -1;
}
br->stp_up = 1;
return 0;
}
debuglevel
#define LOG_LEVEL_NONE 0
#define LOG_LEVEL_ERROR 1
#define LOG_LEVEL_INFO 2
#define LOG_LEVEL_DEBUG 3
#define LOG_LEVEL_RSTPLIB 4
bridge-stp脚本
#!/bin/bash
#
# Script to start/stop spanning tree called from kernel
# Make sure umask is sane
umask 022
# Set up a default search path.
PATH="/sbin:/usr/sbin:/bin:/usr/bin"
export PATH
if [ $# -ne 2 ]; then
echo "Usage: bridge-stp <bridge> {start|stop}"
exit 1
fi
bridge=$1
service=rstpd
pid_file=/var/run/${service}.pid
# Set $pid to pids from /var/run* for {program}. $pid should be declared
# local in the caller.
# Returns LSB exit code for the 'status' action.
checkpid() {
pid=
if [ -f "$1" ] ; then
local line p
read line < "$pid_file"
for p in $line ; do
[ -z "${p//[0-9]/}" -a -d "/proc/$p" ] && pid="$pid $p"
done
if [ -n "$pid" ]; then
return 0
fi
return 1 # "Program is dead and /var/run pid file exists"
fi
return 3 # "Program is not running"
}
daemon() {
local pid
checkpid $pid_file
[ -n "$pid" ] && return
# start it
/sbin/rstpd
RETVAL=$?
[ $RETVAL -eq 0 ] && touch /var/lock/subsys/$service
}
start() {
daemon
}
case $2 in
start)
daemon
exec /sbin/rstpctl rstp $bridge on ;;
stop)
exec /sbin/rstpctl rstp $bridge off ;;
*)
echo "Unknown action:" $2
echo "Usage: bridge-stp <bridge> {start|stop}"
exit 1
该脚本先检查pid文件,如果不存在则启动/sbin/rstpd。但是在daemon函数中,如果pid为空,则直接返回了,
RSTPD
rstpd通过rtnl和内核通信
内核中对STP报文的处理
在kernel/net/bridge/br.c文件中注册了bridge模块:
module_init(br_init)
module_exit(br_deinit)
MODULE_LICENSE("GPL");
MODULE_VERSION(BR_VERSION);
MODULE_ALIAS_RTNL_LINK("bridge");
TCN BPDU
Topology Change Notification BPDU
STP与RSTP的冲突问题
在使用RSTP前,需要先通过 brctl stp br0 off命令关闭内核中的STP功能。此时打印内核的br->stp_enabled的值为0,执行brctl stp br0 on命令后,打印内核的br->stp_enabled的值为1。
先执行brctl stp br0 off,再执行bridge-stp br0 start开启rstpd功能,此时打印内核的br->stp_enabled的值为0,也就是说内核的br->stp_enabled只代表STP的开关,和RSTP无关。
先执行brctl stp br0 on命令开启内核的STP功能,再执行bridge-stp br0 start开启RSTP功能,在PC上抓包,发现设备发了两份包,一份是STP,一份是RSTP:
执行brctl stp br0 on报错
[ 1881.348918] br-lan: failed to start userspace STP (-8)
[ 2126.204139] br-lan: failed to start userspace STP (-8)
在执行该命令时会调用如下函数:
函数调用关系:
net/bridge/br_ioctl.c
old_dev_ioctl()-->br_stp_set_enabled()-->br_stp_start()-->
查看错误码-8,是说文件格式有错:
发现是由于在bridge-stp文件中增加了打印:set -xe导致的,将其去掉后,报256的错误:
此错误是由于在/var/run/目录下已经存在rstpd.pid文件,删除此文件后,再次执行brctl stp br0 on命令,发现终端进程卡住了,证明是在拉起用户态进程的处理过程中异常了。
如果bridge-stp文件格式错误,则打印如下信息:
root@jenet:~# brctl stp br0 on
[ 65.292720] br0: br_stp_call_user: pro:/sbin/bridge-stp,br->dev->name:root@jenet:~# br0, arg:start, rc=-8
[ 65.292745] br_stp_start: err=-8
[ 65.292751] br0: failed to start userspace STP (-8)
[ 65.292756] br_stp_start: using kernel STP
^C
转发时状态判断
在linux-4.14.195/net/bridge/br_forward.c文件中有如下判断:
只有在端口状态为forwarding时才会转发数据,在此处增加打印:
端口状态的定义如下:
#define BR_STATE_DISABLED 0
#define BR_STATE_LISTENING 1
#define BR_STATE_LEARNING 2
#define BR_STATE_FORWARDING 3
#define BR_STATE_BLOCKING 4
当产生环路时,后台有如下日志打印:
[ 122.990840] net_ratelimit: 2302 callbacks suppressed
该条打印在linux-4.14.195/net/core/utils.c文件中定义:
/*
* All net warning printk()s should be guarded by this function.
*/
int net_ratelimit(void)
{
return __ratelimit(&net_ratelimit_state);
}
EXPORT_SYMBOL(net_ratelimit);
#define __ratelimit(state) ___ratelimit(state, __func__)
最终在/linux-4.14.195/lib/ratelimit.c 中定义如下:
/*
* __ratelimit - rate limiting
* @rs: ratelimit_state data
* @func: name of calling function
*
* This enforces a rate limit: not more than @rs->burst callbacks
* in every @rs->interval
*
* RETURNS:
* 0 means callbacks will be suppressed.
* 1 means go ahead and do it.
*/
int ___ratelimit(struct ratelimit_state *rs, const char *func)
{
unsigned long flags;
int ret;
if (!rs->interval)
return 1;
/*
* If we contend on this state's lock then almost
* by definition we are too busy to print a message,
* in addition to the one that will be printed by
* the entity that is holding the lock already:
*/
if (!raw_spin_trylock_irqsave(&rs->lock, flags))
return 0;
if (!rs->begin)
rs->begin = jiffies;
if (time_is_before_jiffies(rs->begin + rs->interval)) {
if (rs->missed) {
if (!(rs->flags & RATELIMIT_MSG_ON_RELEASE)) {
printk_deferred(KERN_WARNING
"%s: %d callbacks suppressed\n",
func, rs->missed);
rs->missed = 0;
}
}
rs->begin = jiffies;
rs->printed = 0;
}
if (rs->burst && rs->burst > rs->printed) {
rs->printed++;
ret = 1;
} else {
rs->missed++;
ret = 0;
}
raw_spin_unlock_irqrestore(&rs->lock, flags);
return ret;
}
EXPORT_SYMBOL(___ratelimit);
#define RATELIMIT_STATE_INIT(name, interval_init, burst_init) { \
.lock = __RAW_SPIN_LOCK_UNLOCKED(name.lock), \
.interval = interval_init, \
.burst = burst_init, \
}
interval被初始化为:5 * HZ
burst被初始化为:10
系统每2秒收到一个BPDU报文:
[ 178.952397] File: net/bridge/br_stp.c, Line: 515
[ 180.952265] File: net/bridge/br_stp.c, Line: 515
[ 182.952208] File: net/bridge/br_stp.c, Line: 515
[ 184.952296] File: net/bridge/br_stp.c, Line: 515
[ 186.952215] File: net/bridge/br_stp.c, Line: 515
[ 188.952118] File: net/bridge/br_stp.c, Line: 515
[ 190.952155] File: net/bridge/br_stp.c, Line: 515
[ 192.952016] File: net/bridge/br_stp.c, Line: 515
[ 194.951912] File: net/bridge/br_stp.c, Line: 515
[ 196.951908] File: net/bridge/br_stp.c, Line: 515
[ 198.951927] File: net/bridge/br_stp.c, Line: 515
[ 200.951827] File: net/bridge/br_stp.c, Line: 515
[ 202.951748] File: net/bridge/br_stp.c, Line: 515
[ 204.951707] File: net/bridge/br_stp.c, Line: 515
[ 206.951666] File: net/bridge/br_stp.c, Line: 515
[ 208.951704] File: net/bridge/br_stp.c, Line: 515
当端口进入blocking状态后,会进入下面的分支:
admin@OpenWrt:/# [ 364.949717] File: net/bridge/br_stp.c, Line: 515
[ 366.949706] File: net/bridge/br_stp.c, Line: 515
[ 368.949802] File: net/bridge/br_stp.c, Line: 515
[ 370.949674] File: net/bridge/br_stp.c, Line: 515
[ 372.315630] mtk_soc_eth 1e100000.ethernet eth0: port 2 link up
[ 372.949774] File: net/bridge/br_stp.c, Line: 515
[ 372.958992] File: net/bridge/br_stp.c, Line: 473, br:br-lan, dev;lan
[ 372.971657] br-lan: topology change detected, sending tcn bpdu
[ 372.983329] File: net/bridge/br_stp.c, Line: 413, br:br-lan, dev;lan
[ 372.995995] File: net/bridge/br_stp.c, Line: 44, br:br-lan, dev;lan
[ 373.008480] File: toolchain ./include/net/switchdev.h, Line: 202, dev;lan
[ 373.022002] File: net/bridge/br_stp.c, Line: 54, br:br-lan, dev;lan
[ 373.034487] br-lan: port 2(lan) entered blocking state
[ 373.044732] File: net/bridge/br_netlink.c, Line: 468, dev:lan
[ 373.056272] File: net/bridge/br_stp.c, Line: 515
[ 373.065487] File: net/bridge/br_stp.c, Line: 473, br:br-lan, dev;lan
[ 373.909721] File: net/bridge/br_stp.c, Line: 515
[ 373.918930] File: net/bridge/br_stp.c, Line: 473, br:br-lan, dev;lan
[ 373.931590] File: toolchain ./include/net/switchdev.h, Line: 202, dev;br-lan
[ 374.949629] File: net/bridge/br_stp.c, Line: 515
[ 374.958833] File: net/bridge/br_stp.c, Line: 473, br:br-lan, dev;lan
[ 374.971519] File: net/bridge/br_stp.c, Line: 515
[ 374.980721] File: net/bridge/br_stp.c, Line: 473, br:br-lan, dev;lan
[ 376.949633] File: net/bridge/br_stp.c, Line: 515
[ 376.958838] File: net/bridge/br_stp.c, Line: 473, br:br-lan, dev;lan
[ 376.971522] File: net/bridge/br_stp.c, Line: 515
[ 376.980726] File: net/bridge/br_stp.c, Line: 473, br:br-lan, dev;lan
[ 377.665397] p->state != BR_STATE_FORWARDING File: net/bridge/br_forward.c, Line: 173, br:br-lan, dev:lan, state:4
[ 377.685838] p->state != BR_STATE_FORWARDING File: net/bridge/br_forward.c, Line: 31, br:br-lan, dev:lan, state:4
[ 378.668114] p->state != BR_STATE_FORWARDING File: net/bridge/br_forward.c, Line: 173, br:br-lan, dev:lan, state:4
[ 378.688567] p->state != BR_STATE_FORWARDING File: net/bridge/br_forward.c, Line: 31, br:br-lan, dev:lan, state:4
[ 378.949712] File: net/bridge/br_stp.c, Line: 515
[ 378.958916] File: net/bridge/br_stp.c, Line: 473, br:br-lan, dev;lan
[ 378.971590] File: net/bridge/br_stp.c, Line: 515
[ 378.980773] File: net/bridge/br_stp.c, Line: 473, br:br-lan, dev;lan
[ 379.674625] p->state != BR_STATE_FORWARDING File: net/bridge/br_forward.c, Line: 173, br:br-lan, dev:lan, state:4
[ 379.695070] p->state != BR_STATE_FORWARDING File: net/bridge/br_forward.c, Line: 31, br:br-lan, dev:lan, state:4
[ 380.684415] p->state != BR_STATE_FORWARDING File: net/bridge/br_forward.c, Line: 173, br:br-lan, dev:lan, state:4
[ 380.704867] p->state != BR_STATE_FORWARDING File: net/bridge/br_forward.c, Line: 31, br:br-lan, dev:lan, state:4
对应的代码为:
此时通过命令行查看接口状态为blocking:
调用maybe_deliver函数的地方为:
修改pathcost
默认情况下,每个端口的pathcost都是100,此时端口ID大的端口被blocking :
此时,修改wan口的pathcost为1000,再查看时发现wan口被blocking了。
每次收到BPDU报文都会更新根端口和指定端口,在br_port_state_selection()函数中,只要不是根端口和指定端口,都会进入到blocking状态:
br_forward.c文件中函数调用关系为:br_flood()-->maybe_deliver()-->should_deliver()
在上面的代码中增加打印:
打印如下:
[ 139.790465] br_port_state_selection: designated_port dev:wan,designated_port:32770,port_id:32770
[ 139.790507] br_port_state_selection: designated_port dev:lan,designated_port:32769,port_id:32769
[ 139.790556] br0: port 1(lan) entered listening state
[ 141.628637] br_port_state_selection: designated_port dev:wan,designated_port:32770,port_id:32770
[ 141.628700] br_port_state_selection: root_port dev:lan,port_no:1,root_port:1
[ 142.992958] br_port_state_selection: designated_port dev:wan,designated_port:32770,port_id:32770
[ 142.993017] br_port_state_selection: root_port dev:lan,port_no:1,root_port:1
[ 144.089529] br_port_state_selection: designated_port dev:wan,designated_port:32770,port_id:32770
[ 144.089558] br_port_state_selection: root_port dev:lan,port_no:1,root_port:1
^C
root@jenet:~# [ 146.006292] br_port_state_selection: designated_port dev:wan,designated_port:32770,port_id:32770
[ 146.006321] br_port_state_selection: root_port dev:lan,port_no:1,root_port:1
[ 148.139787] br_port_state_selection: designated_port dev:wan,designated_port:32770,port_id:32770
[ 148.139822] br_port_state_selection: root_port dev:lan,port_no:1,root_port:1
[ 150.059831] br_port_state_selection: designated_port dev:wan,designated_port:32770,port_id:32770
[ 150.059929] br_port_state_selection: root_port dev:lan,port_no:1,root_port:1
[ 152.196543] br_port_state_selection: designated_port dev:wan,designated_port:32770,port_id:32770
[ 152.196623] br_port_state_selection: root_port dev:lan,port_no:1,root_port:1
[ 154.116565] br_port_state_selection: designated_port dev:wan,designated_port:32770,port_id:32770
[ 154.116607] br_port_state_selection: root_port dev:lan,port_no:1,root_port:1
[ 155.071072] br0: port 1(lan) entered learning state
[ 156.033369] br_port_state_selection: designated_port dev:wan,designated_port:32770,port_id:32770
[ 156.033429] br_port_state_selection: root_port dev:lan,port_no:1,root_port:1
[ 158.028491] rk_gmac-dwmac fe010000.ethernet lan: Link is Down
[ 158.028826] br0: port 1(lan) entered disabled state
[ 158.029008] br_port_state_selection: designated_port dev:wan,designated_port:32770,port_id:32770
[ 158.029058] br0: topology change detected, propagating
先插入wan口网线,再插入lan口网线
使能STP日志
lan口不插网线,wan口插网线,日志如下:
root@jenet:~# brctl stp br0 on
[ 65.363143] br0: br_stp_call_user: pro:/sbin/bridge-stp,br->dev->name:brroot@jenet:~# 0, arg:start, rc=-8
[ 65.363174] br_stp_start: err=-8
[ 65.363182] br0: failed to start userspace STP (-8)
[ 65.363189] br_stp_start: using kernel STP,br->stp_enabled=1
[ 65.363199] br_port_state_selection: dev:wan,designated_port:32770,port_id:32770,port_no:2,root_port:0
组网测试
有线口环路
两台RK的LAN与LAN对接,WAN与WAN对接。在一台
另外一台的端口状态为:
先插入WAN口,打印如下:
先插入wan口,再插入lan口:
root@jenet:~# [ 151.997410] rk_gmac-dwmac fe2a0000.ethernet wan: Link is Up - 1Gbps/Full - flow control off
[ 151.997612] br0: port 2(wan) entered blocking state
[ 151.997652] br_port_state_selection: dev:wan,designated_port:32770,port_id:32770,port_no:2,root_port:0
[ 151.997684] p->designated_bridge: dev:wan 8000.5c857ea0aab9
[ 151.997713] p->br->bridge_id: dev:wan 8000.5c857ea0aab9
[ 151.997740] br0: port 2(wan) entered listening state
[ 152.553989] br_port_state_selection: dev:wan,designated_port:32770,port_id:32770,port_no:2,root_port:2
[ 152.554018] p->designated_bridge: dev:wan 8000.5c857e031866
[ 152.554024] p->br->bridge_id: dev:wan 8000.5c857ea0aab9
[ 153.702511] br_port_state_selection: dev:wan,designated_port:32770,port_id:32770,port_no:2,root_port:2
[ 153.702542] p->designated_bridge: dev:wan 8000.5c857e031866
[ 153.702550] p->br->bridge_id: dev:wan 8000.5c857ea0aab9
[ 155.622649] br_port_state_selection: dev:wan,designated_port:32770,port_id:32770,port_no:2,root_port:2
[ 155.622683] p->designated_bridge: dev:wan 8000.5c857e031866
[ 155.622690] p->br->bridge_id: dev:wan 8000.5c857ea0aab9
root@jenet:~# [ 157.755927] br_port_state_selection: dev:wan,designated_port:32770,port_id:32770,port_no:2,root_port:2
[ 157.755952] p->designated_bridge: dev:wan 8000.5c857e031866
[ 157.755960] p->br->bridge_id: dev:wan 8000.5c857ea0aab9
[ 159.676130] br_port_state_selection: dev:wan,designated_port:32770,port_id:32770,port_no:2,root_port:2
[ 159.676184] p->designated_bridge: dev:wan 8000.5c857e031866
[ 159.676195] p->br->bridge_id: dev:wan 8000.5c857ea0aab9
[ 161.596176] br_port_state_selection: dev:wan,designated_port:32770,port_id:32770,port_no:2,root_port:2
[ 161.596232] p->designated_bridge: dev:wan 8000.5c857e031866
[ 161.596252] p->br->bridge_id: dev:wan 8000.5c857ea0aab9
[ 163.729525] br_port_state_selection: dev:wan,designated_port:32770,port_id:32770,port_no:2,root_port:2
[ 163.729573] p->designated_bridge: dev:wan 8000.5c857e031866
[ 163.729588] p->br->bridge_id: dev:wan 8000.5c857ea0aab9
[ 165.649643] br_port_state_selection: dev:wan,designated_port:32770,port_id:32770,port_no:2,root_port:2
[ 165.649687] p->designated_bridge: dev:wan 8000.5c857e031866
[ 165.649695] p->br->bridge_id: dev:wan 8000.5c857ea0aab9
[ 166.074219] rk_gmac-dwmac fe010000.ethernet lan: Link is Up - 1Gbps/Full - flow control off
[ 166.074292] IPv6: ADDRCONF(NETDEV_CHANGE): lan: link becomes ready
[ 166.074453] br0: port 1(lan) entered blocking state
[ 166.074479] br_port_state_selection: dev:wan,designated_port:32770,port_id:32770,port_no:2,root_port:2
[ 166.074491] p->designated_bridge: dev:wan 8000.5c857e031866
[ 166.074502] p->br->bridge_id: dev:wan 8000.5c857ea0aab9
[ 166.074514] br_port_state_selection: dev:lan,designated_port:32769,port_id:32769,port_no:1,root_port:2
[ 166.074525] p->designated_bridge: dev:lan 8000.5c857ea0aab9
[ 166.074536] p->br->bridge_id: dev:lan 8000.5c857ea0aab9
[ 166.074544] br0: port 1(lan) entered listening state
[ 167.059879] br0: port 2(wan) entered learning state
[ 167.573021] br_port_state_selection: dev:wan,designated_port:32770,port_id:32770,port_no:2,root_port:2
[ 167.573079] p->designated_bridge: dev:wan 8000.5c857e031866
[ 167.573100] p->br->bridge_id: dev:wan 8000.5c857ea0aab9
[ 167.573128] br_port_state_selection: dev:lan,designated_port:32769,port_id:32769,port_no:1,root_port:2
[ 167.573218] p->designated_bridge: dev:lan 8000.5c857ea0aab9
[ 167.573253] p->br->bridge_id: dev:lan 8000.5c857ea0aab9
[ 167.573472] br_port_state_selection: dev:wan,designated_port:32770,port_id:32770,port_no:2,root_port:1
[ 167.573511] p->designated_bridge: dev:wan 8000.5c857e031866
[ 167.573543] p->br->bridge_id: dev:wan 8000.5c857ea0aab9
[ 167.573569] br0: topology change detected, sending tcn bpdu
[ 167.573625] br0: port 2(wan) entered blocking state
[ 167.573749] br_port_state_selection: dev:lan,designated_port:32769,port_id:32769,port_no:1,root_port:1
[ 167.573789] p->designated_bridge: dev:lan 8000.5c857e031866
[ 167.573821] p->br->bridge_id: dev:lan 8000.5c857ea0aab9
[ 168.556317] br_port_state_selection: dev:wan,designated_port:32770,port_id:32770,port_no:2,root_port:1
[ 168.556347] p->designated_bridge: dev:wan 8000.5c857e031866
[ 168.556353] p->br->bridge_id: dev:wan 8000.5c857ea0aab9
[ 168.556359] br_port_state_selection: dev:lan,designated_port:32769,port_id:32769,port_no:1,root_port:1
[ 168.556365] p->designated_bridge: dev:lan 8000.5c857e031866
[ 168.556371] p->br->bridge_id: dev:lan 8000.5c857ea0aab9
[ 169.703044] br_port_state_selection: dev:wan,designated_port:32770,port_id:32770,port_no:2,root_port:1
[ 169.703078] p->designated_bridge: dev:wan 8000.5c857e031866
[ 169.703085] p->br->bridge_id: dev:wan 8000.5c857ea0aab9
[ 169.703091] br_port_state_selection: dev:lan,designated_port:32769,port_id:32769,port_no:1,root_port:1
[ 169.703097] p->designated_bridge: dev:lan 8000.5c857e031866
[ 169.703103] p->br->bridge_id: dev:lan 8000.5c857ea0aab9
[ 169.703274] br_port_state_selection: dev:wan,designated_port:32770,port_id:32770,port_no:2,root_port:1
[ 169.703291] p->designated_bridge: dev:wan 8000.5c857e031866
[ 169.703298] p->br->bridge_id: dev:wan 8000.5c857ea0aab9
[ 169.703304] br_port_state_selection: dev:lan,designated_port:32769,port_id:32769,port_no:1,root_port:1
[ 169.703310] p->designated_bridge: dev:lan 8000.5c857e031866
[ 169.703316] p->br->bridge_id: dev:lan 8000.5c857ea0aab9
[ 171.623480] br_port_state_selection: dev:wan,designated_port:32770,port_id:32770,port_no:2,root_port:1
[ 171.623559] p->designated_bridge: dev:wan 8000.5c857e031866
[ 171.623589] p->br->bridge_id: dev:wan 8000.5c857ea0aab9
[ 171.623618] br_port_state_selection: dev:lan,designated_port:32769,port_id:32769,port_no:1,root_port:1
[ 171.623670] p->designated_bridge: dev:lan 8000.5c857e031866
[ 171.623712] p->br->bridge_id: dev:lan 8000.5c857ea0aab9
[ 171.623832] br_port_state_selection: dev:wan,designated_port:32770,port_id:32770,port_no:2,root_port:1
[ 171.623873] p->designated_bridge: dev:wan 8000.5c857e031866
[ 171.623923] p->br->bridge_id: dev:wan 8000.5c857ea0aab9
[ 171.623965] br_port_state_selection: dev:lan,designated_port:32769,port_id:32769,port_no:1,root_port:1
[ 171.623992] p->designated_bridge: dev:lan 8000.5c857e031866
[ 171.624035] p->br->bridge_id: dev:lan 8000.5c857ea0aab9
[ 173.756637] br_port_state_selection: dev:wan,designated_port:32770,port_id:32770,port_no:2,root_port:1
[ 173.756693] p->designated_bridge: dev:wan 8000.5c857e031866
[ 173.756713] p->br->bridge_id: dev:wan 8000.5c857ea0aab9
[ 173.756731] br_port_state_selection: dev:lan,designated_port:32769,port_id:32769,port_no:1,root_port:1
[ 173.756751] p->designated_bridge: dev:lan 8000.5c857e031866
[ 173.756768] p->br->bridge_id: dev:lan 8000.5c857ea0aab9
[ 173.756849] br_port_state_selection: dev:wan,designated_port:32770,port_id:32770,port_no:2,root_port:1
[ 173.756885] p->designated_bridge: dev:wan 8000.5c857e031866
[ 173.756915] p->br->bridge_id: dev:wan 8000.5c857ea0aab9
[ 173.756943] br_port_state_selection: dev:lan,designated_port:32769,port_id:32769,port_no:1,root_port:1
[ 173.756970] p->designated_bridge: dev:lan 8000.5c857e031866
[ 173.756996] p->br->bridge_id: dev:lan 8000.5c857ea0aab9
[ 175.676768] br_port_state_selection: dev:wan,designated_port:32770,port_id:32770,port_no:2,root_port:1
[ 175.676813] p->designated_bridge: dev:wan 8000.5c857e031866
[ 175.676821] p->br->bridge_id: dev:wan 8000.5c857ea0aab9
[ 175.676827] br_port_state_selection: dev:lan,designated_port:32769,port_id:32769,port_no:1,root_port:1
[ 175.676833] p->designated_bridge: dev:lan 8000.5c857e031866
[ 175.676851] p->br->bridge_id: dev:lan 8000.5c857ea0aab9
[ 175.676903] br_port_state_selection: dev:wan,designated_port:32770,port_id:32770,port_no:2,root_port:1
[ 175.676916] p->designated_bridge: dev:wan 8000.5c857e031866
[ 175.676931] p->br->bridge_id: dev:wan 8000.5c857ea0aab9
[ 175.676942] br_port_state_selection: dev:lan,designated_port:32769,port_id:32769,port_no:1,root_port:1
[ 175.676952] p->designated_bridge: dev:lan 8000.5c857e031866
[ 175.676961] p->br->bridge_id: dev:lan 8000.5c857ea0aab9
[ 177.596891] br_port_state_selection: dev:wan,designated_port:32770,port_id:32770,port_no:2,root_port:1
[ 177.596950] p->designated_bridge: dev:wan 8000.5c857e031866
[ 177.596971] p->br->bridge_id: dev:wan 8000.5c857ea0aab9
[ 177.596989] br_port_state_selection: dev:lan,designated_port:32769,port_id:32769,port_no:1,root_port:1
p->designated_bridge:存储的是网络中协商出来、指定的桥ID
p->br->bridge_id:此端口本地的桥ID。
只有跟桥设备会发送BPfDU报文,所以根桥上不会频繁打印上述日志,根桥设备分别插入wan/lan口网线打印日志为:
root@jenet:~# brctl show
bridge name bridge id STP enabled interfaces
br0 8000.5c857e031866 yes lan
wan
root@jenet:~# [ 500.544494] rk_gmac-dwmac fe010000.ethernet lan: Link is Up - 1Gbps/Full - flow control off
[ 500.544611] IPv6: ADDRCONF(NETDEV_CHANGE): lan: link becomes ready
[ 500.544828] br0: port 1(lan) entered blocking state
[ 500.544852] br_port_state_selection: dev:wan,designated_port:32770,port_id:32770,port_no:2,root_port:0
[ 500.544866] p->designated_bridge: dev:wan 8000.5c857e031866
[ 500.544877] p->br->bridge_id: dev:wan 8000.5c857e031866
[ 500.544895] br_port_state_selection: dev:lan,designated_port:32769,port_id:32769,port_no:1,root_port:0
[ 500.544906] p->designated_bridge: dev:lan 8000.5c857e031866
[ 500.544913] p->br->bridge_id: dev:lan 8000.5c857e031866
[ 500.544924] br0: port 1(lan) entered listening state
[ 501.530741] br0: port 1(lan) received tcn bpdu
[ 501.530786] br0: topology change detected, propagating
root@jenet:~#
root@jenet:~#
root@jenet:~#
root@jenet:~#
root@jenet:~# syspara show
所以说根桥设备上的所有端口都不会阻塞。
二层VPN环路测试
环路探测OK,tap口处于blocking状态:
现场拓扑测试
RK1表项
RK1使用WAN口上网(172.16.67.164),表项为:
接口MAC为:
root@jenet:~# ifconfig
br0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.1.10 netmask 255.255.255.0 broadcast 192.168.1.255
inet6 fe80::4a43 prefixlen 128 scopeid 0x20<link>
inet6 fe80::5e85:7eff:fea0:aab9 prefixlen 64 scopeid 0x20<link>
ether 5c:85:7e:a0:aa:b9 txqueuelen 1000 (Ethernet)
RX packets 1514 bytes 303055 (295.9 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 3401 bytes 204716 (199.9 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
br0:0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.99.0.9 netmask 255.255.0.0 broadcast 10.99.255.255
ether 5c:85:7e:a0:aa:b9 txqueuelen 1000 (Ethernet)
eth1: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
ether ee:32:17:2d:d8:c3 txqueuelen 1000 (Ethernet)
RX packets 2 bytes 636 (636.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 7 bytes 1130 (1.1 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lan: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet6 fe80::5e85:7eff:fea0:aab9 prefixlen 64 scopeid 0x20<link>
ether 5c:85:7e:a0:aa:b9 txqueuelen 1000 (Ethernet)
RX packets 2097 bytes 303934 (296.8 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 2528 bytes 123534 (120.6 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
device interrupt 39
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 5596 bytes 474120 (463.0 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 5596 bytes 474120 (463.0 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
tap0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet6 fe80::9888:2cff:feef:9a88 prefixlen 64 scopeid 0x20<link>
ether 9a:88:2c:ef:9a:88 txqueuelen 100 (Ethernet)
RX packets 3218 bytes 356161 (347.8 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 1720 bytes 78406 (76.5 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
wan: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.16.67.164 netmask 255.255.255.0 broadcast 172.16.67.255
ether 5c:85:7e:a0:aa:ba txqueuelen 1000 (Ethernet)
RX packets 17714 bytes 1909382 (1.8 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 5665 bytes 3572406 (3.4 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
device interrupt 52
RK2表项
RK2使用5G上网,表项为:
root@jenet:~# ifconfig
br0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.0.1 netmask 255.255.255.0 broadcast 192.168.0.255
inet6 fe80::5e85:7eff:fe03:1866 prefixlen 64 scopeid 0x20<link>
inet6 fe80::4a43 prefixlen 128 scopeid 0x20<link>
ether 5c:85:7e:03:18:66 txqueuelen 1000 (Ethernet)
RX packets 3246 bytes 459630 (448.8 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 28 bytes 2707 (2.6 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
br0:0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.99.0.2 netmask 255.255.0.0 broadcast 10.99.255.255
ether 5c:85:7e:03:18:66 txqueuelen 1000 (Ethernet)
eth1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.12.94.121 netmask 255.255.255.0 broadcast 10.12.94.255
inet6 2408:8441:810:2b25:43f:aff:fe0a:21c8 prefixlen 64 scopeid 0x0<global>
ether 06:3f:0a:0a:21:c8 txqueuelen 1000 (Ethernet)
RX packets 2780 bytes 1757658 (1.6 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 1985 bytes 264222 (258.0 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lan: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet6 fe80::5e85:7eff:fe03:1866 prefixlen 64 scopeid 0x20<link>
ether 5c:85:7e:03:18:66 txqueuelen 1000 (Ethernet)
RX packets 2467 bytes 161356 (157.5 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 2693 bytes 482909 (471.5 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
device interrupt 39
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 1264 bytes 152711 (149.1 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 1264 bytes 152711 (149.1 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
tap0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet6 fe80::f0d0:31ff:fea5:7a82 prefixlen 64 scopeid 0x20<link>
ether f2:d0:31:a5:7a:82 txqueuelen 100 (Ethernet)
RX packets 2668 bytes 481922 (470.6 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 1904 bytes 128361 (125.3 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
wan: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
ether 5c:85:7e:03:18:67 txqueuelen 1000 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
device interrupt 52
root@jenet:~#
RK3表项
RK3使用WAN口上网(172.16.67.162),表项为:
接口MAC为:
root@jenet:~# ifconfig
br0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.0.1 netmask 255.255.255.0 broadcast 192.168.0.255
inet6 fe80::4a43 prefixlen 128 scopeid 0x20<link>
inet6 fe80::188d:5fff:feb5:8d09 prefixlen 64 scopeid 0x20<link>
ether 1a:8d:5f:b5:8d:09 txqueuelen 1000 (Ethernet)
RX packets 1706 bytes 293831 (286.9 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 563 bytes 48032 (46.9 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
br0:0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.99.0.5 netmask 255.255.0.0 broadcast 10.99.255.255
ether 1a:8d:5f:b5:8d:09 txqueuelen 1000 (Ethernet)
lan: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet6 fe80::188d:5fff:feb5:8d09 prefixlen 64 scopeid 0x20<link>
ether 1a:8d:5f:b5:8d:09 txqueuelen 1000 (Ethernet)
RX packets 1773 bytes 329602 (321.8 KiB)
RX errors 0 dropped 4 overruns 0 frame 0
TX packets 1857 bytes 130455 (127.3 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
device interrupt 39
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 834 bytes 50500 (49.3 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 834 bytes 50500 (49.3 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
tap0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet6 fe80::3418:1eff:fec4:84ea prefixlen 64 scopeid 0x20<link>
ether 36:18:1e:c4:84:ea txqueuelen 100 (Ethernet)
RX packets 950 bytes 64213 (62.7 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 1442 bytes 274346 (267.9 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
wan: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.16.67.162 netmask 255.255.255.0 broadcast 172.16.67.255
ether 1a:8d:5f:b5:8d:09 txqueuelen 1000 (Ethernet)
RX packets 5380 bytes 503835 (492.0 KiB)
RX errors 0 dropped 3 overruns 0 frame 0
TX packets 2714 bytes 3365557 (3.2 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
device interrupt 52
将RK2和RK3连接
RK2的tap0口被block住,环路探测有效。
STP的hairpin模式
root@jenet:~# brctl --help
Usage: brctl [commands]
commands:
addbr <bridge> add bridge
delbr <bridge> delete bridge
addif <bridge> <device> add interface to bridge
delif <bridge> <device> delete interface from bridge
hairpin <bridge> <port> {on|off} turn hairpin on/off
setageing <bridge> <time> set ageing time
int br_set_hairpin_mode(const char *bridge, const char *port, int hairpin_mode)
{
return port_set(bridge, port, "hairpin_mode", hairpin_mode, 0);
}
最终使写在了如下地方:
搜索代码,并没有地方判断此标志位: