RSTP和STP

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端口选为根端口。

  1. 如果交换机的各个接口接收到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);
}

最终使写在了如下地方:

搜索代码,并没有地方判断此标志位:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/803004.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

数据分析案例-2024 年热门动漫数据集可视化分析

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

黑马点评-Postman卡住sending Requst原因解决

不知道为什么&#xff0c;用这个c1e1d5的token就会一直卡死&#xff0c;但是换了一个token就解决了&#xff0c;目前不知道为什么 解决了&#xff0c;原来是这个请求下面的函数发生了死循环&#xff01;&#xff01;太瓜皮了我超&#xff01; 把num写成了count&#xff0c;导…

7月18日Workshop新加坡专场:在Sui上创建您自己的token

您是base在新加坡&#x1f1f8;&#x1f1ec;的开发者吗&#xff1f; 您是否觉得编程课程枯燥乏味&#xff1f;&#x1f914; 那么&#xff0c;Sui和Metaschool将一起来为您的学习增添乐趣&#xff01; 欢迎加入我们特别为Web3初学者、开发者设组织的“在Sui上创建您自己的t…

linux下Jenkins的安装部署

前言&#xff1a; 用docker安装Jenkins非常方便快捷&#xff0c;但是最近国内的docker镜像源都不好用了&#xff0c;这里回顾一下最原始的Jenkins安装方式 安装前准备 安装环境 Jenkins的运行依赖java环境&#xff0c;linux下jdk的安装参考&#xff1a;linux下JDK的安装-CSD…

2024“狮舞齐鲁”南北狮王争霸赛在临沭开锣

锣鼓声声&#xff0c;狮王争霸。5月2日&#xff0c;临沭县红色朱村旅游区内人头攒动&#xff0c;热闹非凡。备受瞩目的“狮舞齐鲁”南北狮王争霸赛在此开赛&#xff0c;吸引了来自山东省的40支队伍、400余名参赛选手齐聚一堂&#xff0c;共同献上一场精彩绝伦的舞狮盛宴。 此次…

检测机构的配方分析是怎样?

检测机构配方分析是指检测机构通过对样品的化学成分、结构和性质进行分析&#xff0c;以确定其组成和配方的一种服务。检测机构通常提供以下服务&#xff1a; 1. 样品采集与前处理&#xff1a;检测机构通常会指导客户采集具有代表性的样品&#xff0c;并进行必要的前处理&#…

Blender练习,凳面以及凳脚的制作

目录 ​ 1.凳面的制作 2.制作坐垫下面的两条杠 3.制作桌腿 要制作的凳子如图&#xff0c;可以看到&#xff0c;它是一个由长方体&#xff0c;圆柱体等多种几何图形合成的一个立体图形 1.凳面的制作 shifta创建一个正方体 ctrltab打开一个弹窗&#xff0c;选择编辑模式。…

Linux离线安装Mysql5.7

Linux之Mysql安装配置 第一种&#xff1a;Linux离线安装Mysql&#xff08;提前手动下载好tar.gz包&#xff09; 第二种&#xff1a;通过yum安装配置Mysql&#xff08;服务器有网络&#xff09; 之前在阿里云上采用yum安装过一次&#xff08;请看这里&#xff09;&#xff0c;…

区块链资料

Quantstamp - Public Security Assessments smart-contract-sanctuary-bsc/contracts/mainnet at master tintinweb/smart-contract-sanctuary-bsc GitHub https://github.com/slowmist/Cryptocurrency-Security-Audit-Guide/blob/main/README_CN.md sFuzz: 高效自适应的智…

SpringBoot结合ip2region实现博客评论显示IP属地

你好呀&#xff0c;我是小邹。 在现代的Web应用中&#xff0c;特别是博客和论坛类网站&#xff0c;为用户提供地理定位服务&#xff08;如显示用户所在地理位置&#xff09;可以极大地增强用户体验。本文将详细探讨如何使用Java和相关技术栈来实现在博客评论中显示用户的地址信…

大雾弥散动态特效404单页源码

源码介绍 大雾弥散动态特效404单页源码,跟随鼠标反向移动,可以做网站错误页或者丢失页面,将下面的代码放到空白的HTML里面,然后上传到服务器里面,设置好重定向即可 效果预览 完整源码 <!DOCTYPE html> <html><head><meta charset="utf-8&quo…

react自定义校验报错问题修复 ProFormText

1、以下是tsx组件 自定义校验告警导致表单无法提交问题修复 修改如下&#xff1a;

Spring使用外部的属性文件

首先&#xff0c; 我们在Spring里配置一个数据源Datasource&#xff0c;看具体代码&#xff1a; 我们说这样配置数据源&#xff0c;是可以实现&#xff0c; 但是我们不建议讲数据源配置在Spring的配置文件里&#xff0c;因为&#xff0c;这里会配置很多bean&#xff0c;而我们的…

W外链创建抖音私信卡片教程,私信卡片跳转微信工具

W外链地址wai.cn 在数字化时代的浪潮中&#xff0c;私域流量的价值愈发凸显&#xff0c;成为企业获取用户、建立品牌忠诚度、提升转化率的关键手段。抖音&#xff0c;作为当下最热门的短视频社交平台之一&#xff0c;其用户基数庞大、互动性强&#xff0c;为企业私域引流提供了…

爬虫(一)——爬取快手无水印视频

前言 最近对爬虫比较感兴趣&#xff0c;于是浅浅学习了一些关于爬虫的知识。爬虫可以实现很多功能&#xff0c;非常有意思&#xff0c;在这里也分享给大家。由于爬虫能实现的功能太多&#xff0c;而且具体的实现方式也有所不同&#xff0c;所以这里开辟了一个新的系列——爬虫…

FY4B卫星L2级产品掌握和python处理

废话不多说&#xff0c;展示二级产品CTT为例&#xff1a; 抱歉没空了解FY4B产品情况了&#xff0c;直接看代码 # CTT色标配置 bounds_CTT [180, 200, 220, 240, 260, 280, 300, 320] # 根据你的数据设定 colors_CTT [(0, 0, 139/255),(10/255, 0, 245/255),(0, 164/255, 2…

C语言——详解二维数组中元素的地址

在C语言中&#xff0c;二维数组元素的地址认知是一个相对复杂但重要的概念。以下是对二维数组中元素地址认知的详细叙述&#xff1a; 一、二维数组的基本构成 二维数组可以被看作是由多个一维数组组成的数组。例如&#xff0c;定义了一个3行4列的二维数组&#xff0c; int a…

实战分享:利用百数实现通讯录与表单无缝对接,提升管理效率

百数的通讯录实时同步到表单功能&#xff0c;实现了员工信息的即时更新与自动整合&#xff0c;不仅极大地提升了信息管理的效率与准确性&#xff0c;还为企业提供了便捷的数据分析基础&#xff0c;助力企业更高效地运营与决策。 设置方式 在企业管理中&#xff0c;开启通讯录…

深度学习入门——神经网络

前言 神经网络可以帮助自动化设定权重 具体地讲&#xff0c;神经网络的一个重要性质是它可以自动地从数据中学习到合适的权重参数 从感知机到神经网络 神经网络的例子 中间层aka隐藏层 复习感知机 偏置b 并没有被画出来。如果要明确地表示出b&#xff0c;可以像图3-3那样做…

redis基本类型和订阅

redis-cli -h <host> -p <port> -a <password> 其中&#xff0c;< host>是Redis服务器的主机名或IP地址&#xff0c;< port>是Redis服务器的端口号&#xff0c;< password>是Redis服务器的密码&#xff08;如果有的话&#xff09;。 set …