mii-tool的限制/mii-tool和千兆网络
                       来源: ChinaUnix博客   作者: ChinaUnix博客   发布时间:2007-01-01
 
                        mii-tool的限制/mii-tool和千兆网络
                        mii-tool的限制
                        mii-tool不支持1000M以上的网卡,这里我们先做个实验,先看看100M网卡能不能正确显示:
                        [root@localhost /]# mii-tool -v eth0
                        eth0: negotiated 100baseTx-FD, link ok
                        product info: vendor 00:40:63, model 50 rev 10
                        basic mode: autonegotiation enabled
                        basic status: autonegotiation complete, link ok
                        capabilities: 100baseTx-FD 100baseTx-HD 10baseT-FD
                        10baseT-HD
                        advertising: 100baseTx-FD 100baseTx-HD 10baseT-FD
                        10baseT-HD flow-control
                        link partner: 100baseTx-FD 100baseTx-HD 10baseT-FD
                        10baseT-HD
                        #这里显示100M网卡
                        [root@localhost /]# ethtool eth0
                        Settings for eth0:
                        Supported ports: [ TP MII ]
                        Supported link modes: 10baseT/Half 10baseT/Full
                        100baseT/Half 100baseT/Full
                        Supports auto-negotiation: Yes
                        Advertised link modes: 10baseT/Half 10baseT/Full
                        100baseT/Half 100baseT/Full
                        Advertised auto-negotiation: Yes
                        Speed: 100Mb/s
                        Duplex: Full
                        Port: MII
                        PHYAD: 1
                        Transceiver: internal
                        Auto-negotiation: on
                        Supports Wake-on: pumbg
                        Wake-on: d
                        Current message level: 0x00000001 (1)
                        Link detected: yes
                        #这里也显示是100M网卡
                        正常对于100M以下的网卡都能够用这俩个命令来查看,但是对于100M以上网卡的,mii-tool就会出现问题
                        mii-tool -v eth0
                        eth0: negotiated 100baseTx-FD, link ok
                        product info: vendor 00:aa:00, model 56 rev 0
                        basic mode: autonegotiation enabled
                        basic status: autonegotiation complete, link ok
                        capabilities: 100baseTx-FD 100baseTx-HD 10baseT-FD
                        10baseT-HD
                        advertising: 100baseTx-FD 100baseTx-HD 10baseT-FD
                        10baseT-HD flow-control
                        link partner: 100baseTx-FD 100baseTx-HD 10baseT-FD
                        10baseT-HD
                        #这里显示100M网卡,实际上我是1000M的接口
                        ethtool eth0
                        Settings for eth0:
                        Supported ports: [ TP ]
                        Supported link modes: 10baseT/Half 10baseT/Full
                        100baseT/Half 100baseT/Full
                        1000baseT/Full
                        Supports auto-negotiation: Yes
                        Advertised link modes: 10baseT/Half 10baseT/Full
                        100baseT/Half 100baseT/Full
                        1000baseT/Full
                        Advertised auto-negotiation: Yes
                        Speed: 1000Mb/s
                        Duplex: Full
                        Port: Twisted Pair
                        PHYAD: 0
                        Transceiver: internal
                        Auto-negotiation: on
                        Supports Wake-on: umbg
                        Wake-on: d
                        Current message level: 0x00000007 (7)
                        Link detected: yes
                        #这里却正确的显示1000M网卡
                        这里简单分析一下mii-tool的显示部份的实现:
                        1、首先在主函数中打开套接字,循环调用处理函数:
                        int main(int argc, char **argv)
                        {
                        int i;
                        char s[6];
                        /* Open a basic socket. */
                        if ((skfd = socket(AF_INET, SOCK_DGRAM,0))
                        perror("socket");
                        exit(-1);
                        }
                        for (i = 0; i
                        sprintf(s, "eth%d", i);
                        do_one_xcvr(skfd, s, 1);
                        }
                        return 0;
                        }

                        do_one_xcvr的主要功能是调用ioctl取得网卡的phy_id,然后进一步处理:
                        int do_one_xcvr(int skfd, char *ifname, int maybe)
                        {
                        struct mii_data *mii = (struct mii_data *)&ifr.ifr_data;
                        /* Get the vitals from the interface. */
                        strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
                        if (ioctl(skfd, SIOCGMIIPHY, &ifr)
                        {
                        if (!maybe || (errno != ENODEV))
                        {
                        fprintf(stderr, "SIOCGMIIPHY on '%s' failed: %sn",
                        ifname, strerror(errno));
                        }
                        return 1;
                        }
                        show_basic_mii(skfd, mii->phy_id);
                        }
                        关于SIOCGMIIPHY等宏的定义,很容易就能够找到了,这里不分析了……
                        show_basic_mii是整个核心了:
                        int show_basic_mii(int sock, int phy_id)
                        {
                        char buf[100];
                        int i, mii_val[32];
                        int bmcr, bmsr, advert, lkpar;
                        /* Some bits in the BMSR are latched, but we can't rely
                        on being
                        the only reader, so only the current values are
                        meaningful */
                        mdio_read(sock, MII_BMSR);
                        for (i = 0; i
                        mii_val = mdio_read(sock, i);
                        if (mii_val[MII_BMCR] == 0xffff) {
                        fprintf(stderr, " No MII transceiver present!.n");
                        return -1;
                        }
                        /* Descriptive rename. */
                        bmcr = mii_val[MII_BMCR]; bmsr = mii_val[MII_BMSR];
                        advert = mii_val[MII_ANAR]; lkpar = mii_val[MII_ANLPAR];
                        sprintf(buf, "%s: ", ifr.ifr_name);
                        if (bmcr & MII_BMCR_AN_ENA) {
                        if (bmsr & MII_BMSR_AN_COMPLETE) {
                        if (advert & lkpar) {
                        strcat(buf, (lkpar & MII_AN_ACK) ?
                        "negotiated" : "no autonegotiation,");
                        strcat(buf, media_list(advert & lkpar, 1));
                        strcat(buf, ", ");
                        } else {
                        strcat(buf, "autonegotiation failed, ");
                        }
                        } else if (bmcr & MII_BMCR_RESTART) {
                        strcat(buf, "autonegotiation restarted, ");
                        }
                        } else {
                        sprintf(buf+strlen(buf), "%s Mbit, %s duplex, ",
                        (bmcr & MII_BMCR_100MBIT) ? "100" : "10",
                        (bmcr & MII_BMCR_DUPLEX) ? "full" : "half");
                        }
                        strcat(buf, (bmsr & MII_BMSR_LINK_VALID) ? "link ok" :
                        "no link");
                        printf("%sn", buf);
                        return 0;
                        }
                        能够看到,主要是通过mdio_read来读取相关信息的,之后就是判断比较和输出了,而输出网卡物一类型的时候,用到了media_list,先来看看mdio_read:
                        static int mdio_read(int skfd, int location)
                        {
                        struct mii_data *mii = (struct mii_data *)&ifr.ifr_data;
                        mii->reg_num = location;
                        if (ioctl(skfd, SIOCGMIIREG, &ifr)
                        fprintf(stderr, "SIOCGMIIREG on %s failed: %sn",
                        ifr.ifr_name,
                        strerror(errno));
                        return -1;
                        }
                        return mii->val_out;
                        }
                        同样,也是用ioctl……^o^,再来看看media_list,他主要根据mdio_read返回来的相关值读取一个事先封装好的结构数组:
                        static char *media_list(int mask, int best)
                        {
                        static char buf[100];
                        int i;
                        *buf = '';
                        mask >>= 5;
                        for (i = 4; i >= 0; i--) {
                        if (mask & (1
                        strcat(buf, " ");
                        strcat(buf, media.name);
                        if (best) break;
                        }
                        }
                        if (mask & (1
                        strcat(buf, " flow-control");
                        return buf;
                        }
                        最后来看看media的定义的赋值:
                        const struct {
                        char *name;
                        u_short value;
                        } media[] = {
                        /* The order through 100baseT4 matches bits in the BMSR
                        */
                        { "10baseT-HD", MII_AN_10BASET_HD },
                        { "10baseT-FD", MII_AN_10BASET_FD },
                        { "100baseTx-HD", MII_AN_100BASETX_HD },
                        { "100baseTx-FD", MII_AN_100BASETX_FD },
                        { "100baseT4", MII_AN_100BASET4 },
                        { "100baseTx", MII_AN_100BASETX_FD | MII_AN_100BASETX_HD
                        },
                        { "10baseT", MII_AN_10BASET_FD | MII_AN_10BASET_HD },
                        };
                        这里没有定义100M以上的接口,所以,mii-tool不支持1000M