MACアドレスが変更された場合、ifconfigが終了した後に開始するのに遅延がかかるのはなぜですか?

MACアドレスが変更された場合、ifconfigが終了した後に開始するのに遅延がかかるのはなぜですか?

こんにちは、インターフェイスを削除してMACアドレスを変更した後に再度呼び出すbashスクリプトを作成しました。

#!/bin/bash

INTERFACE_STATUS=$( cat /sys/class/net/eth0/operstate )

echo "$INTERFACE_STATUS"

if [ "$INTERFACE_STATUS" == "up" ]
then
    echo  "Putting down eth0"
    sudo ifconfig eth0 down
    # putting down eth0 works only when I sleep 10 seconds after using command
    #sleep 10
    echo "$( cat /sys/class/net/eth0/operstate )"
#     TRIES=0
#     while [ "$( cat /sys/class/net/eth0/operstate )" == "up" ]
#     do
#         sleep 1
#         TRIES=$(($TRIES + 1))
#         if [ "$TRIES" == "7" ]
#         then
#             echo Could not put down eth0
#             exit 1
#         fi
#     done
fi

sudo ifconfig eth0 hw ether "91:91:91:91:91:91"

sudo ifconfig eth0 up

問題はそれがうまくいかないことです。 dropの直後にeth0/sys/class/net/eth0/operstateに変わりましたが、downまだ閉じていないようです。インターフェイスeth0を削除するのに約10秒かかったので、これを機能させる唯一の方法は、sleep 10eth0を削除して追加することです。

だから私の質問は、eht0が実際に閉じられていることを確認する方法です。

//編集する

ifconfig eth0 up新しいMACアドレスを取得できないため、コマンドは最初に使用されたのと同じです。下にして10秒ほど待ってからMACを変更してから、もう一度下げる必要があります。 eth0を削除するのに数秒かかりますが、早すぎて再度削除すると機能しません。

//編集2

MACアドレスをもう一度確認してみると変わったようですが、Googleでpingをしてみると未知のホストが出てくるので今はDNS関連ではないかと思います。しかし、同じアプローチがsleep 10機能します。

//編集3

スクリプトを使用した後、sleep 10pingを試してみました。

piotrek@piotrek-Vostro-2520:~$ ping 212.77.100.101
connect: Network is unreachable
piotrek@piotrek-Vostro-2520:~$ ping -n 212.77.100.101
connect: Network is unreachable
piotrek@piotrek-Vostro-2520:~$ ifconfig 
eth0      Link encap:Ethernet  HWaddr 08:3e:8e:2d:36:55  
        inet addr:10.36.253.122  Bcast:10.36.253.255  Mask:255.255.255.0
        inet6 addr: fe80::a3e:8eff:fe2d:3655/64 Scope:Link
        UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
        RX packets:74297 errors:0 dropped:0 overruns:0 frame:0
        TX packets:38597 errors:0 dropped:0 overruns:0 carrier:0                                                                                           
        collisions:0 txqueuelen:1000                                                                                                                       
        RX bytes:32417366 (32.4 MB)  TX bytes:5201537 (5.2 MB)0                                                                                           
      collisions:0 txqueuelen:1000                                                                                                                       
      RX bytes:32417366 (32.4 MB)  TX bytes:5201537 (5.2 MB)

//4つの要約編集

piotrek@piotrek-Vostro-2520:~$ sudo ifconfig eth0 down; sudo ifconfig eth0 hw ether 08:3e:8e:2d:36:55 ; sudo ifconfig eth0 up
piotrek@piotrek-Vostro-2520:~$ ping -n 212.77.100.101
connect: Network is unreachable
piotrek@piotrek-Vostro-2520:~$ sudo ifconfig eth0 down; sleep 10; sudo ifconfig eth0 hw ether 08:3e:8e:2d:36:55 ; sudo ifconfig eth0 up
piotrek@piotrek-Vostro-2520:~$ ping -n 212.77.100.101
PING 212.77.100.101 (212.77.100.101) 56(84) bytes of data.
64 bytes from 212.77.100.101: icmp_req=1 ttl=246 time=8.91 ms
64 bytes from 212.77.100.101: icmp_req=2 ttl=246 time=8.76 ms
64 bytes from 212.77.100.101: icmp_req=3 ttl=246 time=8.52 ms
^C
--- 212.77.100.101 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 8.523/8.734/8.917/0.194 ms

