syncdがいつのまにか落っこちる件について

# syncdとは

SONiCはさまざまなソフトウェアの集合体で、ホワイトボックススイッチのハードウェアを制御しユーザトラフィックの転送やプロトコル処理など様々な機能を提供しています。

その中でも、パケット転送を司るハードウェアであるスイッチASICに様々な指示を送り込むプログラムがsyncdです。

SONiCは設定や状態など様々な情報をRedis DBに格納して管理しています。DBは複数あり、Config DB、State DB、App DBなどありますが、それらのなかでスイッチASICに送り込む指示を記録するASIC DBというものが存在していて、syncdはこのASIC DBの内容をスイッチASICに送り込むことで設定と実際の動作の同期を担っています。

# ASIC DBに書かれる内容

ASIC DBに書かれているスイッチASICへの指示内容は、Config DBに書かれているような人間が読んでわかる抽象度の高い設定を、細かい指示に分割したものと考えるのがいいと思います。

`/var/log/swss/sairedis.rec` を開くと、ASIC DBに書かれている内容の記録をうかがい知ることができます。下記に一部抜粋します。

```
2019-12-23.15:51:48.887171|#|logrotate on: /var/log/swss/sairedis.rec
2019-12-23.15:51:48.887221|a|INIT_VIEW
2019-12-23.15:51:50.399983|A|SAI_STATUS_SUCCESS
2019-12-23.15:51:50.416924|c|SAI_OBJECT_TYPE_SWITCH:oid:0x21000000000000|SAI_SWITCH_ATTR_INIT_SWITCH=true|SAI_SWITCH_ATTR_FDB_EVENT_NOTIFY=0x561e7c24b520|SAI_SWITCH_ATTR_PORT_STATE_CHANGE_NO
TIFY=0x561e7c24b530|SAI_SWITCH_ATTR_SWITCH_SHUTDOWN_REQUEST_NOTIFY=0x561e7c24b540|SAI_SWITCH_ATTR_SRC_MAC_ADDRESS=6C:B9:C5:16:88:CC
2019-12-23.15:51:50.417082|g|SAI_OBJECT_TYPE_SWITCH:oid:0x21000000000000|SAI_SWITCH_ATTR_DEFAULT_VIRTUAL_ROUTER_ID=oid:0x0
2019-12-23.15:51:52.233743|G|SAI_STATUS_SUCCESS|SAI_SWITCH_ATTR_DEFAULT_VIRTUAL_ROUTER_ID=oid:0x3000000000023
2019-12-23.15:51:52.233881|c|SAI_OBJECT_TYPE_ROUTER_INTERFACE:oid:0x60000000005b5|SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID=oid:0x3000000000023|SAI_ROUTER_INTERFACE_ATTR_TYPE=SAI_ROUTER_IN
TERFACE_TYPE_LOOPBACK
2019-12-23.15:51:52.247030|g|SAI_OBJECT_TYPE_SWITCH:oid:0x21000000000000|SAI_SWITCH_ATTR_CPU_PORT=oid:0x0
2019-12-23.15:51:52.249349|G|SAI_STATUS_SUCCESS|SAI_SWITCH_ATTR_CPU_PORT=oid:0x1000000000001
2019-12-23.15:51:52.249436|g|SAI_OBJECT_TYPE_SWITCH:oid:0x21000000000000|SAI_SWITCH_ATTR_NUMBER_OF_ACTIVE_PORTS=1
2019-12-23.15:51:52.249779|G|SAI_STATUS_SUCCESS|SAI_SWITCH_ATTR_NUMBER_OF_ACTIVE_PORTS=33
```

接頭辞に`SAI`と書かれた単語が数多く出てきますが、これはSwitch Abstraction InterfaceというAPI仕様に基づいた値であることを示しています。本稿ではSAIについて細かく説明しませんが、SAIのパラメータを用意してAPIを呼べば、スイッチASICの種類によらず設定が可能になるものと考えていただければと思います。

# syncdが落ちる?

前述の通り、syncdは設定と動作の同期をとる大切なプログラムです。常に動き続けるべき類のものであり、異常終了はすなわち動作不全につながると言っていいでしょう。しかし、実際にはsyncdがいつのまにかいなくなっているという事象に遭遇することがあります。

たとえば、MTUの設定をうっかり`910000`などとありえないサイズとして記述した場合、現在のSONiCでは事前のパラメータチェックでエラー扱いされず、syncdが`910000`をそのままSAIのパラメータとしてスイッチASICに指示を送り、結果としてSAIのエラーを受け取ります。

が、**syncdはSAIのエラーを受け取ると無条件に終了します**。

落ちているかどうかは、`show services`コマンドを実行するとわかります。syncd dockerが動いていると表示されましたか? どこにも見当たらなければ、落ちています。

syncd自身はASIC DBの中身についての検証を一切行わず、右から左にデータを渡すようにスイッチASICに指示を送り込みます。そこでエラーは受け取ることがないだろうという想定をしています。つまり、本来であればASIC DBに書き込む前の段階で値の正当性はチェックすべきということになるのですが、現時点ではそういうチェックはやられていないようです。

また、手元でVRF周りの設定などをやっていてsyncdが落ちて困っていたのですが、これは設定不備によるものではなく、SONiCの内部ロジックの関係で存在しないポートを削除するようASIC DBに情報が書き込まれているようで、その呼び出しがエラーになっていることが原因のようでした。

# とりあえず落ちないようにする

いずれにせよsyncdが落ちてしまうことは避けたいので、エラー即終了の処理を書き換えることにしました。

```diff
diff --git a/syncd/syncd.cpp b/syncd/syncd.cpp
index 9e221da..864cfd0 100644
--- a/syncd/syncd.cpp
+++ b/syncd/syncd.cpp
@@ -3254,7 +3254,7 @@ sai_status_t processEvent(
                 SWSS_LOG_ERROR("attr: %s: %s", fvField(v).c_str(), fvValue(v).c
_str());
             }

-            SWSS_LOG_THROW("failed to execute api: %s, key: %s, status: %s",
+            SWSS_LOG_ERROR("failed to execute api: %s, key: %s, status: %s",
                     op.c_str(),
                     key.c_str(),
                     sai_serialize_status(status).c_str());
```

`src/sonic-sairedis` ディレクトリでパッチを当てます。できあがったSONiCを使い、これまで落ちていた設定をそのまま適用してみたところ、syncdは落ちなくなりました。(`show services`コマンドで確認)

これでめでたしめでたし。というわけでもなく、エラーログ自体は記録されるので、設定不備がないかなどの確認は必要です。syncdが落ちる従来のコードのままでもエラーログに記録はされるので、パッチは気休めかもしれません。