网线拔掉后如何快速删除IP地址?

网线拔掉后如何快速删除IP地址?

在 CentOS 中,我使用 NetworkManager 来处理我的接口和网络配置。为了进行展示,我需要快速将网络电缆从交换机的端口 1 插入到端口 2。每个交换机端口属于不同的网络。在每个网络中,都有一个单独的 DHCP 服务器为其网络分配 IP 地址。每当我将计算机插入交换机的不同端口时,我都应该收到新的 IP 地址。

然而,拔掉电缆后,大约需要 5 秒钟,IP 地址才会从我的接口中删除。因此,当我快速将计算机重新插入不同的端口时,旧的 IP 地址尚未删除,也没有分配新的 IP 地址。

我的第一次尝试是使用自定义脚本来/etc/NetworkManager/NetworkManager/dispatcher.d/刷新接口的 IP 地址。不幸的是,我的脚本直到大约 5 秒超时后才被调用。

是否可以配置 NetworkManager 以更快地刷新 IP 地址?如果是,怎么办?如果不使用 NetworkManager,是否有其他方法可以快速删除 IP 地址?

另外,有谁知道网络堆栈的哪个组件负责此超时?有可能减少吗?

答案1

在停用设备之前,NM 会忽略载波丢失信号 5 秒。目前超时是不可配置的(在某些情况下超时甚至可以延长至 10 秒)。这样做是因为有时运营商可能会暂时消失,例如在更改 MTU 时或因为交换机决定这样做。

我不知道有什么简单的解决方案,如果您想更快地重新插入电缆,只需 10 秒。当然,您可以发出nmcli device reapply "$DEV"nmcli connection up "$CON",但这需要您进行额外的手动干预。

答案2

我现在正在使用用 C 编写的服务来自己管理界面。它基本上是一个包装器dhclientip。这是我用来管理界面的代码:

#include <stdio.h>
#include <string.h>
#include <asm/types.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <linux/if.h>
#include <linux/rtnetlink.h>
#include <stdlib.h>
#include <stdbool.h>

#define ENTRY(x) {x, #x}
struct {
    unsigned flag;
    const char *name;
} ifi_flag_map[] = {
        ENTRY(IFF_UP),
        ENTRY(IFF_BROADCAST),
        ENTRY(IFF_DEBUG),
        ENTRY(IFF_LOOPBACK),
        ENTRY(IFF_POINTOPOINT),
        ENTRY(IFF_NOTRAILERS),
        ENTRY(IFF_RUNNING),
        ENTRY(IFF_NOARP),
        ENTRY(IFF_PROMISC),
        ENTRY(IFF_ALLMULTI),
        ENTRY(IFF_MASTER),
        ENTRY(IFF_SLAVE),
        ENTRY(IFF_MULTICAST),
        ENTRY(IFF_PORTSEL),
        ENTRY(IFF_AUTOMEDIA),
        ENTRY(IFF_DYNAMIC),
        ENTRY(IFF_LOWER_UP),
        ENTRY(IFF_DORMANT),
        ENTRY(IFF_ECHO),
};

int InterfaceIndex;
char InterfaceName[32];
char FlushCommand[64];
char DHCPCommand[64];

void check_flags(unsigned flags)
{
    size_t i;
    bool hasFlagLowerUp = false;

    for (i = 0; i < sizeof ifi_flag_map/sizeof ifi_flag_map[0]; i++) {
        if (flags & ifi_flag_map[i].flag) {
            if (ifi_flag_map[i].name == "IFF_LOWER_UP"){
                hasFlagLowerUp = true;
            }
        }
    }
    if (!hasFlagLowerUp){
        printf("Cable removed. Going to flush IPs now...\n");
        system(FlushCommand);
    } else {
        printf("Flag IFF_LOWER_UP present. Going to call %s.\n", DHCPCommand);
        system(DHCPCommand);
    }
}

void read_msg(int fd)
{
    int len;
    char buf[4096];
    struct iovec iov = { buf, sizeof(buf) };
    struct sockaddr_nl sa;
    struct msghdr msg = { (void *)&sa, sizeof(sa), &iov, 1, NULL, 0, 0 };
    struct nlmsghdr *nh;

    len = recvmsg(fd, &msg, 0);
    if(len == -1) {
        perror("recvmsg");
        return;
    }

    for (nh = (struct nlmsghdr *) buf; NLMSG_OK (nh, len);
         nh = NLMSG_NEXT (nh, len)) {
        struct ifinfomsg *ifimsg;

        if (nh->nlmsg_type == NLMSG_DONE)
            return;

        if (nh->nlmsg_type == NLMSG_ERROR) {
            continue;
        }

        ifimsg = NLMSG_DATA(nh);

        printf("Noticed event on interface with id %u\n", ifimsg->ifi_index);
        if (ifimsg->ifi_index == InterfaceIndex) {
            printf("Interface is supervised interface %s. Going to check if cable was removed...\n",InterfaceName);
            check_flags(ifimsg->ifi_flags);
        }

    }
}

int main(int argc, char *argv[])
{
    if (argc < 3){
        printf("Please provide interface id as first argument\n");
        printf("Please provide interface name as second argument\n\n");
        printf("Example: %s 2 eth0\n", argv[0]);
        return 1;
    }
    if (sscanf (argv[1], "%i", &InterfaceIndex) != 1) {
        fprintf(stderr, "Interface index must be integer\n");
        return 1;
    }
    strcpy(InterfaceName,argv[2]);
    sprintf(FlushCommand, "ip addr flush dev %s", InterfaceName);
    sprintf(DHCPCommand, "dhclient -r %s && dhclient %s", InterfaceName, InterfaceName);

    printf("Watching interface %s with id %u for events.\n", InterfaceName, InterfaceIndex);
    printf("Will flush IPs from interface %s when cable is removed.\n", InterfaceName);

    struct sockaddr_nl sa;
    int fd;

    memset(&sa, 0, sizeof(sa));
    sa.nl_family = AF_NETLINK;
    sa.nl_groups = RTMGRP_LINK;

    fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
    if(fd == -1) {
        perror("socket");
        return 1;
    }

    if(bind(fd, (struct sockaddr *) &sa, sizeof(sa)) == -1) {
        perror("bind");
        return 1;
    }
    for(;;) {
        read_msg(fd);
    }

    return 0;
}

相关内容