Kernelヘッダにbondingって何?って聞いてみた。

■bonding再考。

 bondingには選択肢が多い。
 冗長化するのだが「どんな冗長化をするか」という、
 考え方が異なるものなので結構複雑だったりする。

 ちなみに「broadcast mode」は仕様が不明だったり対向の条件が不明だったり、
 全スレーブに同じパケットを送信という昔のHUBのような特殊用途向けのモード。
 なるほど、確かに「Bonding Mode 3」を使っている人を見たことが無い。

■「Bonding Mode 1: fault-tolerance (active-backup)」については以前に試した。

 Squeezeでアクティブ/バックアップモードのbonding(teaming)を設定する
 http://d.hatena.ne.jp/labunix/20121005

 Active-Backup mode bond0の正常性確認
 http://d.hatena.ne.jp/labunix/20121007

 bondingのパラメータのテストに便利な方法
 http://d.hatena.ne.jp/labunix/20121217

■モジュールのロード、NICの設定でbondingモードと監視方法を指定する。
 「active-backup」ではMIIとARPの両方に対応している。
  その他付随するオプションを設定する。
 ※以下のコマンドの内、監視方法についてはそれぞれ別のシステムの実行結果。

$ grep bond /etc/modprobe.d/*
/etc/modprobe.d/aliases-bond.conf:alias bond0 bonding

$ grep mode /etc/network/interfaces
        bond-mode 1

$ grep -i mode /proc/net/bonding/bond0
Bonding Mode: fault-tolerance (active-backup)

$ grep -i "stat\|polling" /proc/net/bonding/bond0
MII Status: up
MII Polling Interval (ms): 0
ARP Polling Interval (ms): 15000
MII Status: up
MII Status: up
MII Status: up

$ grep -i "stat\|polling" /proc/net/bonding/bond0
MII Status: up
MII Polling Interval (ms): 2000
MII Status: up
MII Status: up

■まずはモジュールの種類はドライバ。ドライバと言えばカーネル。

$ dpkg -L linux-source-2.6.32 | grep bz2
/usr/src/linux-source-2.6.32.tar.bz2

$ tar jtf /usr/src/linux-source-2.6.32.tar.bz2 | grep bonding | grep "h\$\|txt\$"
linux-source-2.6.32/drivers/net/bonding/bond_3ad.h
linux-source-2.6.32/drivers/net/bonding/bond_alb.h
linux-source-2.6.32/drivers/net/bonding/bonding.h
linux-source-2.6.32/Documentation/networking/bonding.txt
linux-source-2.6.32/include/linux/if_bonding.h

■なるほど、各モードのモジュールがある。

$ cd /usr/src/ && sudo tar jxvf linux-source-2.6.32.tar.bz2
$ ls /usr/src/linux-2.6-2.6.32/drivers/net/bonding/ | grep .h | column
bond_3ad.h      bond_alb.h      bonding.h

■以下の3種類は別途定義されている。

 bond_3ad	802.3ad(LACP)に準拠したリンクアグリケーション
 balance-tlb	送信のみスレーブの負荷分散
 balance-alb	送受信共にスレーブの負荷分散

$ grep "LACP" /usr/src/linux-2.6-2.6.32/drivers/net/bonding/bond_3ad.h  | sed s/")"/"&\n"/g
#define PKT_TYPE_LACPDU         cpu_to_be16(ETH_P_SLOW)

#define MULTICAST_LACPDU_ADDR    {0x01, 0x80, 0xC2, 0x00, 0x00, 0x02}
#define AD_LACP_SLOW 0
#define AD_LACP_FAST 1
        AD_RX_LACP_DISABLED,  // rx Machine
        AD_TYPE_LACPDU = 1,    // type lacpdu
// Link Aggregation Control Protocol(LACP)
 data unit structure(43.4.2.2 in the 802.3ad standard)

        u8 subtype;                  // = LACP(= 0x01)

$ grep "define.*tlb" /usr/src/linux-2.6-2.6.32/drivers/net/bonding/bond_alb.h
#define SLAVE_TLB_INFO(slave) ((slave)->tlb_info)

■ということはヘッダに定義があって、定義があるなら大文字のはず。

$ find linux-source-2.6.32/ -type f -name "*bonding*.h" -print
linux-source-2.6.32/include/linux/if_bonding.h
linux-source-2.6.32/drivers/net/bonding/bonding.h

■共通点として、ローカルでインクルードされている
 2種類のヘッダの3つのモードについてはARP監視が使えない。

$ grep "include \""  /usr/src/linux-2.6-2.6.32/drivers/net/bonding/bonding.h
#include "bond_3ad.h"
#include "bond_alb.h"

■ヘッダの定義で「BOND_MODE」がモード番号に紐付いていることが分かる。

$ grep define linux-source-2.6.32/include/linux/if_bonding.h | grep MODE
#define BOND_MODE_ROUNDROBIN    0
#define BOND_MODE_ACTIVEBACKUP  1
#define BOND_MODE_XOR           2
#define BOND_MODE_BROADCAST     3
#define BOND_MODE_8023AD        4
#define BOND_MODE_TLB           5
#define BOND_MODE_ALB           6 /* TLB + RLB (receive load balancing) */

