2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

クラッシュダンプからNICの制御情報を確認する

Last updated at Posted at 2022-02-03

概要

Linuxのクラッシュダンプからネットワークデバイスの管理情報であるnet_device構造体の内容を確認してみます。

事前準備

以下の記事を参考にして事前準備を行います。

カーネルのデバッグ情報をインストールします。

 # yum install --enablerepo=base-debuginfo kernel-debuginfo-`uname -r`

クラッシュコマンドをインストールします。

 # yum install crash

OSを強制的にパニックさせてテスト用のクラッシュダンプを採取します。

 # echo c > /proc/sysrq-trigger

OS再起動後に/var/crash配下を確認し、クラッシュダンプが採取されていることを確認します。

ipコマンドによる構成の確認

あらかじめ、ipコマンドにより対象サーバのNIC名やIPアドレス等を確認しておきます。

# ip addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 52:54:00:20:1d:56 brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.62/24 brd 192.168.0.255 scope global noprefixroute eth0
       valid_lft forever preferred_lft forever
    inet6 240f:a1:2044:1:cb15:e4dc:e642:6dbc/64 scope global noprefixroute dynamic
       valid_lft 278sec preferred_lft 278sec
    inet6 fe80::b52b:b451:8c26:4b40/64 scope link noprefixroute
       valid_lft forever preferred_lft forever
3: br-201008366ec8: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
    link/ether 02:42:81:87:19:69 brd ff:ff:ff:ff:ff:ff
    inet 172.18.0.1/16 scope global br-201008366ec8
       valid_lft forever preferred_lft forever
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
    link/ether 02:42:fc:76:39:b9 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 scope global docker0
       valid_lft forever preferred_lft forever

以降ではeth0の制御情報についてcrashコマンドで確認していきます。

項目
NIC名 eth0
Index 2
IPアドレス 192.168.0.62
ネットマスク 255.255.255.0
MTU 1500
FLAGS BROADCAST,MULTICAST,UP,LOWER_UP

crashコマンドの起動

採取したクラッシュダンプを指定してcrashコマンドを起動します。

[root@cent7-vm 127.0.0.1-2022-02-03-15:11:50]# cd /var/crash/127.0.0.1-2022-02-03-15\:11\:50/
[root@cent7-vm 127.0.0.1-2022-02-03-15:11:50]# crash /usr/lib/debug/usr/lib/modules/`uname -r`/vmlinux vmcore

crash 7.2.3-11.el7_9.1
Copyright (C) 2002-2017  Red Hat, Inc.
Copyright (C) 2004, 2005, 2006, 2010  IBM Corporation
Copyright (C) 1999-2006  Hewlett-Packard Co
Copyright (C) 2005, 2006, 2011, 2012  Fujitsu Limited
Copyright (C) 2006, 2007  VA Linux Systems Japan K.K.
Copyright (C) 2005, 2011  NEC Corporation
Copyright (C) 1999, 2002, 2007  Silicon Graphics, Inc.
Copyright (C) 1999, 2000, 2001, 2002  Mission Critical Linux, Inc.
This program is free software, covered by the GNU General Public License,
and you are welcome to change it and/or distribute copies of it under
certain conditions.  Enter "help copying" to see the conditions.
This program has absolutely no warranty.  Enter "help warranty" for details.

GNU gdb (GDB) 7.6
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-unknown-linux-gnu"...

WARNING: kernel relocated [172MB]: patching 87388 gdb minimal_symbol values

      KERNEL: /usr/lib/debug/usr/lib/modules/3.10.0-1160.53.1.el7.x86_64/vmlinux
    DUMPFILE: vmcore  [PARTIAL DUMP]
        CPUS: 2
        DATE: Thu Feb  3 15:11:48 2022
      UPTIME: 00:23:00
