Como remover rapidamente o endereço IP quando o cabo de rede é desconectado?

4

Dentro do CentOS eu uso o NetworkManager para lidar com minhas interfaces e configurações de rede. Para um mostruário, preciso conectar rapidamente o cabo de rede da porta 1 à porta 2 do meu switch. Cada porta do switch pertence a uma rede diferente. Em cada rede, um servidor DHCP separado distribui endereços IP para sua rede. Eu deveria receber um novo endereço IP sempre que eu conectar meu computador a uma porta diferente do switch.

No entanto, demora cerca de 5 segundos até que os endereços IP sejam removidos da minha interface ao desconectar o cabo. Portanto, ao reconectar rapidamente meu computador a uma porta diferente, o endereço IP antigo ainda não foi removido e nenhum novo foi atribuído.

Minha primeira tentativa foi usar um script personalizado em /etc/NetworkManager/NetworkManager/dispatcher.d/ , que libera os endereços IP de uma interface. Infelizmente, meu script é chamado não até que o tempo limite de ~ 5 segundos tenha passado.

É possível configurar o NetworkManager para liberar o endereço IP mais rapidamente? Se sim, como? Se não com o NetworkManager, há outra maneira de me livrar dos endereços IP rapidamente?

Além disso, alguém sabe qual componente da pilha de rede é responsável por esse tempo limite? É possível diminuí-lo?

    
por Max 17.10.2017 / 11:04

2 respostas

3

O NM ignora o sinal de perda da portadora por 5 segundos, antes de desativar o dispositivo. O tempo limite não é configurável atualmente (e em alguns casos o tempo limite é estendido até 10 segundos). Isso acontece porque, às vezes, a portadora pode desaparecer por um momento, por exemplo, ao alterar a MTU ou porque o switch decide fazê-lo.

Eu não estou ciente de uma solução simples, se você quiser reconectar o cabo mais rápido, em seguida, 10 segundos. Naturalmente, você pode emitir um nmcli device reapply "$DEV" ou nmcli connection up "$CON" , mas isso requer uma intervenção manual adicional por você.

    
por 19.10.2017 / 07:40
0

Agora estou usando um serviço escrito em C para gerenciar a interface sozinho. É basicamente um wrapper para dhclient e ip . Este é o código que estou usando para gerenciar minha interface:

#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;
}
    
por 23.10.2017 / 13:44