■LINKの状態は4種類ある。
 ※「FAIL」と「DOWN」の違いは、おそらく監視のタイムアウトと関係するのだろうけど、
 詳しい事は今のところ分からない。

$ grep define linux-source-2.6.32/include/linux/if_bonding.h | grep LINK
#define BOND_LINK_UP    0           /* link is up and running */
#define BOND_LINK_FAIL  1           /* link has just gone down */
#define BOND_LINK_DOWN  2           /* link has been down for too long time */
#define BOND_LINK_BACK  3           /* link is going back */

■STATEはActive/Backup。
 以下の4種類はその性質上、Active/Backup方式を取らないので、受信はスイッチの設定依存となる。

 balance-rr	送信のみ全スレーブを順に使用(ラウンドロビン)
 balance-xor	送信のみ送信元と送信先のMACアドレスを元に送信スレーブを決定する負荷分散。
 broadcast	全スレーブに同一パケットを送信。
 802.3ad	IEEE 802.3ad(LACP)に準拠したリンクアグリゲーションを行う。

$ grep define linux-source-2.6.32/include/linux/if_bonding.h | grep STATE
#define BOND_STATE_ACTIVE       0   /* link is active */
#define BOND_STATE_BACKUP       1   /* link is backup */

■以下はSockI/Oコントロール。

$ grep define linux-source-2.6.32/include/linux/if_bonding.h | grep SIOC
#define BOND_ENSLAVE_OLD                (SIOCDEVPRIVATE)
#define BOND_RELEASE_OLD                (SIOCDEVPRIVATE + 1)
#define BOND_SETHWADDR_OLD              (SIOCDEVPRIVATE + 2)
#define BOND_SLAVE_INFO_QUERY_OLD       (SIOCDEVPRIVATE + 11)
#define BOND_INFO_QUERY_OLD             (SIOCDEVPRIVATE + 12)
#define BOND_CHANGE_ACTIVE_OLD          (SIOCDEVPRIVATE + 13)
#define BOND_CHECK_MII_STATUS   (SIOCGMIIPHY)

$ grep "SIOCDEVPRIVATE\|SIOCGMIIPHY" linux-source-2.6.32/include/linux/sockios.h
#define SIOCGMIIPHY     0x8947          /* Get address of MII PHY in use. */
#define SIOCDEVPRIVATE  0x89F0  /* to 89FF */

■MIIは「Media Independent Interface」の略で、MAC/PHYインターフェイスは
 用語としては10M/100Mbpsを指し、1000MbpsはGMII「gigabit media independent interface」。
 10GbpsだとXGMIIとか、MACサービスインターフェイスやMACサービスとかはアーキテクチャのお話。

 (OS上の共通のインターフェイスという意味では、
  イーサネットの種類が変わっても端末側の変更は不要というMIIの性質上、
  SIOCGMII*を指すのが実質GMII/XGMIIでも良い気はするが、詳しい事は分からない。)

 LANのMAC(Media Access Control/媒体アクセス制御)層と物理層(physical layer)との間で読み書きされる。
 データリンク層はL2(OSI参照モデルレイヤー2)で、上記のMACとLLC(Logical Link Control=/論理リンク制御)で構成される。

