




已阅读5页,还剩26页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
目录生成树2摘要2原理2选举根桥3生成树端口状态6收敛7数据结构7算法实现16实现代码17C+代码17Linux中源码23总结30生成树摘要在交换中,通常会设多个交换设备,并在交换设备之间建立多个连接来提供链路的冗余性,但是这有可能是网络中产生环路。为了解决这个问题,在提供冗余的同时,我们可以使用生成树协议来防止产生网络环路。生成树协议最早是由DEC公司开发的,后来,IEEE开发了自己的STP版本,称为802.1D,有兴趣的可自行查阅资料。STP的主要任务是阻止在第二层网络上产生网络环路。它监视着网络中的所有链路,通过关闭一些冗余的接口来确保在网络中不会产生环路。STP采用生成树算法,它首先创建一个拓扑数据库,然后搜索并破坏掉冗余的链路。运行了STP算法之后,帧就只能被转发到保险的有STP挑选出来的链路上。原理在介绍生成树原理之前,首先要来介绍一些专业术语:BPDU:BPDU就是桥协议数据单元,所有的交换设备相互之间都交换信息,并利用这些信息来选出根交换设备,也根据这些信息来进行网络的后续配置。每台交换设备都对桥协议数据单元中的参数进行比较,它们将BPDU传送给某个邻居,并在其中放入他们从其他邻居那里收到的BPDU。根桥:根桥是ID最低的网桥,对于STP来说,关键的问题是为网络中所有的交换机推选出一个根桥,并让根桥成为网络中的焦点。在网络中,所有其他的决定,如哪一个端口要被阻塞,哪个端口要被置为转发状态都是根据根桥的判断来做出的。桥ID:SPT利用桥ID来跟踪网络中的所有交换机。桥ID是由桥优先级和MAC地址的组合来决定的。在网络中,桥ID最小的网桥为根桥。非根桥:出了根桥外,其它所有网桥都是非根桥。他们相互之间都交换BPDU,并在所有交换机上更新STP拓扑数据库,以防止环路并对链路失效采取补救措施。端口开销:当两台交换机之间有多条链路且都不是根端口时,就根据端口开销来决定最佳路径,链路的开销取决于链路的带宽。根端口:根端口是指直接连接到根桥的链路所在的端口,或者到根桥的路径最短的端口。如果有多条链路连接到根桥,就通过检查每条链路的带宽来决定端口的开销,开销最低的端口就成为根端口。如果多条链路的开销相同,就使用桥ID效益一些的那个桥的端口。如果多条链路来自同一台设备,就使用端口号最低的那条链路。非指定端口:非指定端口指开销比指定端口高的端口,非指定端口将被置为阻塞状态,它不能转发数据。转发端口:指能够转发帧的端口。阻塞端口:阻塞端口是指不能转发帧的端口,这样做是为了防止产生环路。然而,被阻塞的端口将始终监听帧。正如上文提到的,STP的任务是找到网络中的所有链路,并关闭较次的冗余链路,这样就可以防止网络环路的产生。为了达到这个目的,STP首先要选举一个根桥,由根桥来负责决定网络拓扑。一旦所有的交换机都同意将某台交换机选举为根桥,其余的每台交换机就必须找到其唯一的根端口。在两台交换机之间的每一条链路必须有唯一的指定端口在那条链路上的端口提供到根桥最大的带宽。一个网桥到达根桥可能通过许多其他网桥,即它不总是最短的路径,但它是将被使用的最快(最大带宽)的路径,总之也就是路径开销最低的路径。显然,在根交换机上 每个端口都是指定端口,因为根桥离自己总是最近的。在执行STP算法之后,任何既不是根端口也不是指定端口的端口都将被置为阻塞状态,这样就打破了交换环路。选举根桥在网络中,桥ID用来选举根桥,并决定根端口。桥ID为8个字节长,其中包含了设备的优先级和MAC地址,在运行IEEE STP版本的所有设备上,默认时的优先级都为32768。决定根桥时,需要将桥的优先级和MAC地址结合起来。如果两台交换机或网桥碰巧有同样的优先级值,那么就比较他们的MAC地址,MAC地址最小的设备就是最低的桥ID。默认时,每2秒发送一次BPDU,它被发送到网桥/交换机的所有活动端口上。可以改变桥的ID,以使它自动成为根桥。在大的交换式网络中,能够做到这一点非常重要,它保证了能够选出最佳路径,在这里,需要考虑效率。图1 选举根桥举例如图1,Fa0/2端口为橙色,也就是处于阻塞状态,从图中可看出,SwitchA和S优先级默认值都为32768(思科交换机中优先级为优先级加VLAN号),而Switch A的MAC地址显然大于B的,因此Switch B为根桥,由于端口号Fa0/2的端口号大于Fa0/1所以Fa0/2被置为阻塞端口。图2 Switch A生成树状态本例以思科2960-24TT交换机为例,图2为Switch A的生成树状态,上图显示了根ID和桥ID的信息,由于仅有Fa0/1处于转发状态,所以根ID上只显示了Fa0/1。下面带虚线部分Role字段显示该端口扮演什么样的角色,Fa0/2为阻塞端口Fa0/1为根端口;Sts字段为端口当前状态,上图显示Fa0/2状态为BLK,也就是阻塞状态,Fa0/1状态为FWD,即转发状态;Cost字段为路径开销,本例都为19,也就是说链路带宽为100Mbit/s,关于路径开销计算读者可上网自行查阅资料,在这里不做过多讨论。图3 Switch B生成树状态图将图3和图2对比可以看出,在Root ID字段中,Switch B中的port部分直接显示出该交换机为根桥。而它的所有端口都为指定端口,且都处于转发状态。为了便于管理,在搭建网络时,我们会指定某一台交换机为根桥,从而使交换设备能够分层次管理,这时候我们可以通过改变交换机的优先级来使之成为根桥,也可以通过同样的方法使某个端口成为根端口。图4 将Switch A优先级改变后的暂时状态上图为将Switch A优先级改为4096后的暂时状态,这时,在Switch B上原本处于转发状态的Fa0/2端口现在处于阻塞状态,这说明STP协议正在起效,BPDU正在更新端口信息。图5 将Switch A优先级改变一段时间后图5为将Switch A优先级改变一段时间以后,所有端口的信息通过BPDU得到当前交换机最新状态,由于Switch A的优先级值的下降,Switch A成为了新的根桥。由此可见,我们可以通过人为改变优先级来管理交换机的生成树状态,从而更好的管理网络。图6 Switch A改变优先级后的生成树状态从图6可以看出,这时的Switch A由于优先级低于Switch B的优先级而成为了新的根桥,而它的所有端口成为了指定端口,且状态都为转发状态。图7 BPDU帧格式图7为通过Cisco Packet Tracer模拟器抓取的BPDU包。生成树端口状态对于运行STP的网桥或交换机来说,其端口状态会在以下五种状态之间转变:阻塞:被阻塞的端口不能转发帧,它只监听BPDU。设置阻塞状态的目的是防止使用有环路的路径。当交换机加电时,默认情况下所有的端口都处于阻塞状态。侦听:所有好的端口都侦听BPDU,以确信在传送数据帧之前在网络上没有环路的产生。处在侦听状态的端口,在没有形成MAC地址表时,就准备转发数据帧。学习:交换机端口侦听BPDU,并学习交换式网络中的所有路径。处在学习状态的端口形成了MAC地址表,但不能转发数据帧。转发延迟意味着将端口从侦听状态转换到学习状态所花费的时间,默认时设置为15秒。转发:在桥接的端口上,处在转发状态的端口发送并接收所有的数据帧。如果在学习状态结束时,端口仍然是指定端口或根端口,它就进入转发状态。禁用:从管理上讲,处于禁用状态的端口是不能参与帧的转发或形成STP。处于禁用状态下,端口实质上是不工作的。大多数情况下,交换机端口都处于阻塞或者转发状态。转发端口是指到根桥的开销最低的端口,但如果网络的拓扑改变了,交换机上的端口就会处于侦听或者学习状态。只有在学习状态或转发状态下,交换机才能填写MAC地址表。正如上文所述,阻塞端口是一种防止网络环路的策略。一旦交换机决定了到根桥的最佳路径,那么所有其他的端口将处于阻塞状态。被阻塞的端口仍然能接收BPDU,它们只是不能发送任何帧。如果由于网络拓扑的改变,交换机决定让一个被阻塞的端口现在成为指定端口或桥端口,它将转到侦听状态(如图4),并检查它收到的所有BPDU,以确信一旦他变为转发状态,将不会引起网络环路的出现。收敛当网桥或交换机上的所有端口都转变到转发或阻塞状态时,就产生了收敛。在收敛完成之前,交换机不能转发任何数据。在重新转发数据之前,所有的设备都必须更新。因此,如果想让网络中的用户能够继续发送数据,就必须保证交换式网络的实际设计确实很好,以便STP能够快速收敛。收敛是重要的,它用来确保所有的设备都有同样的数据库,但它确实会花一些时间。从阻塞状态转变到转发状态通常要花50秒。通过创建层次化的交换机实际设计,就可以让核心交换机成为STP的根桥,以便让STP收敛的又好又快。在交换机端口上,生成树拓扑从阻塞到转发的典型收敛时间为50秒,在服务器或主机上,这会引起超时。要解决这个问题,可以使用快速端口在某个端口上禁用生成树。数据结构STP的几个状态: Block:阻断状态,接收但不转发数据。 Listening:侦听状态,不转发数据,可以收发BPDU,执行选举root bridge,root port,designate port等动作。 Learning:学习状态,不转发数据,开始学习MAC,为数据转发作准备,所以称之为Learning状态 Forward:转发状态,转发数据。 Disable:禁用状态,既不参与STP计算,也不转发数据。 一. 首先是Bridge注册过程: static int _init br_init(void) br_fdb_init(); #ifdef CONFIG_BRIDGE_NETFILTER if (br_netfilter_init() return 1; #endif brioctl_set(br_ioctl_deviceless_stub); /* 数据包的处理函数注册为br_handle_frame */ br_handle_frame_hook = br_handle_frame;br_fdb_get_hook =br_fdb_get;br_fdb_put_hook= br_fdb_put;register_netdevice_notifier(&br_device_notifier); return 0; 二. 网桥处理函数 int br_handle_frame(struct net_bridge_port *p, struct sk_buff *pskb) struct sk_buff *skb = *pskb; const unsigned char*dest=eth_hdr(skb)-h_dest;if (p-state = BR_STATE_DISABLED) goto err; if (!is_valid_ether_addr(eth_hdr(skb)-h_source) goto err; /* 网桥打开了STP功能, 是否为网桥组播地址,PS:bridge_ula定义为 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 ,只比较前5个字段, 为什么第5个字段要和0XF0比较,就不知道了 (01-80-c2-00-00-F0 ?) */if (p-br-stp_enabled & !memcmp(dest, bridge_ula, 5) & !(dest5 & 0xF0) if (!dest5) /* 涉及到STP功能的数据包都交给函数br_stp_handle_bpdu来处理 */NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, skb-dev, NULL, br_stp_handle_bpdu);return 1; goto err; /* 如果端口处于Learning或Forwarding状态时,要记录从端口通过的数据包的源MAC地址,以update CAM表 */if (p-state = BR_STATE_FORWARDING | p-state = BR_STATE_LEARNING) if (br_should_route_hook) if (br_should_route_hook(pskb) return 0;skb = *pskb;dest = eth_hdr(skb)-h_dest; if (!compare_ether_addr(p-br-dev-dev_addr, dest) skb-pkt_type = PACKET_HOST; /* 在br_handle_frame中更新CAM表 */ NF_HOOK(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb-dev, NULL, br_handle_frame_finish); return 1; err: kfree_skb(skb);return 1; 三. 接下来我们首先分析更新CAM表的函数br_handle_frame_finish,在第4小节再分析STP的处理函数br_stp_handle_bpduint br_handle_frame_finish(struct sk_buff *skb) const unsigned char *dest = eth_hdr(skb)-h_dest;struct net_bridge_port *p = rcu_dereference(skb-dev-br_port);struct net_bridge *br;struct net_bridge_fdb_entry *dst; int passedup = 0; if (!p | p-state = BR_STATE_DISABLED) goto drop; /* insert into forwarding database after filtering to avoid spoofing 使用数据包的源MAC地址来更新CAM表 */ br = p-br; br_fdb_update(br, p, eth_hdr(skb)-h_source); if (p-state = BR_STATE_LEARNING) goto drop; /* 如果网桥的虚拟网卡处于混杂模式,那么每个接收到的数据包都需要克隆一份送到AF_PACKET协议处理 */if (br-dev-flags & IFF_PROMISC) struct sk_buff *skb2;skb2 = skb_clone(skb, GFP_ATOMIC); if (skb2 != NULL) passedup = 1; br_pass_frame_up(br, skb2); /* 目的MAC为广播或多播,则需要向本机的上层协议栈传送这个数据包,这里有一个标志变量passedup用于表示是否传送过了,如果已传送过,那就算了 */ if (is_multicast_ether_addr(dest) br_flood_forward(br, skb, !passedup);if (!passedup) br_pass_frame_up(br, skb); goto out; dst = _br_fdb_get(br, dest); if (dst != NULL & dst-is_local) if (!passedup) br_pass_frame_up(br, skb); else kfree_skb(skb); goto out; if (dst != NULL) br_forward(dst-dst, skb); goto out; /* CAM表中没有,只能flood了。 */ br_flood_forward(br, skb, 0); out: return 0; drop: kfree_skb(skb); goto out; 四. 在介绍br_stp_handle_bpdu这个函数之前,我们首先来看一下内核中用来表示一个BPDU的数据结构是什么 br_config_bpdu struct br_config_bpdu unsigned topology_change:1; /* 拓扑改变标志 */unsigned topology_change_ack:1; /* 拓扑改变回应标志 */ bridge_id root; /* 根ID,用于会聚后的网桥网络中,所有配置 BPDU 中的该字段都应该具有相同值(同VLAN),又可分为两个 BID 子字段:网桥优先级和网桥 MAC 地址 */ int root_path_cost; /* 路径开销,通向有根网桥(Root Bridge)的所有链路的积累资本 */ bridge_id bridge_id; /* 创建当前 BPDU 的网桥 BID */ port_id port_id; /* 端口ID,每个端口值都是唯一的 */ int message_age; /* 记录 Root Bridge 生成当前 BPDU 起源信息的所消耗时间 */ int max_age; /* 保存 BPDU 的最长时间,也反映了拓朴变化通知(Topology Change Notification)过程中的网桥表生存时间情况 */ int hello_time; /* 周期性配置 BPDU 间的时间 */ int forward_delay; /* 用于在 Listening 和 Learning 状态的时间,也反映了拓朴变化通知(Topology Change Notification)过程中的时间情况 */ ; 五. BPDU处理函数br_stp_handle_bpdu int br_stp_handle_bpdu(struct sk_buff *skb) struct net_bridge_port *p = rcu_dereference(skb-dev-br_port);struct net_bridge *br; unsigned char *buf; if (!p) goto err; br = p-br; spin_lock(&br-lock); if (p-state = BR_STATE_DISABLED | !(br-dev-flags & IFF_UP) goto out; /* insert into forwarding database after filtering to avoid spoofing 根据BPDU中的MAC地址来更新CAM表 */ br_fdb_update(br, p, eth_hdr(skb)-h_source); if (!br-stp_enabled) goto out; /* need at least the 802 and STP headers */ if (!pskb_may_pull(skb, sizeof(header)+1) | memcmp(skb-data, header, sizeof(header) goto out; buf = skb_pull(skb, sizeof(header); if (buf0 = BPDU_TYPE_CONFIG) struct br_config_bpdu bpdu;if (!pskb_may_pull(skb, 32) goto out; /* 802.3数据包格式: 目的地址 | 源地址 | 长度 | DSAP | SSAP | cntl | org_code | 类型 | 数据 | CRC 6 6 2 1 1 1 3 2 381492 4 */ buf = skb-data; / 跳过了数据字段的6个字节,buf指向了类型字段 /* STP的数据包不是以太网格式的,而是802.3格式的, */ bpdu.topology_change = (buf1 & 0x01) ? 1 : 0; bpdu.topology_change_ack = (buf1 & 0x80) ? 1 : 0; bpdu.root.prio0 = buf2; bpdu.root.prio1 = buf3; bpdu.root.addr0 = buf4; bpdu.root.addr1 = buf5; bpdu.root.addr2 = buf6; bpdu.root.addr3 = buf7; bpdu.root.addr4 = buf8; bpdu.root.addr5 = buf9; bpdu.root_path_cost = (buf10 24) | (buf11 16) | (buf12 8) | buf13; bpdu.bridge_id.prio0 = buf14;bpdu.bridge_id.prio1 = buf15;bpdu.bridge_id.addr0 = buf16; bpdu.bridge_id.addr1 = buf17; bpdu.bridge_id.addr2 = buf18; bpdu.bridge_id.addr3 = buf19; bpdu.bridge_id.addr4 = buf20; bpdu.bridge_id.addr5 = buf21; bpdu.port_id = (buf22 lock); err: kfree_skb(skb); return 0; 六. 在处理BPDU之前,我们先来看一下net_bridge和net_bridge_port这两个数据结构,这两个是很重要的数据结构,如果不理解这两个结构,后面的分析就很难进行了。 struct net_bridge spinlock_t lock; struct list_head port_list; struct net_device *dev; struct net_device_stats statistics; spinlock_t hash_lock; struct hlist_head hashBR_HASH_SIZE; struct list_head age_list; unsigned long feature_mask; /* STP */ bridge_id designated_root; /网络中根桥的ID bridge_id bridge_id; /网桥本身的ID u32 root_path_cost; unsigned long max_age; unsigned long hello_time; unsigned long forward_delay; unsigned long bridge_max_age; unsigned long ageing_time; unsigned long bridge_hello_time; unsigned long bridge_forward_delay; u16 root_port; unsigned char stp_enabled; unsigned char topology_change; unsigned char topology_change_detected; struct timer_list hello_timer; struct timer_list tcn_timer; struct timer_list topology_change_timer; struct timer_list gc_timer; struct kobject ifobj; struct net_bridge_port struct net_bridge *br; struct net_device *dev; struct list_head list; /* STP */ u8 priority; u8 state; u16 port_no; unsigned char topology_change_ack; unsigned char config_pending; port_id port_id; /端口的ID,在从端口发出的BPDU中,会将这个端口的ID存入BPDU中 port_id designated_port; bridge_id designated_root; bridge_id designated_bridge; u32 path_cost; u32 designated_cost; struct timer_list forward_delay_timer; struct timer_list hold_timer; struct timer_list message_age_timer; struct kobject kobj; struct work_struct carrier_check; struct rcu_head rcu; ; 七. config_bpdu的处理函数br_received_config_bpdu void br_received_config_bpdu(struct net_bridge_port *p, struct br_config_bpdu *bpdu) struct net_bridge *br; int was_root; br = p-br; was_root = br_is_root_bridge(br); if (br_supersedes_port_info(p, bpdu) br_record_config_information(p, bpdu); br_configuration_update(br); br_port_state_selection(br); if (!br_is_root_bridge(br) & was_root) del_timer(&br-hello_timer); if (br-topology_change_detected) del_timer(&br-topology_change_timer); br_transmit_tcn(br); mod_timer(&br-tcn_timer, jiffies + br-bridge_hello_time); if (p-port_no = br-root_port) br_record_config_timeout_values(br, bpdu); br_config_bpdu_generation(br); if (bpdu-topology_change_ack) br_topology_change_acknowledged(br); else if (br_is_designated_port(p) br_reply(p); 八. br_supersedes_port_info(p, bpdu) 这个函数,就是把包中的值,同先前指定的对应值进行判断和比较,经确定是否需要更新 /* called under bridge lock */ /* 如果要更新则返回1,不然返回0 */ static int br_supersedes_port_info(struct net_bridge_port *p, struct br_config_bpdu *bpdu) int t; /* 收到的BPDU的root ID和当前交换机端口上记录的root ID进行比较 */ t = memcmp(&bpdu-root, &p-designated_root, 8); if (t 0) return 0; /* 若相等,则往下 */ if (bpdu-root_path_cost designated_cost) return 1; else if (bpdu-root_path_cost p-designated_cost) return 0; t = memcmp(&bpdu-bridge_id, &p-designated_bridge, 8); if (t 0) return 0; if (memcmp(&bpdu-bridge_id, &p-br-bridge_id, 8) return 1; if (bpdu-port_id designated_port) return 1;return 0; 算法实现br_stp_rcv()函数在br_stp_bpdu.c中操作生成树配置上的更新。这个函数分析BPDU并建立一个BPDU的br_config_bpdu数据结构。数据结构和端口信息将被传递到br_stp.c中的br_received_config_bpdu()函数。这个函数首先调用br_record_config_information()来登记端口上的BPDU信息,然后调用br_configuration_update()更新网桥配置。代码如下:struct br_config_bpduunsigned topology_change:1;unsigned topology_change_ack:1;bridge_id root;int root_path_cost;bridge_id bridge_id;port_id port_id;int message_age;int max_age;int hello_time;int forward_delay;配置信息更新后,端口状态也根据端口指定的角色会在br_port_state_selection()中更新。例如,一个端口为避免回路进入阻塞状态。注:br_configuration_update()可被多处调用。例如,系统管理者可以执行命令去废除一个端口或者更改路径开销。这种情况也会引发网桥配置更新。br_configuration_update()仅仅调用两个函数br_root_selection()和br_designated_port_selection()来分别用于选择一个新的根和决定指定端口。如果根或者指定端口改变后,同样会更新路径开销。实现代码C+代码/* *Spanning tree protocol; BPDU handling *Linux ethernet bridge * *Authors: *Lennert Buytenhek * *This program is free software; you can redistribute it and/or *modify it under the terms of the GNU General Public License *as published by the Free Software Foundation; either version *2 of the License, or (at your option) any later version. */#include #include #include #include #include #include #include #include #include #include #include br_private.h#include br_private_stp.h#define STP_HZ256#define LLC_RESERVE sizeof(struct llc_pdu_un)static void br_send_bpdu(struct net_bridge_port *p, const unsigned char *data, int length)struct sk_buff *skb;skb = dev_alloc_skb(length+LLC_RESERVE);if (!skb)return;skb-dev = p-dev;skb-protocol = htons(ETH_P_802_2);skb_reserve(skb, LLC_RESERVE);memcpy(_skb_put(skb, length), data, length);llc_pdu_header_init(skb, LLC_PDU_TYPE_U, LLC_SAP_BSPAN, LLC_SAP_BSPAN, LLC_PDU_CMD);llc_pdu_init_as_ui_cmd(skb);llc_mac_hdr_init(skb, p-dev-dev_addr, p-br-group_addr);skb_reset_mac_header(skb);NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb-dev,dev_queue_xmit);static inline void br_set_ticks(unsigned char *dest, int j)unsigned long ticks = (STP_HZ * j)/ HZ;put_unaligned_be16(ticks, dest);static inline int br_get_ticks(const unsigned char *src)unsigned long ticks = get_unaligned_be16(src);return DIV_ROUND_UP(ticks * HZ, STP_HZ);/* called under bridge lock */void br_send_config_bpdu(struct net_bridge_port *p, struct br_config_bpdu *bpdu)unsigned char buf35;if (p-br-stp_enabled != BR_KERNEL_STP)return;buf0 = 0;buf1 = 0;buf2 = 0;buf3 = BPDU_TYPE_CONFIG;buf4 = (bpdu-topology_change ? 0x01 : 0) |(bpdu-topology_change_ack ? 0x80 : 0);buf5 = bpdu-root.prio0;buf6 = bpdu-root.prio1;buf7 = bpdu-root.addr0;buf8 = bpdu-root.addr1;buf9 = bpdu-root.addr2;buf10 = bpdu-root.addr3;buf11 = bpdu-root.addr4;buf12 = bpdu-root.addr5;buf13 = (bpdu-root_path_cost 24) & 0xFF;buf14 = (bpdu-root_path_cost 16) & 0xFF;buf15 = (bpdu-root_path_cost 8) & 0xFF;buf16 = bpdu-root_path_cost & 0xFF;buf17 = bpdu-bridge_id.prio0;buf18 = bpdu-bridge_id.prio1;buf19 = bpdu-bridge_id.addr0;buf20 = bpdu-bridge_id.addr1;buf21 = bpdu-bridge_id.addr2;buf22 = bpdu-bridge_id.addr3;buf23 = bpdu-bridge_id.addr4;buf24 = bpdu-bridge_id.addr5;buf25 = (bpdu-port_id 8) & 0xFF;buf26 = bpdu-port_id & 0xFF;br_set_ticks(buf+27, bpdu-message_age);br_set_ticks(buf+29, bpdu-max_age);br_set_ticks(buf+31, bpdu-hello_time);br_set_ticks(buf+33, bpdu-forward_delay);br_send_bpdu(p, buf, 35);/* called under bridge lock */void br_send_tcn_bpdu(struct net_bridge_port *p)unsigned char buf4;if (p-br-stp_enabled != BR_KERNEL_STP)return;buf0 = 0;buf1 = 0;buf2 = 0;buf3 = BPDU_TYPE_TCN;br_send_bpdu(p, buf, 4);/* * Called from llc. * * NO locks, but rcu_read_lock */void br_stp_rcv(const struct stp_proto *proto, struct sk_buff *skb,struct net_device *dev)const unsigned char *dest = eth_hdr(skb)-h_dest;struct net_bridge_port *p;struct net_bridge *br;const unsigned char *buf;if (!br_port_exists(dev)goto err;p = br_port_ge
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 新解读《CB-T 532 - 1999船用通风管路放水塞》新解读
- Brand KPIs for health insurance:ICICI Lombard in India-英文培训课件2025.4
- 基于注意力机制跨阶段并行残差融合模型的非侵入式负荷辨识
- 汽车传感器与检测技术电子教案:雷达传感器
- 介绍大学活动方案
- 介绍校园文化活动方案
- 介绍美食活动方案
- 从化老人慰问活动方案
- 仓库冬季活动策划方案
- 仙人吹气活动方案
- 年产xxx水泥粉助磨剂项目实施方案(项目申请参考)
- 固体废物清运委托合同
- 2025年高考英语仿真模拟试卷(含答案解析)
- 《道路桥梁养护技术》课件
- 《新能源材料概论》 课件 第3章 化学-电能转换新能源材料
- 2025年中考生物考前必背全册知识点梳理(全国)
- 护理文件书写导致的纠纷
- 基于机器学习的糖尿病早期诊断模型及可解释分析
- 路面硬化施工方案
- 学前教育安全标志课件
- 环境污染和生态破坏事故应急预案样本(2篇)
评论
0/150
提交评论