Skip to content

Instantly share code, notes, and snippets.

@hkwi
Last active December 19, 2015 04:48
Show Gist options
  • Save hkwi/5899404 to your computer and use it in GitHub Desktop.
Save hkwi/5899404 to your computer and use it in GitHub Desktop.

openflow 1.3 日本語訳 6.3.4 multiple controllers

6.3.4 複数コントローラ

スイッチはコントローラ 1 つだけと通信チャンネルを確立しても構いませんが、 コントローラ複数と確立しても構いません。 例えば 1 つめのコントローラ自体が失われたあるいは接続が失われた場合でも OpenFlow で動作し続けることができるといったように、 複数コントローラ存在することで、より良い信頼性が得られます。 コントローラ間の切り替えは全てコントローラ側で管理されますので、 エラーから高速に回復したり負荷分散の制御をしたりできます。 スイッチの管理に関するコントローラ間の調停方法については、本仕様のスコープ外で、 コントローラ自身で行われるコントローラ間引継ぎを同期させるのを手助けするところ までが、複数コントローラの機能自体のゴールです。 複数コントローラの機能は、コントローラのフェイルオーバーやロードバランスについて言及しているだけで、 (コントローラの)仮想化といったものは OpenFlow プロトコルの範囲外です。

OpenFlow 制御が開始すると、スイッチは設定された全コントローラに接続し、 それら全ての接続を同時に維持し続けなければなりません。 多くのコントローラは「コントローラ→スイッチ」コマンドを送信しても構いませんが、 これらのコマンドに対する応答やエラーは、それぞれのコマンドに紐付いた接続上で (スイッチから)送信されなければなりません。 非同期メッセージは複数コントローラに送信する必要があるでしょう。 つまり、適切な OpenFlow チャンネルごとにメッセージを複製し、 準備できた各コントローラ接続に順次送信します。

コントローラのデフォルト role は OFPCR_ROLE_EQUAL です。 このロールではコントローラはスイッチにフルアクセスでき、 また同時に、他の同じロールのコントローラと同等の位置づけになります。 デフォルトでは、スイッチの非同期メッセージ(packet-in や flow-removed など)は 全て受信することになります。 コントローラは「コントローラ→スイッチ」コマンドを送信し、スイッチの状態を変更できます。 スイッチは、コントローラ間の調停やリソース共有などは何も行いません。

コントローラは OFPR_ROLE_SLAVE へのロール変更リクエストを出せます。 このロールではコントローラは、スイッチに対して読み出し専用アクセスになります。 スイッチはデフォルトでは、ポートステータスメッセージ以外の非同期メッセージを受信しません。 また、パケット送信したりスイッチの状態を変化させるような「コントローラ→スイッチ」 コマンドの実行は拒否されます。 例えば OFPT_PACKET_OUT, OFPT_FLOW_MOD, OFPT_GROUP_MOD, OFPT_PORT_MOD, OFPT_TABLE_MOD リクエストや、中身が空でない OFPMP_TABLE_FEATURES マルチパート リクエストは拒否されます。 コントローラがこれらのコマンドを送信した場合、スイッチは typeOFPET_BAD_REQUESTcodeOFPBRC_IS_SLAVEOFPT_ERROR メッセージを返さなければなりません。 OFPT_ROLE_REQUEST, OFPT_SET_ASYNC やデータ問い合わせのみの OFPT_MULTIPPART_REQUEST といった他の「コントローラ→スイッチ」メッセージは 通常通り処理されるはずです。

コントローラは OFPT_ROLE_MASTER へのロール変更リクエストを出せます。 このロールは OFPCR_ROLE_EQUAL と似ていてスイッチに対してフルアクセスになります。 違う点は、このロールのコントローラがただひとつになることをスイッチが保障する点です。 コントローラが OFPCR_ROLE_MASTER にロールを変更すると、スイッチ側では OFPCR_ROLE_MASTER で接続している全コントローラを OFPCR_ROLE_SLAVE に変更します。OFPCR_ROLE_EQUAL のロールのコントローラには影響ありません。 このロール変更をスイッチが実行した際には、ロール変更が起こったコントローラ (ほとんどの場合接続性が失われているコントローラ)に対してはメッセージが 生成されません(訳注:??)。

