ºìÁªLinuxÃÅ»§
Linux°ïÖú

LinuxÖÐÍøÇÅÔ´Âë¿ò¼ÜµÄ³õ²½·ÖÎö

·¢²¼Ê±¼ä:2006-11-29 09:56:39À´Ô´:ºìÁª×÷Õß:Emperor
½ñÌì´¦ÀíÍøÇŵÄSTPµÄÎÊÌâÓöµ½ÁËÂé·³£¬¶ÔÕâ¸ö¶«¶«ÀíÂ۵ĵ¹ÊÇ¿´Á˲»ÉÙ£¬Ã»ÓÐÕæÕæѧϰµ½ËüµÄÔ´Àí£¬À´¿´LinuxµÄʵÏÖ£¬ÊÖͷûÓÐ×ÊÁÏ£¬¿´ÁËÁ½¸öÖÓÍ·£¬Ö»°ÑÍøÇŵĿò¼Ü½á¹¹¿´Í꣬ËùÒÔÏëÏÈÌù³öÀ´£¬Ï£ÍûÓÐÑо¿Õâ¿éµÄ´ó¸çÃÇÌÖÂÛ£¬¼ÌÐø°ÑËüдÍ꣬ºÃºÃѧϰһÏ£º

°æ±¾£ºLinux 2.4.18

Ò»¡¢µ÷ÓÃ

ÔÚsrc/net/core/dev.cµÄÈíÖжϺ¯Êýstatic void net_rx_action(struct softirq_action *h)ÖУº

ÒýÓÃ:
line 1479

#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
if (skb->dev->br_port != NULL &&
br_handle_frame_hook != NULL) {
handle_bridge(skb, pt_prev);
dev_put(rx_dev);
continue;
}
#endif


Èç¹û¶¨ÒåÁËÍøÇÅ»òÍøÇÅÄ£¿é£¬ÔòÓÉhandle_bridgeº¯Êý´¦Àískb->dev->br_port £º½ÓÊÕ¸ÃÊý¾Ý°üµÄ¶Ë¿ÚÊÇÍøÇŶ˿Ú×éµÄÒ»Ô±br_handle_frame_hook £º¶¨ÒåÁËÍøÇÅ´¦Àíº¯Êý¡£

¶þ¡¢³õʼ»¯

ÒýÓÃ:
src/net/bridge/br.c£º
static int __init br_init(void)
{
printk(KERN_INFO "NET4: Ethernet Bridge 008 for NET4.0\n";

br_handle_frame_hook = br_handle_frame;
br_ioctl_hook = br_ioctl_deviceless_stub;
#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
br_fdb_get_hook = br_fdb_get;
br_fdb_put_hook = br_fdb_put;
#endif
register_netdevice_notifier(&br_device_notifier);

return 0;
}


³õʼ»¯º¯ÊýÖ¸Ã÷ÁËÍøÇŵĴ¦Àíº¯ÊýÊÇbr_handle_frameioctl´¦Àíº¯ÊýÊÇ£ºbr_ioctl_deviceless_stub¡£

Èý¡¢br_handle_frame(br_input.c)

ÍøÇÅ´¦Àíº¯Êý

ÒýÓÃ:
void br_handle_frame(struct sk_buff *skb)
{
struct net_bridge *br;
unsigned char *dest;
struct net_bridge_port *p;

/*»ñÈ¡Ä¿µÄMACµØÖ·*/
dest = skb->mac.ethernet->h_dest;

/*skb->dev->br_portÓÃÓÚÖ¸¶¨½ÓÊÕ¸ÃÊý¾Ý°üµÄ¶Ë¿Ú£¬
Èô²»ÊÇÊôÓÚÍøÇŵĶ˿ڣ¬ÔòΪNULL*/
p = skb->dev->br_port;
if (p == NULL) /*¶Ë¿Ú²»ÊÇÍøÇÅ×é¶Ë¿ÚÖÐ*/
goto err_nolock;

/*±¾¶Ë¿ÚËùÊôµÄÍøÇÅ×é*/
br = p->br;

/*¼ÓËø£¬ÒòΪÔÚת·¢ÖÐÐèÒª¶ÁCAM±í£¬ËùÒÔ±ØÐë¼Ó¶ÁËø£¬
±ÜÃâÔÚÕâ¸ö¹ý³ÌÖÐÁíÍâµÄÄں˿ØÖÆ·¾¶(Èç¶à´¦Àí»úÉÏÁíÍâÒ»¸öCPUÉϵÄϵͳµ÷ÓÃ)ÐÞ¸ÄCAM±í*/
read_lock(&br->lock);
if (skb->dev->br_port == NULL) /*Ç°ÃæÅжϹýµÄ*/
goto err;

/*br->devÊÇÍøÇŵÄÐéÄâÍø¿¨£¬Èç¹ûËüδUP£¬
»òÍøÇÅDISABLED,p->stateʵ¼ÊÉÏÊÇÇŵĵ±Ç°¶Ë¿ÚµÄSTP¼ÆËãÅжϺóµÄ״̬*/
if (!(br->dev.flags & IFF_UP) ||
p->state == BR_STATE_DISABLED)
goto err;

/*Ô´MACµØַΪ255.X.X.X£¬¼´Ô´MACÊǶಥ»ò¹ã²¥£¬¶ªÆúÖ®*/
if (skb->mac.ethernet->h_source[0] & 1)
goto err;
ÎÄÕÂÆÀÂÛ

¹²ÓÐ 2 ÌõÆÀÂÛ

  1. Emperor ÓÚ 2006-11-29 09:58:19·¢±í:

    »ù±¾¿ò¼Ü¾ÍÊÇÕâÑùÁË£¬ÓëÄÇЩ½²ÍøÇÅÔ­ÀíµÄÊéÉϽ²µÄ»ù±¾²î²»¶à¡­¡­

    ÍøÇÅÖ®ËùÒÔÊÇÍøÇÅ£¬Ö÷Òª¿¿ÕâÁ½¸öº¯Êý£º

    ÒýÓÃ:
    br_fdb_insert
    br_fdb_get


    Ò»¸öѧϰ£¬Ò»¸ö²é±í£»ÁíÍ⣬֧³ÖSTP£¬´¦ÀíBPDU£¬ÐèÒªÓõ½º¯Êýbr_stp_handle_bpdu.ÄÄλÓÐÕâÈý¸öº¯ÊýµÄϸ½Ú·ÖÎö£¬¿É·ñË;żúÒ»·Ý£¬ÃâµÃÏÂÎçÄÇôÐÁ¿àÔÙÈ¥¿Ð´úÂë¡­¡­

    ɨÁËһϠbr_fdb_insert£¬½á¹¹»¹ÊǺÜÇåÎö£¬Èç¹ûµ±Ç°ÏîÒÑ´æÔÚÓÚhash±íÏîÖУ¬Ôò¸üÐÂËü£¨__fdb_possibly_replace£©£¬Èç¹ûÊÇÐÂÏÔò²åÈ룬ʵ¼ÊÊÇÒ»¸öË«ÏòÁ´±íµÄά»¤¹ý³Ì£¨__hash_link£©£º

    ÒýÓÃ:
    void br_fdb_insert(struct net_bridge *br,
    struct net_bridge_port *source,
    unsigned char *addr,
    int is_local)
    {
    struct net_bridge_fdb_entry *fdb;
    int hash;

    hash = br_mac_hash(addr);

    write_lock_bh(&br->hash_lock);
    fdb = br->hash[hash];
    while (fdb != NULL) {
    if (!fdb->is_local &&
    !memcmp(fdb->addr.addr, addr, ETH_ALEN)) {
    __fdb_possibly_replace(fdb, source, is_local);
    write_unlock_bh(&br->hash_lock);
    return;
    }

    fdb = fdb->next_hash;
    }

    fdb = kmalloc(sizeof(*fdb), GFP_ATOMIC);
    if (fdb == NULL) {
    write_unlock_bh(&br->hash_lock);
    return;
    }

    memcpy(fdb->addr.addr, addr, ETH_ALEN);
    atomic_set(&fdb->use_count, 1);
    fdb->dst = source;
    fdb->is_local = is_local;
    fdb->is_static = is_local;
    fdb->ageing_timer = jiffies;

    __hash_link(br, fdb, hash);

    write_unlock_bh(&br->hash_lock);
    }


    ͬÑù£¬²é±íÒ²ÊÇÒ»¸ö±éÀúÁ´±í£¬½øÐеØÖ·Æ¥ÅäµÄ¹ý³Ì£º

    ÒýÓÃ:
    struct net_bridge_fdb_entry *br_fdb_get(struct net_bridge *br, unsigned char *addr)
    {
    struct net_bridge_fdb_entry *fdb;

    read_lock_bh(&br->hash_lock);
    fdb = br->hash[br_mac_hash(addr)];
    while (fdb != NULL) {
    if (!memcmp(fdb->addr.addr, addr, ETH_ALEN)) {
    if (!has_expired(br, fdb)) {
    atomic_inc(&fdb->use_count);
    read_unlock_bh(&br->hash_lock);
    return fdb;
    }

    read_unlock_bh(&br->hash_lock);
    return NULL;
    }

    fdb = fdb->next_hash;
    }

    read_unlock_bh(&br->hash_lock);
    return NULL;
    }

  2. Emperor ÓÚ 2006-11-29 09:57:32·¢±í:

    ÖÚËùÖÜÖ®£¬ÍøÇÅÖ®ËùÒÔÊÇÍøÇÅ£¬±ÈHUB¸üÖÇÄÜ£¬ÊÇÒòΪËüÓÐÒ»¸öMAC-PORTµÄ±í£¬ÕâÑùת·¢Êý¾Ý¾Í²»Óù㲥£¬¶ø²é±í¶¨¶Ë¿Ú¾Í¿ÉÒÔÁË

    ÿ´ÎÊÕµ½Ò»¸ö°ü£¬ÍøÇŶ¼»áѧϰÆäÀ´Ô´MAC£¬Ìí¼Ó½øÕâ¸ö±í¡£LinuxÖÐÕâ¸ö±í½ÐCAM±í(Õâ¸öÃû×ÖÊÇÆäËü×ÊÁÏÉÏ¿´µÄ)¡£Èç¹ûÇŵÄ״̬ÊÇLEARNING»òFORWARDING(ѧϰ»òת·¢)£¬Ôòѧϰ¸Ã°üµÄÔ´µØÖ·skb->mac.ethernet->h_source£¬½«ÆäÌí¼Óµ½CAM±íÖУ¬Èç¹ûÒѾ­´æÔÚÓÚ±íÖÐÁË£¬Ôò¸üж¨Ê±Æ÷£¬br_fdb_insertÍê³ÉÁËÕâÒ»¹ý³Ì

    ÒýÓÃ:
    if (p->state == BR_STATE_LEARNING ||
    p->state == BR_STATE_FORWARDING)
    br_fdb_insert(br, p, skb->mac.ethernet->h_source, 0);


    STPЭÒéµÄBPDU°üµÄÄ¿µÄMAC²ÉÓõÄÊǶಥĿ±êMACµØÖ·£º´Ó01-80-c2-00-00-00£¨Bridge_group_addr£ºÍøÇÅ×é¶à²¥µØÖ·£©¿ªÊ¼.ËùÒÔÕâÀïÊÇÈç¹û¿ªÆôÁËSTP£¬¶øµ±Ç°Êý¾Ý°üÓÖÊÇÒ»¸öBPDU(!memcmp(dest, bridge_ula, 5)£¬ unsigned char bridge_ula[6] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 }£¬Ôò½»ÓÉÏàÓ¦º¯Êý´¦Àí¡£if (br->stp_enabled &&£¬ÕâÀïÖ»±È½ÏÇ°5¸ö×Ö½Ú£¬Ã»ÓÐ×ÐϸÑо¿¹ýSTPÊÇʹÓÃÁËÈ«²¿¶à²¥µØÖ·£¨´Ó0 1 : 0 0 : 5 e : 0 0 : 0 0 : 0 0µ½0 1 : 0 0 : 5 e : 7 f : ff : ff¡££©£¬»¹ÊÇֻʹÓÃÁËÒ»²¿·Ý£¬ÕâÀï¿´À´ËƺõÖ»ÊÇÒ»²¿·Ý£¬Ã»È¥ÉÁË

    ÒýÓÃ:
    !memcmp(dest, bridge_ula, 5) &&
    !(dest[5] & 0xF0)) /*01-80-c2-00-00-F0 ÊÇÒ»¸öʲôµØÖ·£¿ÎªÊ²Ã´ÒªÅжÏÄØ£¿*/
    goto handle_special_frame;

    /*´¦Àí¹³×Óº¯Êý£¬È»ºóת½»br_handle_frame_finishº¯Êý¼ÌÐø´¦Àí*/
    if (p->state == BR_STATE_FORWARDING) {
    NF_HOOK(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
    br_handle_frame_finish);
    read_unlock(&br->lock);
    return;
    }

    err:
    read_unlock(&br->lock);
    err_nolock:
    kfree_skb(skb);
    return;

    handle_special_frame:
    if (!dest[5]) {
    br_stp_handle_bpdu(skb);
    return;
    }

    kfree_skb(skb);
    }


    ËÄ¡¢br_handle_frame_finish

    ÒýÓÃ:
    static int br_handle_frame_finish(struct sk_buff *skb)
    {
    struct net_bridge *br;
    unsigned char *dest;
    struct net_bridge_fdb_entry *dst;
    struct net_bridge_port *p;
    int passedup;

    /*Ç°Ãæ»ù±¾Ïàͬ*/
    dest = skb->mac.ethernet->h_dest;


    p = skb->dev->br_port;
    if (p == NULL)
    goto err_nolock;

    br = p->br;
    read_lock(&br->lock);
    if (skb->dev->br_port == NULL)
    goto err;

    passedup = 0;

    /*Èç¹ûÍøÇŵÄÐéÄâÍø¿¨´¦ÓÚ»ìÔÓģʽ£¬ÄÇôÿ¸ö½ÓÊÕµ½µÄÊý¾Ý°ü¶¼ÐèÒª¿Ë¡һ·Ý
    Ë͵½AF_PACKETЭÒé´¦ÀíÌå(ÍøÂçÈíÖжϺ¯Êýnet_rx_actionÖÐptype_allÁ´µÄ´¦Àí)¡£*/
    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 (dest[0] & 1) {
    br_flood_forward(br, skb, !passedup);
    if (!passedup)
    br_pass_frame_up(br, skb);
    goto out;
    }

    /*LinuxÖеÄMAC-PORT±íÊÇCAM±í£¬ÕâÀï¸ù¾ÝÄ¿µÄµØÖ·À´²é±í£¬
    ÒÔÈ·¶¨ÓÉÄĸö½Ó¿Ú°Ñ°üת·¢³öÈ¥
    ÿһ¸ö±íÏîÊÇͨ¹ý½á¹¹struct net_bridge_fdb_entryÀ´ÃèÊöµÄ£º
    struct net_bridge_fdb_entry
    {
    struct net_bridge_fdb_entry *next_hash; //ÓÃÓÚCAM±íÁ¬½ÓµÄÁ´±íÖ¸Õë
    struct net_bridge_fdb_entry **pprev_hash; //ΪʲôÊÇpprev²»ÊÇprevÄØ£¿»¹Ã»ÓÐ×ÐϸȥÑо¿
    atomic_t use_count; //´ËÏǰµÄÒýÓüÆÊýÆ÷
    mac_addr addr; //MACµØÖ·
    struct net_bridge_port *dst; //´ËÏîËù¶ÔÓ¦µÄÎïÀí¶Ë¿Ú
    unsigned long ageing_timer; //´¦ÀíMAC³¬Ê±
    unsigned is_local:1; //ÊÇ·ñÊDZ¾»úµÄMACµØÖ·
    unsigned is_static:1; //ÊÇ·ñÊǾ²Ì¬MACµØÖ·
    };*/
    dst = br_fdb_get(br, dest);

    /*²éѯCAM±íºó£¬Èç¹ûÄܹ»ÕÒµ½±íÏ²¢ÇÒÄ¿µÄMACÊǵ½±¾»úµÄÐéÄâÍø¿¨µÄ£¬
    ÄÇô¾ÍÐèÒª°ÑÕâ¸ö°üÌá½»¸øÉϲãЭÒ飬
    ÕâÑù£¬ÎÒÃǾͿÉÒÔͨ¹ýÕâ¸öÐéÄâÍø¿¨µÄµØÖ·À´Ô¶³Ì¹ÜÀíÍøÇÅÁË*/
    if (dst != NULL && dst->is_local) {
    if (!passedup)
    br_pass_frame_up(br, skb);
    else
    kfree_skb(skb);
    br_fdb_put(dst);
    goto out;
    }

    /*²éµ½±íÁË£¬ÇÒ²»ÊDZ¾µØÐéÄâÍø¿¨µÄ£¬×ª·¢Ö®*/
    if (dst != NULL) {
    br_forward(dst->dst, skb);
    br_fdb_put(dst);
    goto out;
    }

    /*Èç¹û±íÀï±ß²é²»µ½£¬ÄÇôֻºÃѧϰѧϰHUBÁË¡­¡­*/
    br_flood_forward(br, skb, 0);

    out:
    read_unlock(&br->lock);
    return 0;

    err:
    read_unlock(&br->lock);
    err_nolock:
    kfree_skb(skb);
    return 0;
    }