# 通知設計書 15-状態変更

## 概要

本ドキュメントは、FreeBSDカーネルにおけるCARP状態変更通知の設計を記述する。CARP（Common Address Redundancy Protocol）プロトコルの状態遷移が発生した際にdevctl(4)サブシステムを通じてユーザーランドに通知を送信する仕組みについて定義する。

### 本通知の処理概要

CARP状態変更通知は、CARPプロトコルの状態が遷移（INIT、BACKUP、MASTER間の遷移）した際にcarp_set_state()関数内でdevctl_notifyにより発行されるカーネル通知である。

**業務上の目的・背景**：CARPはネットワークインターフェースの冗長性を提供するプロトコルであり、複数のホスト間でIPアドレスの共有と自動フェイルオーバーを実現する。状態遷移（特にBACKUPからMASTERへの遷移やその逆）はサービスの可用性に直接影響するため、ユーザーランドのモニタリングシステムやフェイルオーバースクリプトがリアルタイムに状態変化を検知する必要がある。

**通知の送信タイミング**：carp_set_state()関数内で、CARPソフトコンテキスト（carp_softc）の状態（sc_state）が前回と異なる新しい状態に遷移した時点で送信される。

**通知の受信者**：devctl(4)デバイスをオープンしているユーザーランドプロセス。主にdevd(8)デーモンが受信し、フェイルオーバースクリプトの実行などを行う。

**通知内容の概要**：システム名「CARP」、サブシステム名として「{vhid}@{インターフェース名}」、タイプとして状態名（"INIT"、"BACKUP"、"MASTER"のいずれか）、データなし（NULL）が通知される。

**期待されるアクション**：devd(8)がCARP状態遷移を検知し、MASTERへの遷移時にはサービスの起動、BACKUPへの遷移時にはサービスの停止、アラートの発報などを行う。

## 通知種別

カーネルdevctl通知（devctl_notify経由）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（devctl(4)キュー経由） |
| 優先度 | 通常 |
| リトライ | なし |

### 送信先決定ロジック

devctl(4)デバイスファイル(/dev/devctl)をオープンしているすべてのプロセスに対してブロードキャスト送信される。

## 通知テンプレート

### devctl通知の場合

| 項目 | 内容 |
|-----|------|
| システム名 | CARP |
| サブシステム名 | {vhid}@{インターフェース名} |
| タイプ | INIT / BACKUP / MASTER |
| データ | NULL（データなし） |

### 本文テンプレート

```
!system=CARP subsystem={vhid}@{if_name} type=INIT
!system=CARP subsystem={vhid}@{if_name} type=BACKUP
!system=CARP subsystem={vhid}@{if_name} type=MASTER
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| vhid | CARP仮想ホストID | sc->sc_vhid | Yes |
| if_name | 親インターフェース名 | if_name(sc->sc_carpdev) | Yes |
| state | 遷移先状態名 | carp_states[state] | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| カーネル内部 | carp_set_state()呼び出し | sc->sc_stateと新stateが異なる場合 | CARP状態遷移時 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| 同一状態 | 新しい状態が現在の状態と同一の場合、通知は発行されない（2610行目のif文） |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[carp_set_state呼び出し] --> B[CARP_LOCK_ASSERT]
    B --> C{sc_state != state?}
    C -->|No| D[何もしない]
    C -->|Yes| E[subsys文字列生成 vhid@if_name]
    E --> F[CARP_LOG 状態遷移ログ出力]
    F --> G[sc_state = state]
    G --> H[devctl_notify CARP/subsys/state/NULL]
    H --> I[終了]
    D --> I
```

## データベース参照・更新仕様

該当なし（カーネル内メモリ構造体の操作のみ）

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| carp_softc構造体 | CARP情報の参照 | sc_vhid、sc_state、sc_carpdev等 |

### テーブル別参照項目詳細

#### carp_softc構造体

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| sc_vhid | 仮想ホストID | CARPグループの識別 |
| sc_state | 現在の状態 | 状態遷移の判定（0:INIT, 1:BACKUP, 2:MASTER） |
| sc_carpdev | 親インターフェースのifnet | インターフェース名の取得 |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| carp_softc構造体 | UPDATE | sc_stateを新しい状態に更新 |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| devctl送信失敗 | devctlキューが満杯 | 通知は破棄される |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | なし |
| リトライ間隔 | 該当なし |
| リトライ対象エラー | 該当なし |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし |
| 1日あたり上限 | 制限なし |

