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)) < 0) {
perror("socket");
exit(-1);
}
for (i = 0; i < MAX_ETH; 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) < 0)
{
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 < 8; 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) < 0) {
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<<i)) {
strcat(buf, " ");
strcat(buf, media.name);
if (best) break;
}
}
if (mask & (1<<5))
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