LOAD AVERAGE: 0.01, 0.14, 0.14
       TASKS: 161
    NODENAME: cent7-vm
     RELEASE: 3.10.0-1160.53.1.el7.x86_64
     VERSION: #1 SMP Fri Jan 14 13:59:45 UTC 2022
     MACHINE: x86_64  (2095 Mhz)
      MEMORY: 2 GB
       PANIC: "SysRq : Trigger a crash"
         PID: 1994
     COMMAND: "bash"
        TASK: ffff8d8db8ede300  [THREAD_INFO: ffff8d8db9c7c000]
         CPU: 1
       STATE: TASK_RUNNING (SYSRQ)

crash>

ネットワーク情報の表示

netコマンドでネットワークデバイスの一覧を表示します。

crash> net
   NET_DEVICE     NAME   IP ADDRESS(ES)
ffff8d8dbbbb2000  lo     127.0.0.1
ffff8d8d75ccd000  eth0   192.168.0.62
ffff8d8dba7fa000  br-201008366ec8 172.18.0.1
ffff8d8dba7f8000  docker0 172.17.0.1

出力される項目は以下のとおりです。

 項目 説明
NET_DEVICE net_device構造体のポインタ
NAME NIC名
IP_ADDRESS(ES) IPアドレス

net_device構造体のダンプ

structコマンドでeth0のnet_device構造体 ffff8d8d75ccd000 の内容をダンプします。

crash> struct net_device ffff8d8d75ccd000
struct net_device {
  name = "eth0\000\000\000\000\000\000\000\000\000\000\000",
  name_hlist = {
    next = 0x0,
    pprev = 0xffff8d8dbbbc8440
  },
  ifalias = 0x0,
  mem_end = 0,
  mem_start = 0,
  base_addr = 0,
  irq = 0,
  state = 3,
  dev_list = {
    next = 0xffff8d8dba7fa050,
    prev = 0xffff8d8dbbbb2050
  },
  napi_list = {
    next = 0xffff8d8d75c8c450,
    prev = 0xffff8d8d75c8c450
  },
  unreg_list = {
    next = 0xffff8d8d75ccd070,
    prev = 0xffff8d8d75ccd070
  },
  upper_dev_list = {
    next = 0xffff8d8d75ccd080,
    prev = 0xffff8d8d75ccd080
  },
  features = 4296755753,
  hw_features = 35192963811337,
  wanted_features = 1787913,
  vlan_features = 35188668825641,
  hw_enc_features = 8796093022209,
  mpls_features = 1,
  ifindex = 2,
  iflink = 2,
  ...