$ grep MII linux-source-2.6.32/include/linux/sockios.h
#define SIOCGMIIPHY     0x8947          /* Get address of MII PHY in use. */
#define SIOCGMIIREG     0x8948          /* Read MII PHY register.       */
#define SIOCSMIIREG     0x8949          /* Write MII PHY register.      */

■「PRIVATE」の名の通り、16種類「0x89F0〜0x89FF」が装置に依存して再定義される。
 私の知る限りのお手本は「ethernet.h」でしょうか。

$ grep -B 11 SIOCDEVPRIVATE linux-source-2.6.32/include/linux/sockios.h
/* Device private ioctl calls */

/*
 *      These 16 ioctls are available to devices via the do_ioctl() device
 *      vector. Each device should include this file and redefine these names
 *      as their own. Because these are device dependent it is a good idea
 *      _NOT_ to issue them to random objects and hope.
 *
 *      THESE IOCTLS ARE _DEPRECATED_ AND WILL DISAPPEAR IN 2.5.X -DaveM
 */

#define SIOCDEVPRIVATE  0x89F0  /* to 89FF */

$ grep 'SIOCDEVPRIVATE+' linux-source-2.6.32/arch/cris/include/asm/ethernet.h
#define SET_ETH_SPEED_10        SIOCDEVPRIVATE+1        /* 10 Mbps */
#define SET_ETH_SPEED_100       SIOCDEVPRIVATE+2        /* 100 Mbps. */
#define SET_ETH_DUPLEX_AUTO     SIOCDEVPRIVATE+3        /* Auto neg duplex */
#define SET_ETH_DUPLEX_HALF     SIOCDEVPRIVATE+4        /* Full duplex */
#define SET_ETH_DUPLEX_FULL     SIOCDEVPRIVATE+5        /* Half duplex */
#define SET_ETH_ENABLE_LEDS     SIOCDEVPRIVATE+6        /* Enable net LEDs */
#define SET_ETH_DISABLE_LEDS    SIOCDEVPRIVATE+7        /* Disable net LEDs */
#define SET_ETH_AUTONEG         SIOCDEVPRIVATE+8

■SockI/Oコントロールは物理インターフェイスに関する設定なので、
 他にも例えば以下のような箇所で登場します。

$ sudo ifenslave -v -a | grep SIOC | grep -v HWADDR
The result of SIOCGIFFLAGS on lo is 49.
The result of SIOCGIFADDR is 00.00.7f.00.
The result of SIOCGIFFLAGS on eth0 is 1043.
The result of SIOCGIFADDR is 00.00.ffffffc0.ffffffa8.
The result of SIOCGIFFLAGS on eth1 is 1043.
The result of SIOCGIFADDR is 00.00.ffffffac.10.
The result of SIOCGIFFLAGS on bond0 is 1443.
The result of SIOCGIFADDR is 00.00.ffffffc0.ffffffa8.

$ grep define /usr/src/linux-source-2.6.32/include/linux/sockios.h | grep "SIOCGIF"
#define SIOCGIFNAME     0x8910          /* get iface name               */
#define SIOCGIFCONF     0x8912          /* get iface list               */
#define SIOCGIFFLAGS    0x8913          /* get flags                    */
#define SIOCGIFADDR     0x8915          /* get PA address               */
#define SIOCGIFDSTADDR  0x8917          /* get remote PA address        */
#define SIOCGIFBRDADDR  0x8919          /* get broadcast PA address     */
#define SIOCGIFNETMASK  0x891b          /* get network PA mask          */
#define SIOCGIFMETRIC   0x891d          /* get metric                   */
#define SIOCGIFMEM      0x891f          /* get memory address (BSD)     */
#define SIOCGIFMTU      0x8921          /* get MTU size                 */
#define SIOCGIFENCAP    0x8925          /* get/set encapsulations       */
#define SIOCGIFHWADDR   0x8927          /* Get hardware address         */
#define SIOCGIFSLAVE    0x8929          /* Driver slaving support       */
#define SIOCGIFINDEX    0x8933          /* name -> if_index mapping     */
#define SIOGIFINDEX     SIOCGIFINDEX    /* misprint compatibility :-)   */
#define SIOCGIFPFLAGS   0x8935
#define SIOCGIFCOUNT    0x8938          /* get number of devices */
#define SIOCGIFBR       0x8940          /* Bridging support             */
#define SIOCGIFTXQLEN   0x8942          /* Get the tx queue length      */
#define SIOCGIFMAP      0x8970          /* Get device parameters        */
#define SIOCGIFVLAN     0x8982          /* 802.1Q VLAN support          */

