我们使用 OpManager 监控远程 Linux 机器上的接口设备。这些机器有 VLAN,我们用它们来收集有关中继到机器的网络的信息。例如,我们有 eth0.2、eth0.3、eth0.12、eth0.13、eth0.22、eth0.23(分别对应于 VLAN 2、3、12、13、22、23)。
我们正在管理 IP 地址上使用 SNMP 来检查并确保接口已启动。但是,如果我们必须重新启动网络服务,我们会遇到接口索引发生变化的问题。我们将收到以下错误消息:
接口“eth0.23 - eth0.23”已关闭。接口描述为“eth0.23”,索引为 11。未配置电路 ID。
即使接口已启动并正在运行。
我们如何才能将索引值更改为在重启后保持不变。如果我们将接口从静态 IP 更改为动态 IP,我们也看到了这一点。
答案1
简而言之,SNMP RFC 不需要网络管理器重新初始化之间的 ifIndex 持久性。net-snmp 不提供任何特殊工具来提供此功能。
来自 RFC 2863:
接口 ifIndex 值恒定(重新初始化之间)的要求通过以下方式满足:在动态删除接口后,其 ifIndex 值不能被其他接口重复使用。不同的动态添加的接口直到下次网管系统重新初始化之后才有效。
要点是,当系统重新初始化(即重新启动)时,明确允许将 ifIndex 条目用于任何接口。
来自 Linux 内核 (net/core/dev.c):
static int dev_new_index(struct net *net)
{
static int ifindex;
for (;;) {
if (++ifindex <= 0)
ifindex = 1;
if (!__dev_get_by_index(net, ifindex))
return ifindex;
}
}
内核中的 ifindex 分配使用简单的增量算法。这很重要,因为在 net-snmp (agent/mibgroup/if-mib/data_access/interface_ioctl.c) 中:
oid
netsnmp_access_interface_ioctl_ifindex_get(int fd, const char *name)
{
#ifndef SIOCGIFINDEX
return 0;
#else
struct ifreq ifrq;
int rc = 0;
DEBUGMSGTL(("access:interface:ioctl", "ifindex_get\n"));
rc = _ioctl_get(fd, SIOCGIFINDEX, &ifrq, name);
if (rc < 0) {
DEBUGMSGTL(("access:interface:ioctl",
"ifindex_get error on inerface '%s'\n", name));
return 0;
}
return ifrq.ifr_ifindex;
#endif /* SIOCGIFINDEX */
}
这个函数最终被调用来填充 ifindex,它只是使用 IOCTL 接口从 Linux 内核检索 SIOCGIFINDEX 值。
当我在使用基于 SNMP 的监控系统时遇到此类问题时,我最终使用了另一种方法来引用网络接口。具体来说,我使用了接口名称而不是接口索引号(即“eth0”、“eth1”、“vlan150”等)。
答案2
您可以考虑使用 if_indextoname(index_val, index_name)。其中 index_val 为 unsigned int 类型,index_name 为 char * 类型。
传递 index_val 并且 Linux 内核会将其映射到正确的 index_name,您可以在代码中使用它,因为 index_name 在重启后是相同的。