概述
如图,这里就不对每个处理函数就行讲解了。
上送网络层进行处理
static void br_pass_frame_up(struct net_bridge *br, struct sk_buff *skb)
{
struct net_device *indev, *brdev = br->dev;
skb->dev = brdev; //把报文的接收dev修改为bridge dev
NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, indev, NULL,
netif_receive_skb);
}
泛洪发送
static void br_flood(struct net_bridge *br, struct sk_buff *skb,
void (*__packet_hook)(const struct net_bridge_port *p,
struct sk_buff *skb))
{
struct net_bridge_port *p;
struct net_bridge_port *prev;
prev = NULL;
/*遍历bridge下加入的二层端口,从每个二层端口发送一份出去*/
list_for_each_entry_rcu(p, &br->port_list, list)
{
if (should_deliver(p, skb))
{
if (prev != NULL)
{
struct sk_buff *skb2;
/*把报文拷贝一份后从二层端口发送出去*/
if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL)
{
br->dev->stats.tx_dropped++;
kfree_skb(skb);
return;
}
__packet_hook(prev, skb2);
}
prev = p;
}
}
if (prev != NULL) {
__packet_hook(prev, skb);
return;
}
kfree_skb(skb);
}
六、MAC地址的学习
bridge每收到一个报文,就会根据报文的源MAC来更新FDB表项。
int 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;
struct sk_buff *skb2;
br = p->br;
br_fdb_update(br, p, eth_hdr(skb)->h_source);
}
void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source,
const unsigned char *addr)
{
struct hlist_head *head = &br->hash[br_mac_hash(addr)];
struct net_bridge_fdb_entry *fdb;
fdb = fdb_find(head, addr);
/*如果FDB表项已经存在,则更新*/
if (likely(fdb))
{
/* attempt to update an entry for a local interface */
/*如果是本机FDB,表示接收错误*/
if (unlikely(fdb->is_local))
{
if (net_ratelimit())
printk(KERN_WARNING "%s: received packet with "
"own address as source addressn",
source->dev->name);
}
else{/*更新FDB表项,同时更新FDB的老化时间戳*/
fdb->dst = source;
fdb->ageing_timer = jiffies;
}
}
/*如果FDB表项不存在,就新建一个FDB*/else{spin_lock(&br->hash_lock);
if (!fdb_find(head, addr))
fdb_create(head, source, addr, 0);
spin_unlock(&br->hash_lock);
}
}
七、MAC地址的老化
每次FDB表项被命中更新时,会更新FDB表项的老化时间戳。Bridge起了一个定时器,来定期的清理长时间不用的FDB表项。
初始化定时器
void br_stp_timer_init(struct net_bridge *br)
{
。。。。。。
setup_timer(&br->gc_timer, br_fdb_cleanup, (unsigned long) br);
}
void br_fdb_cleanup(unsigned long _data)
{
struct net_bridge *br = (struct net_bridge *)_data;
unsigned long delay = hold_time(br);
unsigned long next_timer = jiffies + br->forward_delay;
int i;
/*加锁进行保护*/
spin_lock_bh(&br->hash_lock);
/*遍历FDB hash表中的每一项,判断FDB表项是否过期,如果过期,就删除*/
for (i = 0; i
{
struct net_bridge_fdb_entry *f;
struct hlist_node *h, *n;
hlist_for_each_entry_safe(f, h, n, &br->hash[i], hlist)
{
unsigned long this_timer;
/*跳过静态的FDB表项*/
if (f->is_static)
continue;
this_timer = f->ageing_timer + delay;
/*如果FDB表项过期,就删除该FDB表项*/
if (time_before_eq(this_timer, jiffies))
fdb_delete(f);
else if (time_before(this_timer, next_timer))
next_timer = this_timer;
}
}
spin_unlock_bh(&br->hash_lock);
/*遍历完后重新设置老化定时器*/
mod_timer(&br->gc_timer, round_jiffies(next_timer + HZ/4));
}
最后
以上就是受伤板凳为你收集整理的linux通过端口发送,三、Linux上桥的实现的全部内容,希望文章能够帮你解决linux通过端口发送,三、Linux上桥的实现所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复