各コントローラは OFPT_ROLE_REQUEST でスイッチとのロールをやりとりできます ( 7.3.9 参照)し、 スイッチは各コントローラ接続のロールを記憶していなければなりません。 メッセージ中の generation_id が現在値であれば、コントローラは いつでもロールを変更できます。

コントローラが自分自身のロールを設定し、通常さらにコントローラ間の調整をする 必要があるといった master 選出プロセスを手助けする軽量な仕組みを、 ロール変更メッセージは提供しています。 スイッチはコントローラの状態をそれ自身で変更することはできませんので、 コントローラの状態変化は常に、コントローラ群からのリクエストの結果 引き起こされます。 Slave コントローラ、あるいは、Equal コントローラは自分自身を Master に 選出することができます。スイッチが同時に接続できるのは、 Equal 状態の複数コントローラ、Slave 状態の複数コントローラ、 Master 状態のコントローラひとつまでです。 (もしあれば)Master 状態のコントローラと Equal 状態の全コントローラは スイッチの状態を変更することができますので、これらのコントローラ間で スイッチを片寄せする仕組みはありません。 Master ロールのコントローラがスイッチの状態変更を行う唯一のコントローラで あるようにするためには、Equal 状態のコントローラは存在してはならず、 他のコントローラは全て Slave 状態にすべきです。

スイッチのどのタイプの非同期メッセージがOpenFlow チャンネル上で送信されるかを、 コントローラが制御することもできて、上記のデフォルトの動作を変更できます。 これは 非同期設定 メッセージ( 6.1.1 参照)を使って、 特定の OpenFlow チャンネルで、どのメッセージタイプを有効にするか、あるいは 無効にするかを列挙して設定できます( 7.3.10 参照)。 この機能を使うことで、コントローラはそれぞれ異なるメッセージを受け取ることができて、 Master 状態のコントローラは関知しない通知を選択的に無効にしたり、 Slave 状態のコントローラは監視したい通知を有効にしたりできます。

master/slave トランザクション中のメッセージ順序エラーを検出ため、 OFPT_ROLE_REQUEST メッセージは 64 bit の数値フィールド generation_id があり、master での順番を示しています。 master 選出メカニズムの一部では、コントローラ(やコントローラの代りに サードパーティ製品)が generation_id の割り当てと連携します。 generation_id は単調増加するカウンターです。 つまり例えば新しい master が選出されたなど、master 変更が起こるたびに 新しい(大きい)generation_id が割り当たります。 generation_id は wrap-around します。

OFPCR_ROLE_MASTER あるいは OFPCR_ROLE_SLAVE である OFPT_ROLE_REQUEST を受信した際は、スイッチはこれまでの最大値と メッセージ中の generation_id を比較します。 以前の値よりも小さい generation_id のついたメッセージは、 古すぎるとして破棄されます。 古すぎるメッセージを受信した場合は typeOFPET_ROLE_REQUESTcodeOFPRRFC_STALE のエラーメッセージをスイッチが返さなければなりません。

次の擬似コードは、スイッチが generation_id をどう扱うかを示しています:

スイッチ起動時

generation_is_defined = false;

OFPCR_ROLE_MASTER あるいは OFPCR_ROLE_SLAVEOFPT_ROLE_REQUEST を 受信し、その generation_idGEN_ID_X だった時

if (generation_is_defined AND distance(GEN_ID_X, cached_generation_id) < 0) {
  <discard OFPT_ROLE_REQUEST message>;
  <send an error message with code OFPRRFC_STALE>;
} else {
  cached_generation_id = GEN_ID_X;
  generation_is_defined = true;
  <process the message normally>;
}

ただし distance()Wrapping Sequence Number Distance で、次で 計算されるものです。

distance(a, b) := (int64_t)(a - b)

つまり distance() は符号なしシーケンス番号を二つの補数符号付数値として解釈して得られる差です。 ab より(周回の意味で)大きく「シーケンス空間の半分」以内にある場合に、正の値が得られます。 逆の場合(a < b)は負の値が得られます。

OFPT_ROLE_REQUEST のロールが OFPCR_ROLE_EQUAL の場合は、generation_id を無視しなければ なりません。 generation_id は master/slave トランザクションのレースコンディションの曖昧さを排除するために あります。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment