Table of Contents
대부분의 데스크탑 네트워크 칩셋은 Realtek 을 사용한다. 그런데, 이것을 리눅스에서 사용할때에는 가끔 문제를 발생시킨다. 검색을 해보니까 상당히 많은 사례가 있다. 나의 경우에는 Oracle Linux 10.1 배포판에 UEK 커널을 사용할 경우에 문제가 생겼다.
문제
문제의 증상은 네트워크가 다운된다는데 있다. 다운이 되지 않는다고 하더라도 속도가 제대로 나지 않는 경우가 많았다. 이러한 경우에 무엇이 문제인지 찾기가 매우 어렵다. 네트워크가 아예 안되면 문제원인이 명확하지만, 아예 되지 않는 건 아니고 속도가 느리거나 간할적으로 끊겼다가 다시 연결되는 등의 문제가 반복된다면 원인찾기가 쉽지가 않다.
Realtek 랜카드
사용하는 Realtek 랜카드는 ASRock AB350 Pro4 에 내장된 것이다. 리눅스에서는 다음과 같이 보인다.
|
1 2 3 4 |
09:00.0 Ethernet controller [0200]: Realtek Semiconductor Co., Ltd. RTL8111/8168/8211/8411 PCI Express Gigabit Ethernet Controller [10ec:8168] (rev 11) Subsystem: ASRock Incorporation Motherboard (one of many) [1849:8168] Kernel driver in use: r8169 Kernel modules: r8169 |
Oracle 10.1 UEK 커널 드라이버는 r8169 로 잡힌다. 결론은 이게 문제다.
로그
원인을 파악하기 위해서 리눅스 서버의 각종 로그를 살펴봤는데, 커널 부팅 메시지에 다음과 같은 메시지가 출력되었다.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
[ 11.086875] ------------[ cut here ]------------ [ 11.086877] WARNING: CPU: 9 PID: 1 at lib/timerqueue.c:38 timerqueue_add+0xc3/0xd0 [ 11.086883] Modules linked in: rfkill nfnetlink_cttimeout openvswitch nsh nf_conncount psample ib_core nf_conntrack_netbios_ns nf_conntrack_broadcast nft_fib_inet nft_fib_ipv4 nft_fib_ipv6 nft_fib nft_reject_inet nf_reject_ipv4 nf_reject_ipv6 nft_reject nft_ct nft_chain_nat nf_nat nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 vfat fat snd_hda_codec_realtek snd_hda_codec_generic snd_hda_scodec_component snd_hda_codec_hdmi amd_atl intel_rapl_msr intel_rapl_common snd_hda_intel snd_intel_dspcfg edac_mce_amd snd_intel_sdw_acpi snd_hda_codec kvm_amd snd_hda_core snd_hwdep wmi_bmof snd_pcm snd_timer kvm snd soundcore pcspkr i2c_piix4 k10temp i2c_smbus wmi gpio_amdpt gpio_generic sg fuse loop xfs sd_mod crct10dif_pclmul crc32_pclmul ahci ghash_clmulni_intel nvme r8169 sha512_ssse3 libahci sha256_ssse3 nvme_core libata sha1_ssse3 ccp realtek nvme_keyring sp5100_tco nvme_auth dm_mod aesni_intel gf128mul [ 11.086952] CPU: 9 UID: 0 PID: 1 Comm: systemd Not tainted 6.12.0-204.92.4.2.el10uek.x86_64 #2 [ 11.086955] Hardware name: To Be Filled By O.E.M. AB350 Pro4/AB350 Pro4, BIOS P10.50 03/19/2026 [ 11.086957] RIP: 0010:timerqueue_add+0xc3/0xd0 [ 11.086959] Code: 48 89 1f 48 89 5f 08 48 89 fe 48 89 df e8 35 c5 ff ff 48 85 db 5b 40 0f 95 c5 89 e8 5d 31 d2 31 c9 31 f6 31 ff e9 6d 78 02 00 <0f> 0b e9 48 ff ff ff 66 0f 1f 44 00 00 90 90 90 90 90 90 90 90 90 [ 11.086961] RSP: 0018:ffffd53640354d80 EFLAGS: 00010012 [ 11.086964] RAX: ffff8ebfdeea8400 RBX: ffff8eb8c8ce4b80 RCX: 0000000000000000 [ 11.086966] RDX: 0000000000000001 RSI: ffff8eb8c8ce4b80 RDI: ffff8ebfdeea8460 [ 11.086967] RBP: 0000000294cab8fe R08: 0000000000000000 R09: 0000000000000000 [ 11.086969] R10: 0000000000000000 R11: 0000000000000000 R12: ffff8eb8c8ce4b80 [ 11.086970] R13: ffff8ebfdea28440 R14: 0000000000000003 R15: ffff8ebfdeea8400 [ 11.086972] FS: 00007fc36469a980(0000) GS:ffff8ebfdee80000(0000) knlGS:0000000000000000 [ 11.086974] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 11.086976] CR2: 0000557ac5368030 CR3: 000000010e586000 CR4: 0000000000350ef0 [ 11.086978] Call Trace: [ 11.086981] <IRQ> [ 11.086984] __hrtimer_start_range_ns+0x174/0x210 [ 11.086992] hrtimer_start_range_ns+0x77/0xd0 [ 11.086996] napi_complete_done+0x165/0x220 [ 11.087001] rtl8169_poll+0x5b/0x90 [r8169] [ 11.087008] __napi_poll+0x2b/0x163 [ 11.087011] net_rx_action+0x343/0x430 [ 11.087013] ? srso_return_thunk+0x5/0x5f [ 11.087022] handle_softirqs+0xea/0x2b8 [ 11.087027] __irq_exit_rcu+0xab/0xd0 [ 11.087029] common_interrupt+0x85/0xa0 [ 11.087033] </IRQ> [ 11.087034] <TASK> [ 11.087035] asm_common_interrupt+0x26/0x40 [ 11.087038] RIP: 0010:bit_putcs+0x316/0x5e0 [ 11.087041] Code: 48 39 fe 75 ef 48 01 c3 4d 39 dc 75 91 8b 4c 24 48 48 8b 7c 24 30 89 4c 24 0c 48 8d 74 24 68 48 8b 87 c0 03 00 00 48 8b 40 68 <e8> 85 f1 7f 00 41 8b b5 10 02 00 00 8b 4c 24 0c 48 8b 5c 24 40 41 [ 11.087043] RSP: 0018:ffffd5364004f750 EFLAGS: 00000246 [ 11.087045] RAX: ffffffffada11f00 RBX: ffff8eb8cbff2f1d RCX: 000000000000000d [ 11.087046] RDX: ffff8eb8cbff2fec RSI: ffffd5364004f7b8 RDI: ffff8eb8cc21f000 [ 11.087047] RBP: 000000000000000d R08: 0000000000000010 R09: 0000000000000200 [ 11.087048] R10: 00000000000001ff R11: ffff8eb8c19f8cfa R12: ffff8eb8c19f8cfa [ 11.087050] R13: ffff8eb8c02bf000 R14: 0000000000000001 R15: 0000000000000000 [ 11.087053] ? __pfx_drm_fbdev_shmem_defio_imageblit+0x10/0x10 [ 11.087065] fbcon_putcs+0x13d/0x190 [ 11.087068] ? __pfx_bit_putcs+0x10/0x10 [ 11.087072] fbcon_redraw+0x103/0x260 [ 11.087077] fbcon_scroll+0x17a/0x1c0 [ 11.087080] con_scroll+0xfa/0x210 [ 11.087084] lf+0xb5/0xc0 [ 11.087086] ? atomic_notifier_call_chain+0x39/0x50 [ 11.087089] handle_ascii.isra.0+0x165/0x290 [ 11.087092] do_con_trol+0x4d/0x640 [ 11.087095] do_con_write+0x371/0x541 [ 11.087099] ? console_unlock+0x9d/0x140 [ 11.087104] con_write+0x13/0x50 [ 11.087107] do_output_char+0x18b/0x1f0 [ 11.087110] n_tty_write+0x171/0x3c0 [ 11.087113] ? __pfx_woken_wake_function+0x10/0x10 [ 11.087118] iterate_tty_write+0x114/0x2a0 [ 11.087121] ? srso_return_thunk+0x5/0x5f [ 11.087125] file_tty_write.isra.0+0x6f/0x92 [ 11.087128] do_iter_readv_writev+0x123/0x230 [ 11.087134] vfs_writev+0x17b/0x3c0 [ 11.087142] ? do_writev+0x86/0x160 [ 11.087144] do_writev+0x86/0x160 [ 11.087148] do_syscall_64+0x90/0x1c0 [ 11.087152] ? srso_return_thunk+0x5/0x5f [ 11.087154] ? arch_exit_to_user_mode_prepare.isra.0+0x1e/0xf0 [ 11.087157] ? srso_return_thunk+0x5/0x5f [ 11.087159] ? syscall_exit_to_user_mode+0x36/0x190 [ 11.087162] ? srso_return_thunk+0x5/0x5f [ 11.087164] ? do_syscall_64+0xb6/0x1c0 [ 11.087166] ? srso_return_thunk+0x5/0x5f [ 11.087168] ? do_sys_openat2+0xa2/0xe0 [ 11.087172] ? srso_return_thunk+0x5/0x5f [ 11.087174] ? arch_exit_to_user_mode_prepare.isra.0+0x1e/0xf0 [ 11.087176] ? srso_return_thunk+0x5/0x5f [ 11.087178] ? syscall_exit_to_user_mode+0x36/0x190 [ 11.087181] ? srso_return_thunk+0x5/0x5f [ 11.087183] ? do_syscall_64+0xb6/0x1c0 [ 11.087184] ? do_user_addr_fault+0x37c/0x630 [ 11.087188] ? srso_return_thunk+0x5/0x5f [ 11.087191] entry_SYSCALL_64_after_hwframe+0x76/0x7e [ 11.087194] RIP: 0033:0x7fc36412d754 [ 11.087208] Code: 00 f7 d8 64 89 01 48 83 c8 ff c3 66 2e 0f 1f 84 00 00 00 00 00 90 f3 0f 1e fa 80 3d 75 09 0d 00 00 74 13 b8 14 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 54 c3 0f 1f 00 48 83 ec 28 89 54 24 1c 48 89 [ 11.087209] RSP: 002b:00007ffd72b27408 EFLAGS: 00000202 ORIG_RAX: 0000000000000014 [ 11.087212] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007fc36412d754 [ 11.087213] RDX: 0000000000000005 RSI: 00007ffd72b27450 RDI: 0000000000000082 [ 11.087214] RBP: 00007ffd72b27500 R08: 0000000000000000 R09: 00007ffd72b27480 [ 11.087215] R10: 00007ffd72b27460 R11: 0000000000000202 R12: 0000000000000082 [ 11.087217] R13: 0000557ac553f2d0 R14: 0000000000000040 R15: 0000000000000003 [ 11.087222] </TASK> [ 11.087223] ---[ end trace 0000000000000000 ]--- |
보면 뭐가 뭔지 보이지 않는다. AI 에 질의한 결과는 다음과 같았다.
- 로그 분석: 무엇이 문제인가요?
– 발생 지점 (rtl8169_poll): 메인보드(ASRock AB350 Pro4)에 내장된 리얼텍 꽃게칩 랜카드 드라이버(r8169)가 작동하는 과정입니다.
– 오류 원인 (timerqueue_add): 리얼텍 드라이버가 네트워크 패키지를 처리(NAPI)하면서 타이머(hrtimer)를 시작하려는데, 이미 큐에 등록된 타이머를 중복 등록하거나 타이머 메모리가 오염되면서 커널 경고(WARNING)가 발생했습니다.
– 결과: 이 에러가 발생하면 리눅스 커널은 시스템 붕괴를 막기 위해 네트워크 드라이버(r8169)를 강제로 일시 정지(Freeze)시키거나 먹통으로 만듭니다. 재부팅하면 타이머가 초기화되어 잠시 작동하다가, 트래픽이 발생하여 이 버그를 다시 건드리는 순간 네트워크가 차단되는 것입니다.
드라이버가 문제가 된다는게 결론이다.
r8168 드라이버 설치
이 문제를 해결하는 가장 쉬운 방법은 최신의 드라이버를 설치하면 된다. 최신 드라이버는 Realtek 홈페이지에서 다운로드 가능하다. 홈페이지에가면 종류별로 있는데, r8168 로 표기된 것을 다운로드 하면 된다.
- GBE Ethernet LINUX driver r8168 for kernel up to 7.1
한가지 고려해야 하는 것이, Oracle 10.1 UEK 커널은 6.x 이다. 홈페이지에는 7.1 이라고 되어 있는데도 6.x 에서도 설치가 가능하다.
또, 한가지 더 있는데 드라이버 설치는 dkms 으로 해야 한다. 문제는 Oracle 10.1 에는 dkms 명령어가 존재하지 않는다. 이를 해결하기 위해서 epel-release 저장소를 설치하고 dnf 명령어를 이용하면 손쉽게 설치할 수 있다. 또, 컴파일을 하기 위해 컴파일러와 의존성 패키지를 함께 설치해 준다.
|
1 2 3 |
sudo dnf install -y epel-release sudo dnf install -y gcc make elfutils-libelf-devel tar bzip2 sudo dnf install -y dkms |
커널 모듈을 설치하기 위해서는 kernel-headers, kernel-devel 를 함께 설치해 준다.
|
1 2 |
sudo dnf install kernel-headers sudo dnf install -y kernel-uek-devel-$(uname -r) |
uek 커널의 경우에 devel 패키지명이 다르다는 걸 명심해야 한다.
압축해제
다운로드 받은 최신 드라이버를 /usr/src 디렉토리에 압축 해제해 준다.
|
1 2 |
tar xvjf r8168-8.056.02.tgz -C /usr/src cd /usr/src/r8168-8.056.02 |
dkms.conf
이제 dkms 커널 모듈 컴파일을 하기 위해서 dkms.conf 파일을 다음과 같이 작성해 준다.
|
1 2 3 4 5 6 7 8 9 10 |
PACKAGE_NAME="r8168" PACKAGE_VERSION="8.056.02" BUILT_MODULE_NAME[0]="r8168" BUILT_MODULE_LOCATION[0]="src/" DEST_MODULE_LOCATION[0]="/kernel/drivers/net/ethernet/realtek" AUTOINSTALL="yes" # 최신 6.x 커널 및 DKMS 빌드용 타깃 매핑 표준 명령어 MAKE[0]="make -C /lib/modules/${kernelver}/build M=/usr/src/r8168-8.056.02/src modules" CLEAN="make -C /lib/modules/${kernelver}/build M=/usr/src/r8168-8.056.02/src clean" |
이제 컴파일을 해야 하는데, 쉘 환경변수를 다음과 같이 등록해준다.
|
1 2 3 4 5 |
cd /usr/src R8168_DIR="$(ls -d r8168-* | head -n 1)" R8168_VER="${R8168_DIR#r8168-}" echo "Using version: ${R8168_VER}" |
이제 dkms 를 이용한 모듈 컴파일 설치 해준다.
|
1 2 3 4 5 6 7 |
KVER="$(uname -r)" sudo dkms add -m r8168 -v "${R8168_VER}" sudo dkms build -m r8168 -v "${R8168_VER}" -k "${KVER}" sudo dkms install -m r8168 -v "${R8168_VER}" -k "${KVER}" dkms status |
r8169 블랙리스트 작성
이제 r8169 모듈을 부팅시 로딩하지 못하도록 블랙리스트를 작성한다.
|
1 |
echo 'blacklist r8169' | sudo tee /etc/modprobe.d/blacklist-r8169.conf |
initramfs 재빌드
이제 initramfs 를 재빌드 해준다.
|
1 |
sudo dracut -f "/boot/initramfs-$(uname -r).img" "$(uname -r)" |
성공하면 reboot 을 해준다.
확인
재부팅을 하고 난 후에 제대로 r8168모듈이 올라왔는지를 확인해야 한다.
|
1 2 3 |
lsmod | egrep 'r8168|r8169' lspci -nnk | grep -A3 -i ethernet ethtool -i enp9s0 |
위 세가지 방법으로 확인이 가능하다. ethtool 을 이용한 방법으로 확인해본 결과는 다음과 같다.
|
1 2 3 4 5 6 7 8 9 10 11 |
]$ sudo ethtool -i enp9s0 driver: r8168 version: 8.056.02-NAPI firmware-version: expansion-rom-version: bus-info: 0000:09:00.0 supports-statistics: yes supports-test: no supports-eeprom-access: no supports-register-dump: yes supports-priv-flags: no |