■さて少しスイッチ側の設定について。
 EtherChannelを設定するときに、インタフェースに対してチャネル・グループ番号を設定するアレです。
 Catalyst間で推奨されるPAgP、つまりCISCO以外のスイッチは通常、「LACP」か「mode on」のはずです。

 ・PAgP(Port Aggregation Protocol)
	※Cisco独自のEtherChannelのネゴシエーションプロトコル
	 Cisco独自なので、PAgPの対向はPAgPでチャネルを形成。

 ・LACP(Link Aggregation Control Protocol)
	※IEEE802.3で定義された業界標準のEtherChannelのネゴシエーションプロトコル
	 ポートのSpeedやDuplex、VLAN番号、トランキングステータスなどの条件に基づいてチャネルを形成。

	 Acitve/Active、Active/Passiveでのチャネルの形成は可能だがPassive/Passiveは不可。
	 (LACPのネゴシエーションを開始せず、受信するLACPパケットに応答するのみ。
	  LACPパケット伝送を抑えるモードなので、考えれば当然の組み合わせ。)

 mode on
	※EtherChannelを形成する際にネゴシーエーションを行わずに強制的にEtherChannelを形成
	 「mode on」の対向は「mode on」である必要がある。
	 強制の他の言い回しは固定。スイッチメーカによって何故か説明が異なる。

	 EtherChannelを動的なリンクアグリゲーションとしたり、

■まとめ1
 BONDING MODEは7種類あって、4以上はMII監視が使えない。

$ grep "define .*MODE" /usr/src/linux-source-2.6.32/include/linux/if_bonding.h | \
  sed s/".*define "//g | \
  awk '{if ($2>3) print $0,"/* No MII */"; else print $0}'
BOND_MODE_ROUNDROBIN    0
BOND_MODE_ACTIVEBACKUP  1
BOND_MODE_XOR           2
BOND_MODE_BROADCAST     3
BOND_MODE_8023AD        4 /* No MII */
BOND_MODE_TLB           5 /* No MII */
BOND_MODE_ALB           6 /* TLB + RLB (receive load balancing) */ /* No MII */

■まとめ2
 自身の負荷や障害を監視して切り替わる場合は優先度が指定できる。
 基本的にスイッチ設定が不要だが、受信の負荷や障害を監視しないbalance-tlbの場合のみ、
 受信時はスイッチの設定に依存する。

$ grep "define .*MODE" /usr/src/linux-source-2.6.32/include/linux/if_bonding.h | \
  sed s/".*define "//g | \
  awk '{if ($2==1 || $2>5) print $0,"/* No Switch Settings & Active/Primary */"; \
  else {if ($2==5) print $0,"/* Need Recieve Switch settings & Active/Primary */";else print $0}}'
BOND_MODE_ROUNDROBIN    0
BOND_MODE_ACTIVEBACKUP  1 /* No Switch Settings & Active/Primary */
BOND_MODE_XOR           2
BOND_MODE_BROADCAST     3
BOND_MODE_8023AD        4
BOND_MODE_TLB           5 /* Need Recieve Switch settings & Active/Primary */
BOND_MODE_ALB           6 /* TLB + RLB (receive load balancing) */ /* No Switch Settings & Active/Primary */


■まだまだある。。。

 トランキングについてはまた次の機会に。

 bonding機能紹介と展望
 http://osdn.jp/event/kernel2005/pdf/nec.pdf