なぜsleep 10重要ですか?

//編集5

奇妙になります。私が使用すると非常にうまく動作しますsleep。せずに試してみると、sleepIPは大丈夫だと思い、インターフェースも浮かんだようですが、ネットワークができませんね。数秒後に削除しようとすると、eth0私のsudo ifconfig eth0 downOS(ubuntu 12.10)は自動的に自分のデバイスに再接続します。古いMACアドレス新しいIPを取得しました。 2回目の使用後はsudo ifconfig eth0 down完全に下げることができましたeth0

piotrek@piotrek-Vostro-2520:~$ sudo ifconfig eth0 down; sleep 10; sudo ifconfig eth0 hw ether 08:3e:8e:2d:36:55 ; sudo ifconfig eth0 up
piotrek@piotrek-Vostro-2520:~$ sudo ifconfig
eth0      Link encap:Ethernet  HWaddr 08:3e:8e:2d:36:55  
        inet addr:10.36.253.241  Bcast:10.36.253.255  Mask:255.255.255.0
        inet6 addr: fe80::a3e:8eff:fe2d:3655/64 Scope:Link
        UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
        RX packets:439341 errors:0 dropped:0 overruns:0 frame:0
        TX packets:224187 errors:0 dropped:0 overruns:0 carrier:0
        collisions:0 txqueuelen:1000 
        RX bytes:400718780 (400.7 MB)  TX bytes:26246307 (26.2 MB)

piotrek@piotrek-Vostro-2520:~$ sudo ifconfig eth0 down; sudo ifconfig eth0 hw ether 08:3e:8e:2d:36:55 ; sudo ifconfig eth0 up
piotrek@piotrek-Vostro-2520:~$ ping -n 212.77.100.101
connect: Network is unreachable
piotrek@piotrek-Vostro-2520:~$ ifconfig
eth0      Link encap:Ethernet  HWaddr 08:3e:8e:2d:36:55  
        inet addr:10.36.253.241  Bcast:10.36.253.255  Mask:255.255.255.0
        inet6 addr: fe80::a3e:8eff:fe2d:3655/64 Scope:Link
        UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
        RX packets:439656 errors:0 dropped:0 overruns:0 frame:0
        TX packets:224321 errors:0 dropped:0 overruns:0 carrier:0
        collisions:0 txqueuelen:1000 
        RX bytes:400827185 (400.8 MB)  TX bytes:26267012 (26.2 MB)

piotrek@piotrek-Vostro-2520:~$ sudo ifconfig eth0 down
piotrek@piotrek-Vostro-2520:~$ ifconfig
eth0      Link encap:Ethernet  HWaddr e0:db:55:97:de:cc  
        inet addr:10.36.253.122  Bcast:10.36.253.255  Mask:255.255.255.0
        inet6 addr: fe80::e2db:55ff:fe97:decc/64 Scope:Link
        UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
        RX packets:440302 errors:0 dropped:0 overruns:0 frame:0
        TX packets:224862 errors:0 dropped:0 overruns:0 carrier:0
        collisions:0 txqueuelen:1000 
        RX bytes:401129508 (401.1 MB)  TX bytes:26323176 (26.3 MB)

piotrek@piotrek-Vostro-2520:~$ sudo ifconfig eth0 down
piotrek@piotrek-Vostro-2520:~$ ifconfig eth0
eth0      Link encap:Ethernet  HWaddr e0:db:55:97:de:cc  
        BROADCAST MULTICAST  MTU:1500  Metric:1
        RX packets:440437 errors:0 dropped:0 overruns:0 frame:0
        TX packets:224881 errors:0 dropped:0 overruns:0 carrier:0
        collisions:0 txqueuelen:1000 
        RX bytes:401147424 (401.1 MB)  TX bytes:26326068 (26.3 MB)

//編集6

@Moreakiが提案した解決策を試しましたが、同じ現象が発生します。スクリプトは約1秒間実行されますが、使用後にネットワークにアクセスすることはできません。 @Moreakiのコードは次のとおりです。

#!/usr/bin/env bash

INTF=eth0
INTERFACE_STATUS=$(cat /sys/class/net/${INTF}/operstate)
echo "$INTERFACE_STATUS"