  以降省略

net_device構造体のメンバーを個別にダンプ

structコマンドでeth0のnet_device構造体 ffff8d8d75ccd000 のメンバーを個別にダンプします。

デバイス名を表示する場合、net_device.nameを指定します。

crash> struct net_device.name ffff8d8d75ccd000
  name = "eth0\000\000\000\000\000\000\000\000\000\000\000"
crash>

デバイスのインデックス番号を表示する場合、net_device.ifindexを指定します。

crash> struct net_device.ifindex ffff8d8d75ccd000
  ifindex = 2
crash>

ifindexの値はip addrコマンドで表示されたものと同一の値です。

デバイスのインタフェースフラグを表示する、net_device.flagsを指定します。

crash> struct net_device.flags ffff8d8d75ccd000
  flags = 4099
crash>

flagsの値4096を16進数に変換すると0x1003となります。これは以下のフラグのORをとった値です。

フラグ
IFF_UP 0x01
IFF_BROADCAST 0x02
IFF_MULTICAST 0x1000

デバイスのMTUを表示する、net_device.mtuを指定します。

crash> struct net_device.mtu ffff8d8d75ccd000
  mtu = 1500
crash>

MTUの値はip addrコマンドで表示されたものと同一の値です。

IPv4情報のダンプ

eth0のnet_device構造体からIPv4の制御情報ip_ptrのポインタffff8d8d7614ec00をin_device構造体にマッピングして内容をダンプします。

crash> struct net_device.ip_ptr ffff8d8d75ccd000
  ip_ptr = 0xffff8d8d7614ec00
crash> struct in_device ffff8d8d7614ec00
struct in_device {
  dev = 0xffff8d8d75ccd000,
  refcnt = {
    counter = 3
  },
  dead = 0,
  ifa_list = 0xffff8d8db8423100,
  mc_list = 0xffff8d8dba818f00,
  mc_count = 1,
  mc_tomb_lock = {
    {
      rlock = {
        raw_lock = {
          val = {
            counter = 0
          }
        }
      }
    }
  },
  mc_tomb = 0x0,
  mr_v1_seen = 0,
  mr_v2_seen = 0,
  mr_maxdelay = 0,
  mr_qrv = 2 '\002',
  mr_gq_running = 0 '\000',
  mr_ifc_count = 0 '\000',
  mr_gq_timer = {
    entry = {
      next = 0x0,
      prev = 0x0
    },
    expires = 0,
    base = 0xffffffff8cd03bc0,
    function = 0xffffffff8c2e30f0,
    data = 18446618237443828736,
    slack = -1,
    start_pid = -1,
    start_site = 0x0,
    start_comm = "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
  },
  mr_ifc_timer = {
    entry = {
      next = 0x0,
      prev = 0x0
    },
    expires = 0,
    base = 0xffffffff8cd03bc0,
    function = 0xffffffff8c2e3120,
    data = 18446618237443828736,
    slack = -1,
    start_pid = -1,
    start_site = 0x0,
    start_comm = "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
  },
  arp_parms = 0xffff8d8d766c2840,
  cnf = {
    sysctl = 0xffff8d8d75ef1800,
    data = {1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0},
    state = {67108863},
    extra_data = {10000, 1000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    extra_state = {65535}
  },
  callback_head = {
    next = 0x0,
    func = 0x0
  }
}

eth0のin_device構造体のifa_listの内容ffff8d8db8423100in_ifaddr構造体にマッピングしてIPアドレスの情報を読み取ります。

crash> struct in_device.ifa_list ffff8d8d7614ec00
  ifa_list = 0xffff8d8db8423100
crash> list ffff8d8db8423100
ffff8d8db8423100
crash> struct in_addr ffff8d8db8423100
struct in_addr {
  s_addr = 0
}
crash> struct in_ifaddr ffff8d8db8423100
struct in_ifaddr {
  hash = {
    next = 0x0,
    pprev = 0xffffffff8ce6a390
  },
  ifa_next = 0x0,
  ifa_dev = 0xffff8d8d7614ec00,
  callback_head = {
    next = 0x0,
    func = 0x0
  },
  ifa_local = 1040230592,
  ifa_address = 1040230592,
  ifa_mask = 16777215,
  ifa_broadcast = 4278233280,
  ifa_scope = 0 '\000',
  ifa_prefixlen = 24 '\030',
  ifa_flags = 640,
  ifa_label = "eth0\000\000\000\000\000\000\000\000\000\000\000",
  ifa_valid_lft = 0,
  ifa_preferred_lft = 0,
  ifa_cstamp = 4294674072,
  ifa_tstamp = 4294674128
}

in_ifaddr構造体のifa_address/ifa_mask の値1040230592/16777215をそれぞれ16進数に変換すると0x3E00A8C0/0xffffffとなります。
これらのバイトオーダーをひっくり返すと 0xc0A8003E/0xffffff00となり、10進数ドット表記に変換すると、IPアドレス/ネットマスクは192.168.0.62/255.255.255.0であることが判ります。これらはip addrコマンドの出力結果と一致しています。

ドライバの情報のダンプ

eth0のnet_device構造体からnetdev_opsのポインタffff8d8d7614ec00をnet_device_ops構造体にマッピングして内容をダンプします。

crash> struct net_device.netdev_ops ffff8d8d75ccd000
  netdev_ops = 0xffffffffc02d4520
crash> struct  net_device_ops ffffffffc02d4520
struct net_device_ops {
  ndo_init = 0x0,
  ndo_uninit = 0x0,
  ndo_open = 0xffffffffc02d29e0,
  ndo_stop = 0xffffffffc02d0550,
  ndo_start_xmit = 0xffffffffc02d1260,
  {
    ndo_select_queue = 0x0,
    __UNIQUE_ID_rh_kabi_hide51 = {
      ndo_select_queue = 0x0
    },
    {<No data fields>}
  },
  ndo_change_rx_flags = 0x0,
  ndo_set_rx_mode = 0xffffffffc02d2aa0,
  ndo_set_mac_address = 0xffffffffc02d0cf0,
  ndo_validate_addr = 0xffffffff8c282b50,
  ndo_do_ioctl = 0x0,
  ndo_set_config = 0x0,
  ndo_change_mtu_rh74 = 0x0,
  ndo_neigh_setup = 0x0,
  ndo_tx_timeout = 0x0,
  {
    ndo_get_stats64 = 0xffffffffc02d03d0,
    __UNIQUE_ID_rh_kabi_hide52 = {
      ndo_get_stats64 = 0xffffffffc02d03d0
    },
    {<No data fields>}
  },
  ndo_get_stats = 0x0,
  ndo_vlan_rx_add_vid = 0xffffffffc02d0e60,
  ndo_vlan_rx_kill_vid = 0xffffffffc02d0ef0,
  ndo_poll_controller = 0xffffffffc02d0140,
  ndo_netpoll_setup = 0x0,
  ndo_netpoll_cleanup = 0x0,
  ndo_busy_poll = 0x0,
  ndo_set_vf_mac = 0x0,
  ndo_set_vf_vlan_rh73 = 0x0,
  ndo_set_vf_tx_rate = 0x0,
  ndo_set_vf_spoofchk = 0x0,
  ndo_get_vf_config = 0x0,
  ndo_set_vf_link_state = 0x0,
  ndo_set_vf_port = 0x0,
  ndo_get_vf_port = 0x0,
  ndo_setup_tc_rh72 = 0x0,
  ndo_fcoe_enable = 0x0,
  ndo_fcoe_disable = 0x0,
  ndo_fcoe_ddp_setup = 0x0,
  ndo_fcoe_ddp_done = 0x0,
  ndo_fcoe_ddp_target = 0x0,
  ndo_fcoe_get_hbainfo = 0x0,
  ndo_fcoe_get_wwn = 0x0,
  ndo_rx_flow_steer = 0x0,
  ...

