Chinaunix首页 | 论坛 | 博客
  • 博客访问: 7475
  • 博文数量: 13
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 10
  • 用 户 组: 普通用户
  • 注册时间: 2015-09-09 10:59
文章分类
文章存档

2015年(13)

我的朋友
最近访客

分类: 嵌入式

2015-10-09 09:22:49

原文地址:桥多播功能分析 作者:lwchsz

void br_multicast_init(struct net_bridge *br)
{
    br->hash_elasticity = 4;
    br->hash_max = 512;

    br->multicast_router = 1;
    br->multicast_last_member_count = 2;
    br->multicast_startup_query_count = 2;

    br->multicast_last_member_interval = HZ;
    br->multicast_query_response_interval = 10 * HZ;
    br->multicast_startup_query_interval = 125 * HZ / 4;
    br->multicast_query_interval = 125 * HZ;
    br->multicast_querier_interval = 255 * HZ;
    br->multicast_membership_interval = 260 * HZ;

    spin_lock_init(&br->multicast_lock);
    setup_timer(&br->multicast_router_timer,
            br_multicast_local_router_expired, 0);
    setup_timer(&br->multicast_querier_timer,
            br_multicast_local_router_expired, 0);
    setup_timer(&br->multicast_query_timer, br_multicast_query_expired,//创立多播查询定时器
            (unsigned long)br);
}

static void br_multicast_query_expired(unsigned long data)
{
    struct net_bridge *br = (void *)data;

    spin_lock(&br->multicast_lock);
    if (br->multicast_startup_queries_sent <
        br->multicast_startup_query_count)
        br->multicast_startup_queries_sent++;

    br_multicast_send_query(br, NULL, br->multicast_startup_queries_sent);//发送多播查询报文

    spin_unlock(&br->multicast_lock);
}

static void br_multicast_send_query(struct net_bridge *br,
                    struct net_bridge_port *port, u32 sent)
{
    unsigned long time;
    struct br_ip br_group;

    if (!netif_running(br->dev) || br->multicast_disabled ||
        timer_pending(&br->multicast_querier_timer))//如果设备关闭,或者多播禁止或者timer真挂起则返回
        return;

    memset(&br_group.u, 0, sizeof(br_group.u));

    br_group.proto = htons(ETH_P_IP);
    __br_multicast_send_query(br, port, &br_group);

#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
    br_group.proto = htons(ETH_P_IPV6);
    __br_multicast_send_query(br, port, &br_group);
#endif

    time = jiffies;
    time += sent < br->multicast_startup_query_count ?
        br->multicast_startup_query_interval :
        br->multicast_query_interval;
    mod_timer(port ? &port->multicast_query_timer :
             &br->multicast_query_timer, time);
}

static void __br_multicast_send_query(struct net_bridge *br,
                      struct net_bridge_port *port,
                      struct br_ip *ip)
{
    struct sk_buff *skb;

    skb = br_multicast_alloc_query(br, ip);
    if (!skb)
        return;

    if (port) {
        __skb_push(skb, sizeof(struct ethhdr));
        skb->dev = port->dev;
        NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
            dev_queue_xmit);
    } else
        netif_rx(skb);
}

static struct sk_buff *br_multicast_alloc_query(struct net_bridge *br,
                        struct br_ip *addr)
{
    switch (addr->proto) {
    case htons(ETH_P_IP):
        return br_ip4_multicast_alloc_query(br, addr->u.ip4);//ipv4 IGMP查询报文
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
    case htons(ETH_P_IPV6):
        return br_ip6_multicast_alloc_query(br, &addr->u.ip6);//ipv6 MLD查询报文
#endif
    }
    return NULL;
}

流程比较简单,要关闭这个功能可以通过echo "0"> /sys/class/net/br0/bridge/multicast_snooping
命令关闭

阅读(351) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~