if [ "$INTERFACE_STATUS" == "up" ]; then
    echo "Putting down ${INTF}"
    # if you need to remove all IP addresses associated with ${INTF}
    sudo ip addr flush dev ${INTF}
    # set the interface status down
    sudo ip link set dev ${INTF} down
    # flush neighbour cache
    sudo ip neigh flush dev ${INTF}
    # flush routing cache entries pertaining to ${INTF}
    sudo ip route flush table cache dev ${INTF}
    echo "New state: $(cat /sys/class/net/${INTF}/operstate)"
fi

sudo ip link set dev ${INTF} address "08:3e:8e:2d:36:55"
sudo ip link set dev ${INTF} up

それを使用すると、次のような結果が得られます。

piotrek@piotrek-Vostro-2520:~$ ./mac_test.sh 
up
Putting down eth0
New state: down

pingを試した後:

piotrek@piotrek-Vostro-2520:~$ ping google.com
ping: unknown host google.com
piotrek@piotrek-Vostro-2520:~$ ping 8.8.8.8
connect: Network is unreachable

//編集7

@Moreakiのルーティングスクリプトを使用してMacアドレスを変更する前のルーティングは次のとおりです。

piotrek@piotrek-Vostro-2520:~$ ./routing.sh 
Destination        Gateway         Source             Iface    R_Type RT_table  
default            10.36.253.1     10.36.253.122      eth0            main      
10.36.253.0/24     0.0.0.0         10.36.253.122      eth0            main      
169.254.0.0/16     0.0.0.0         10.36.253.122      eth0            main

以下を使用してMACアドレスを変更した後私のスクリプトは10秒遅れました。:

piotrek@piotrek-Vostro-2520:~$ ./routing.sh 
Destination        Gateway         Source             Iface    R_Type RT_table  
default            10.36.253.1     10.36.253.241      eth0            main      
10.36.253.0/24     0.0.0.0         10.36.253.241      eth0            main      
169.254.0.0/16     0.0.0.0         10.36.253.241      eth0            main

@Moreakiスクリプトを使用した後のルーティング:

piotrek@piotrek-Vostro-2520:~$ ./routing.sh
Destination        Gateway         Source             Iface    R_Type RT_table

@Moreakiもその行にコメントを付けることを提案しましたが、sudo ip addr flush dev ${INTF}それでも理解できますconnect: Network is unreachable。コメントアウトされた行を含むスクリプトを使用した後、私のルーティングは次のようになります。

piotrek@piotrek-Vostro-2520:~$ ./routing.sh
Destination        Gateway         Source             Iface    R_Type RT_table  
10.36.253.0/24     0.0.0.0         10.36.253.122      eth0

答え1

インターフェイスのクローズ遅延は、インターフェイスのドライバおよび/またはハードウェアに関連している可能性があります。これが正しい場合、ドライバやハードウェアが実際にインターフェイスを閉じたかどうかを知る標準的な方法はありません。

トラブルシューティングの残りの部分を読んでみると、競合プロセスがあるかのように聞こえます。特にインターフェース自体を「回復」する部分がそうです。インターフェイスを閉じた後にインターフェイスを実行して復元するためのツールがありますか?

検出するのは少し難しいですが、不可能ではありません。私はあなたがそれを検出できることを示唆する迅速で簡単な方法を考えることはできません。

答え2

私は遅れる必要はないと思います。インターフェイスをシャットダウンする前に、以前のMACアドレスから物理的に切断できなければなりません。ワイヤレス接続中なので、今はテストできません。 ifconfig --helpを確認してください。このような? :

ifconfig <interface> del <address>

ワイヤレスネットワークから切断すると、APのMACアドレスを含むすべてを消去する小さなスクリプトを実行します。

sudo dhcpcd --release "$INTERFACE"
sudo iwconfig "$INTERFACE" essid off
sudo iwconfig "$INTERFACE" ap off
sudo ifconfig "$INTERFACE" down

答え3

まだコメントできないので、私の視点があなたが観察する行動についてある程度明らかになることを願っています。通常、Linuxでは、インターフェイス設定を変更するためにifconfigを使用しないことをお勧めします。実際、この機能は10年以上前に「廃止予定」です。それにもかかわらず、ディストリビューションでifconfigとルーティングを引き続き提供するため、まだ機能する必要があります。

このアプローチが現在見ている動作を変更しているかどうかを確認できますか?

#!/usr/bin/env bash

INTF=eth0
INTERFACE_STATUS=$(cat /sys/class/net/${INTF}/operstate)
echo "$INTERFACE_STATUS"