  以降省略

試しにイーサネットドライバのopenハンドラ ndo_openを逆アセンブルしてみます。

crash> dis ffffffffc02d29e0 10
0xffffffffc02d29e0 <virtnet_open>:      nopl   0x0(%rax,%rax,1) [FTRACE NOP]
0xffffffffc02d29e5 <virtnet_open+5>:    push   %rbp
0xffffffffc02d29e6 <virtnet_open+6>:    mov    %rsp,%rbp
0xffffffffc02d29e9 <virtnet_open+9>:    push   %r15
0xffffffffc02d29eb <virtnet_open+11>:   lea    0x900(%rdi),%r15
0xffffffffc02d29f2 <virtnet_open+18>:   push   %r14
0xffffffffc02d29f4 <virtnet_open+20>:   lea    0x8c0(%rdi),%r14
0xffffffffc02d29fb <virtnet_open+27>:   push   %r13
0xffffffffc02d29fd <virtnet_open+29>:   push   %r12
0xffffffffc02d29ff <virtnet_open+31>:   mov    %rdi,%r12
crash>

シンボルがvirtnet_openとなっていることから、イーサネットドライバはvirtnetであることが判ります。

その他の情報のダンプ

まず、カーネルソースを調査して出力すべき制御情報としてどのようなものがあるかを確認します。次にそれらをリンクしているポインタやテーブル管理リストが格納されているグローバル変数を特定し、順番にたどっていくことで、最終的に確認したい情報が表示できるはずです。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?