### 配信時間帯

制限なし。

## セキュリティ考慮事項

- devctl(4)デバイスへのアクセスにはroot権限が必要
- CARPの状態遷移情報は冗長構成の状態を示すため、セキュリティ上の配慮が必要
- carp_set_state()はCARP_LOCK_ASSERTにより排他制御されている

## 備考

- carp_set_state()関数はsys/netinet/ip_carp.cの2605行目に定義されている
- devctl_notify()呼び出しは2622行目で行われる
- CARP状態は"INIT"(0)、"BACKUP"(1)、"MASTER"(2)の3種類（ip_carp.hの171行目で定義）
- サブシステム名は「{vhid}@{if_name}」形式で、IFNAMSIZ+5バイトのバッファが使用される
- CARPのVHID（仮想ホストID）の最大値は255（CARP_MAXVHID）

---

## コードリーディングガイド

本通知を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

CARPプロトコルの内部構造とCARP状態の定義を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ip_carp.h | `sys/netinet/ip_carp.h` | CARP_STATES定義（171行目: "INIT", "BACKUP", "MASTER"）、CARP_MAXVHID |
| 1-2 | ip_carp.c | `sys/netinet/ip_carp.c` | carp_softc構造体（95行目付近: sc_carpdev, sc_vhid, sc_state等） |

**読解のコツ**: CARPの状態は整数値（0, 1, 2）として管理され、carp_states配列で文字列にマッピングされる。carp_set_state()内でローカルに宣言される。

#### Step 2: エントリーポイントを理解する

carp_set_state()がCARP状態遷移とdevctl通知の中心関数である。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ip_carp.c | `sys/netinet/ip_carp.c` | carp_set_state()関数（2605-2624行目） |

**主要処理フロー**:
1. **2608行目**: CARP_LOCK_ASSERTでロック保持を確認
2. **2610行目**: sc->sc_state != stateの判定（同一状態なら何もしない）
3. **2611行目**: carp_states配列の宣言
4. **2614-2615行目**: subsys文字列の生成（"vhid@if_name"形式）
5. **2617-2618行目**: CARP_LOGで状態遷移ログを出力
6. **2620行目**: sc->sc_state = state（状態の更新）
7. **2622行目**: devctl_notify("CARP", subsys, carp_states[state], NULL)

#### Step 3: carp_set_state()の呼び出し元を理解する

どのような状況でCARP状態が遷移するかを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ip_carp.c | `sys/netinet/ip_carp.c` | carp_master_down()、carp_send_ad()等からの呼び出し |

### プログラム呼び出し階層図

```
[CARP状態遷移トリガー]
    |
    +-- carp_master_down()  [マスターダウン検出]
    |      +-- carp_set_state(sc, MASTER, ...)
    |
    +-- carp_send_ad()  [アドバタイズメント送信]
    |      +-- carp_set_state(sc, BACKUP, ...)
    |
    +-- carp_sc_state()  [リンク状態変化]
    |      +-- carp_set_state(sc, INIT, ...)
    |
    +-- carp_set_state() [sys/netinet/ip_carp.c:2605]
           |
           +-- devctl_notify("CARP", subsys, carp_states[state], NULL)
```

### データフロー図

```
[入力]                       [処理]                          [出力]

carp_softc (sc)   --->  carp_set_state()            --->  devctl(4)キュー
新しい状態(state)        |                              |
遷移理由(reason)         +-- 状態比較                    +-- devd(8)
                         +-- subsys文字列生成
                         +-- sc_state更新
                         +-- devctl_notify
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| ip_carp.c | `sys/netinet/ip_carp.c` | ソース | carp_set_state()の実装、devctl_notify呼び出し |
| ip_carp.h | `sys/netinet/ip_carp.h` | ヘッダー | CARP_STATES定義、CARP_MAXVHID等の定数 |
| ip_carp_nl.h | `sys/netinet/ip_carp_nl.h` | ヘッダー | CARPのNetlink関連定義 |
| devctl.h | `sys/sys/devctl.h` | ヘッダー | devctl_notify()のプロトタイプ |
| if_var.h | `sys/net/if_var.h` | ヘッダー | ifnet構造体の定義（sc_carpdevの型） |