if [ "$INTERFACE_STATUS" == "up" ]; then
    echo "Putting down ${INTF}"
    # if you need to remove all IP addresses associated with ${INTF}
    sudo ip addr flush dev ${INTF}
    # set the interface status down
    sudo ip link set dev ${INTF} down
    # flush neighbour cache
    sudo ip neigh flush dev ${INTF}
    # flush routing cache entries pertaining to ${INTF}
    sudo ip route flush table cache dev ${INTF}
    echo "New state: $(cat /sys/class/net/${INTF}/operstate)"
fi

sudo ip link set dev ${INTF} address "91:91:91:91:91:91"
sudo ip link set dev ${INTF} up

付録1:フィードバックを読んだ後、ルーティング設定に関する追加情報を提供できます。私は10年前に書いた古いスクリプトを見つけました。これにより、次のようなルーティングテーブル出力が表示されますnetstat(このコマンドを実行するにはルートが必要です)。

#!/usr/bin/env bash

# 08/2000: Initial code to beautify iproute2 routing table output
# 08/2013: Updated it for the new decade and removed swearing.

: ${IPTOOL:=/sbin/ip}
: ${DEBUG:=0}

print_format="%-18s %-15s %-18s %-8s %-6s %-10s\n"

if [ "x$1" == "x-v" -o "x$1" == "x--verbose" ]; then
    DEBUG=1
fi

dbg_log(){
    if [ $DEBUG -eq 1 ]; then
        echo "$*"
    fi
}

printme(){
    if [ "x$via" == "x" -a $src_route -eq 0 ]; then
        via="0.0.0.0"
    fi
    if [ "x$src" == "x" ]; then
        src=$(${IPTOOL} addr show dev $dev label $dev | awk '/inet/ {print $2}')
        src=${src%%/*}
    fi
    printf "$print_format" "$net" "$via" "$src" "$dev" "$type" "$table_id"
}

eval_route(){
    not_parsed=0

    while read net rest; do
        if [ $src_route -eq 0 ]; then
            src=
            type=
        fi
        table_id="${TABLE_ID}"
        dev=
        via=
        set -- $rest
        while [ $# -ne 0 ]; do
            case $1 in
                proto)  shift 1;;
                scope)  shift 1;;
                metric) shift 1;;
                dev)    shift 1; dev=$1;;
                via)    shift 1; via=$1;;
                src)    shift 1; src=$1
                   # As soon as I've figured out, how to get back the
                   # interface/label definition from a given src IP
                   # I will adjust this ugly hack. --rn, 08/2000
                   if [ "x${src%.*}" != "x${net%.*}" ]; then
                       dev=$(${IPTOOL} addr show dev $dev to $src | \
                           awk -v check_ip=${temp_ip%%/*} 'BEGIN {/$check_ip/} END {print $7}')
                   fi
                   ;;
                *) dbg_log "option $1 not parsed"; not_parsed=1;;
            esac
            shift 1
        done
        # Check for 'throw, blackhole, unreachable, prohibit'
        # Since we only check for non-numeric strings, we have
        # to exclude the default target too.
        if [ "x${net//[0-9.]/}" == "x$net" -a "x$net" != "xdefault" ]; then
            type=${net:0:2}
            type=${type~~}
            net=$rest
            dev="all"
            src="0.0.0.0/0"
            not_parsed=0
        fi
        [ $not_parsed -eq 0 ] && printme
        not_parsed=0
    done < <(${IPTOOL} route show table $TABLE_ID)
}

src_route=0
printf "$print_format" "Destination" "Gateway" "Source" "Iface" "R_Type" "RT_table"
while read RULE_ID rest; do
    RULE_ID=${RULE_ID//:/}
    fromIP=
    toIP=
    TABLE_ID=
    set -- ${rest}
    while [ $# -ne 0 ]; do
        case $1 in
            from)   fromIP=$2  ; shift 2;;
            to)     toIP=$2    ; shift 2;;
            lookup) TABLE_ID=$2; shift 2;;
            *)                   shift 1;;
        esac
    done
    if [ $RULE_ID -ne 0 ]; then
        dbg_log "+------------------[RULE: $RULE_ID]------------------+"
        if [ "x$fromIP" != "xall" ]; then
            src_route=1
            src="$IP"
            type=SR
        fi
        eval_route
        src_route=0
    fi
done < <(${IPTOOL} rule show)

関連情報