通过 MAC 或总线地址(而非名称)关闭接口

通过 MAC 或总线地址(而非名称)关闭接口

有没有办法通过 MAC 或更好的方式通过 lspci 的总线地址关闭网络接口

我正在寻找这样的东西:

ifconfig [BUS ADDRESS from lspci] down

这当然不起作用,使用 ifconfig 或 ip link set dev down

提前致谢

答案1

当然可以——首先找出哪些接口名称属于该设备。它们可以通过 sysfs 列出,位于net/PCI 设备的子目录中:

$ echo /sys/bus/pci/devices/*/net/*
/sys/bus/pci/devices/0000:03:00.0/net/wlan0
/sys/bus/pci/devices/0000:05:00.5/net/eth0

您可以在包装器脚本中使用它ifconfig-by-pciid。(下面提供了示例。)

(请注意,一个 PCI 设备可以承载多个网络接口,尤其是对于 Wi-Fi。)


依恋:pcip.pl

#!/usr/bin/env perl
# pcip - 'ip' wrapper translating PCI & MAC addresses to interface names
# (c) 2015 Mantas Mikulėnas <[email protected]>
# Released under the MIT License <https://spdx.org/licenses/MIT>
#
# Match by PCI device:
#
#     pcip link set pci:03:00.0 up
#
# Match by MAC address:
#
#     pcip addr add 10.0.42.1/16 dev mac:48:5d:04:85:fc:d7
#
# Use with other commands besides `ip`:
#
#     pcip -c ifconfig mac:485d.0485.fcd7 up

use v5.10;
use warnings;
use strict;
use File::Basename;
use Getopt::Long qw(:config no_ignore_case bundling);
use List::Util qw(max);

sub _warn { warn "$0: $_[0]\n"; return; }

sub read_line {
    my ($path) = @_;

    if (open(my $fh, "<", $path)) {
        chomp(my $line = <$fh>);
        close($fh);
        return $line;
    } else {
        _warn("could not open '$path': $!");
    }
}

sub canonicalize_mac {
    my ($addr) = @_;

    my $vbyte = qr/[0-9a-f]{1,2}/;
    my $fbyte = qr/[0-9a-f]{2}/;
    my @match;

    # convert Windows-style addresses with dashes
    $addr = lc($addr);
    $addr =~ y/-/:/;
    # expand missing leading 0's, parse Cisco-style addresses
    if (@match = $addr =~ /^($vbyte):($vbyte):($vbyte):($vbyte):($vbyte):($vbyte)$/ or
        @match = $addr =~ /^($fbyte)($fbyte)\.($fbyte)($fbyte)\.($fbyte)($fbyte)$/ or
        @match = $addr =~ /^($fbyte)($fbyte)($fbyte)($fbyte)($fbyte)($fbyte)$/)
    {
        return join(":", map {sprintf("%02x", hex $_)} @match);
    }
    return $addr;
}

sub ifname_from_pci {
    my ($pciid) = @_;

    unless ($pciid =~ /^[0-9a-f]{4}:/) {
        $pciid = "0000:$pciid";
    }
    return map {basename($_)}
           glob("/sys/bus/pci/devices/$pciid/net/*/");
}

sub ifname_from_mac {
    my ($arg) = @_;

    my $addr = canonicalize_mac($arg);
    if (!$addr) {
        _warn("invalid MAC address '$arg'");
    } else {
        return map {basename($_)}
               grep {read_line("$_/address") eq $addr}
               grep {-f "$_/address"}
               glob("/sys/class/net/*/");
    }
}

sub expand {
    my ($arg) = @_;

    for ($arg) {
        if (/^pci:(.+)/) {
            return ifname_from_pci($1);
        }
        elsif (/^mac:(.+)/) {
            return ifname_from_mac($1);
        }
        else {
            _warn("unknown expansion '$arg'");
        }
    }
}

sub replace_first {
    my ($func, $start, @args) = @_;

    my $pos = -1;
    my $arg = undef;
    for my $i ($start..$#args) {
        if ($args[$i] =~ /^(pci|mac):/) {
            $pos = $i;
            $arg = $args[$i];
            last;
        }
    }
    if ($pos == -1) {
        return $func->(@args);
    } else {
        my @names = expand($arg);
        if (!@names) {
            _warn("could not translate '$arg' to an interface name");
        } else {
            return map {
                $args[$pos] = $_;
                replace_first($func, $pos+1, @args)
            } @names;
        }
    }
}


my $cmd = "ip";
my $fail = 0;

my $handler = sub {
    my (@args) = @_;

    my $ret = (system {$args[0]} @args) >> 8;
    if ($ret) {
        _warn("call {@args} failed with code $ret");
    }
    if ($fail) {
        exit $ret;
    }
    return $ret;
};

GetOptions(
    "c|command=s" => \$cmd,
    "f|fail!" => \$fail,
);

my @cmd = ($cmd, @ARGV);
my @ret = replace_first($handler, 0, @cmd);

if (@ret) {
    exit max(@ret);
} else {
    _warn("no commands were run");
    exit 1;
}
# vim: ts=4:sw=4:et

相关内容