이름이 아닌 MAC 또는 버스 주소로 인터페이스를 종료합니다.

이름이 아닌 MAC 또는 버스 주소로 인터페이스를 종료합니다.

MAC 또는 더 나은 방법으로 lspci의 버스 주소를 사용하여 네트워크 인터페이스를 종료하는 방법이 있습니까?

내가 찾고 있는 것은 다음과 같습니다.

ifconfig [BUS ADDRESS from lspci] down

물론 이것은 ifconfig나 ip link set dev down에서는 작동하지 않습니다.

미리 감사드립니다

답변1

물론이죠. 먼저 어떤 인터페이스 이름이 해당 장치에 속하는지 알아보세요. net/PCI 장치의 하위 디렉터리 에 있는 sysfs를 통해 나열될 수 있습니다 .

$ 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. (아래에 예시가 나와 있습니다.)

(특히 Wi-Fi의 경우 하나의 PCI 장치가 여러 네트워크 인터페이스를 호스팅할 수 있습니다.)


부착: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

관련 정보