2015/11/18

FreeRADIUS 3.0.4 で DHCP サーバを立てる時に気をつけること

FreeRADIUS 3.0.4 を使って DHCP を使っているとたまに SEGV することがあったのでその原因を探ってみたメモ。
なんとなーく高負荷時くらいに発生するようですが、負荷が低い時にも発生するので core dump を取ってきちんと追ってみました。


環境

  • OS : CentOS 7.1.1503
  • FreeRADIUS : 3.0.4


abrtd の設定

SEGV だけじゃ原因が分からないのでまずは coredump を取るように設定。
abrt なるものがあるらしいので使ってみる
  • # yum install -y abrt-cli
  • # vim /etc/security/limits.d/core.conf
    • *       hard        core        unlimited
    • *       soft        core        unlimited
    • くらいに設定。 core のファイルを作るように。
  • # vim /etc/sysctl.d/50-core.conf
    • kernel.core_uses_pid = 1
    • fs.suid_dumpable = 2
    • Storage = both
    • くらいで。
  • # vim /etc/sytemd/system.conf
    • DumpCore を yes,  DefaultLimitCORE を unlimited に
  • # systemctl enable abrtd
  • # reboot

これで core が取れるようになった。
coredump の場所は abrt が設定するようで /var/spool/abrt/ くらい。


coredump から原因を追う

  • # gdb /var/spool/abrt/ccpp-2015-11-04-09\:39\:18-2478/coredump
    • すると debuginfo が無いので入れろと言ってくる
  • # yum --enablerepo='*debug*' install /usr/lib/debug/.build-id/9c/9089cc84962eae11b31e65e92af30874f83b2c
    • 言われた通りに打つと入る。便利。
どうやら
  • #0  fr_packet_cmp (a=0x7f068be885a0, b=0xcb6b5c9a1101f601) at src/lib/packet.c:45
とかで SEGV している様子。

back trace は

  • #0  fr_packet_cmp (a=0x7f068be885a0, b=0xcb6b5c9a1101f601) at src/lib/packet.c:45
  • #1  0x00007f06894c9eea in rbtree_find (tree=0x7f068bed05a0, data=data@entry=0x7fff68b1cdb8) at src/lib/rbtree.c:517
  • #2  0x00007f06894d0f8f in fr_packet_list_yank (pl=0x7f068bed0fc0, request=0x7f068be885a0) at src/lib/packet.c:559
  • #3  0x00007f0689b5e1ff in request_done (request=request@entry=0x7f068be3d070, action=action@entry=2) at src/main/process.c:636
  • #4  0x00007f0689b5e6ad in request_process_timer (request=0x7f068be3d070) at src/main/process.c:908
  • #5  0x00007f0689b624bd in request_common (request=request@entry=0x7f068be3d070, action=<optimized out>) at src/main/process.c:1122
  • #6  0x00007f0689b632a5 in request_cleanup_delay (request=0x7f068be3d070, action=<optimized out>) at src/main/process.c:1176
  • #7  0x00007f06894d1a1f in fr_event_run (el=el@entry=0x7f068bbb4f00, when=when@entry=0x7fff68b1d040) at src/lib/event.c:260
  • #8  0x00007f06894d1fd9 in fr_event_loop (el=0x7f068bbb4f00) at src/lib/event.c:482
  • #9  0x00007f0689b63d61 in radius_event_process () at src/main/process.c:4983
  • #10 0x00007f0689b42758 in main (argc=3, argv=<optimized out>) at src/main/radiusd.c:584

とか。

request の管理は rbtree でやっていて、その rbtree で find や insert する時の比較ルーチンで落ちてるみたいです。
他の dump もいくつか見るとやっぱり rbtree 周り。
request_done すると request_hash から外す時に rbtree_insert とかするっぽいですね。
コードを読んでいくと nodup なるものが true ならそのルーチンは呼ばれないみたいです

git grep nodup すると読んだ時の最新の 3.0.9 では DHCP は default で nodup が true の様子
そして CentOS7 の yum で入る 3.0.4 では nodup は true では無いみたいです。

ということで
/etc/raddb/sites-enabled/dhcp
performance { skip_duplicate_checks = yes }
を追加しておしまい。しばらく運用しても SEGV することはなくなりました。


再現してみる

とりあえず運用している radiusd は落ちなくなったのですが原因が本当にコレかチェックしてみます。


再現環境

  • OS : OSX Yosemite 10.10.5
  • Docker : 1.9
  • docker-machine : 0.5.0
  • Virtualbox : 5.0.10 r104061


再現方法

前回作った FreeRADIUS のサーバで試してみます。
Docker で container を上げると '02:42:ac:11:00:??' の mac address が自動生成されるようなのでそれに対して適当にダミーのデータを投入します
  • 256.times{|n| IpAddress.create!(address:n, mac_address: format('02:42:ac:11:00:%02x', n))}
この状態で dhclient だけが入っている container を100個くらい起動。
そうすると SEGV しました。数度再現するのでこれが原因っぽいです。
そして nodup を設定してまた負荷をかけてみます。
今度は SEGV しません。原因はやっぱりこれのようですね。


まとめ

FreeRADIUS 3.0.4 で DHCP サーバを上げる場合は nodup の設定をしておきましょう。
CentOS 7 の yum で入る FreeRADIUS は 3.0.4 です。
また、FreeRADIUS 3.0.8 ではデフォルトで有効なようなので、この設定はしばらくすると必要無くなります。


参考URL

0 件のコメント:

コメントを投稿