# 通知設計書 12-ルート変更

## 概要

本ドキュメントは、FreeBSDカーネルにおけるIFNETルート変更通知の設計を記述する。ルーティングテーブルにおけるアドレスの追加・削除時にdevctl(4)サブシステムを通じてユーザーランドに通知を送信する仕組みについて定義する。

### 本通知の処理概要

IFNETルート変更通知は、ネットワークインターフェースにIPアドレス（IPv4/IPv6）が追加または削除された際に、rt_addrmsg()関数を通じてdevctl_notifyで発行されるカーネル通知である。

**業務上の目的・背景**：ネットワークインターフェースへのアドレス割り当て変更は、ルーティング、ファイアウォール、DNSなどのネットワークサービスに直接影響するため、ユーザーランドのネットワーク管理デーモンがリアルタイムにアドレス変更を検知する必要がある。DHCPクライアントやネットワーク管理ツールがこの通知を利用してネットワーク構成を動的に更新する。

**通知の送信タイミング**：rt_addrmsg()関数が呼び出された時点で送信される。RTM_ADD（アドレス追加）またはRTM_DELETE（アドレス削除）コマンドに応じて、ADDR_ADDまたはADDR_DELとして通知される。

**通知の受信者**：devctl(4)デバイスをオープンしているユーザーランドプロセス。主にdevd(8)デーモンが受信する。

**通知内容の概要**：システム名「IFNET」、サブシステム名としてインターフェース名（if_xname）、タイプ「ADDR_ADD」または「ADDR_DEL」、データとしてアドレス文字列（address=xxx）が通知される。

**期待されるアクション**：devd(8)やネットワーク管理デーモンがアドレス変更を検知し、ルーティングテーブルの再計算、DNSの更新、関連サービスの再構成などを行う。

## 通知種別

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

## 送信仕様

### 基本情報

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

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

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

## 通知テンプレート

### devctl通知の場合

| 項目 | 内容 |
|-----|------|
| システム名 | IFNET |
| サブシステム名 | {インターフェース名 (if_xname)} |
| タイプ | ADDR_ADD または ADDR_DEL |
| データ | address={IPアドレス文字列} |

### 本文テンプレート

```
!system=IFNET subsystem={ifp->if_xname} type=ADDR_ADD address={addr}
!system=IFNET subsystem={ifp->if_xname} type=ADDR_DEL address={addr}
```

### 添付ファイル

該当なし（カーネル通知のため添付ファイルの概念はない）

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| ifp->if_xname | インターフェース名 | ifa->ifa_ifp->if_xname | Yes |
| address | IPアドレス文字列 | inet_ntoa_r()またはip6_sprintf()で変換 | Yes |
| cmd | 操作種別 | RTM_ADDまたはRTM_DELETE | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| カーネル内部 | rt_addrmsg()呼び出し | AF_INETまたはAF_INET6のアドレス変更 | アドレスの追加または削除時 |
| ioctl操作 | SIOCAIFADDR等 | アドレス設定ioctl経由 | ifconfig等によるアドレス設定 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| 非INET/INET6ファミリ | AF_INETでもAF_INET6でもないアドレスファミリの場合、devctl通知は発行されない |
| カーネルコンパイルオプション | INETまたはINET6が有効でない場合、対応するブロックはコンパイルされない |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[rt_addrmsg呼び出し] --> B[EVENTHANDLER_DIRECT_INVOKE]
    B --> C{アドレスファミリ判定}
    C -->|AF_INET| D[inet_ntoa_rでアドレス文字列化]
    C -->|AF_INET6| E[ip6_sprintfでアドレス文字列化]
    C -->|その他| F[devctl通知なし]
    D --> G{cmd判定}
    E --> G
    G -->|RTM_ADD| H[devctl_notify IFNET/if_xname/ADDR_ADD/address=addr]
    G -->|RTM_DELETE| I[devctl_notify IFNET/if_xname/ADDR_DEL/address=addr]
    H --> J[rtsock_addrmsg呼び出し]
    I --> J
    F --> J
    J --> K[終了]
```

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

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

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| ifaddr構造体 | アドレス情報の参照 | ifa->ifa_addr、ifa->ifa_ifp |
| sockaddr_in/in6 | IPアドレスの取得 | sa->sin_addr / IFA_IN6(ifa) |

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

#### ifaddr構造体

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| ifa_addr | アドレス情報 | 対象アドレスを指定 |
| ifa_ifp | インターフェースポインタ | インターフェース名の取得用 |

### 更新テーブル一覧

該当なし（通知の発行のみで、データの更新は上位の呼び出し元で行われる）

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| devctl送信失敗 | devctlキューが満杯 | 通知は破棄される（カーネル側ではエラーハンドリングなし） |

### リトライ仕様

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

## 配信設定

### レート制限

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

### 配信時間帯

制限なし。カーネルイベント発生時に即座に通知される。

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

- devctl(4)デバイスへのアクセスにはroot権限が必要
- IPアドレス情報が通知データに含まれるが、devctlへのアクセス制御により保護される
- IPv6アドレスはip6_sprintf()で文字列化され、INET6_ADDRSTRLEN以内に制限される

## 備考

- rt_addrmsg()関数はsys/net/route.cの611行目に定義されている
- IPv4の場合は632行目、IPv6の場合は643行目でdevctl_notifyが呼び出される
- V_rt_add_addr_allfibs設定により全FIBへの通知制御が行われる（648行目）
- この通知は通知一覧では「ルート変更」として分類されているが、実際にはアドレスの追加・削除通知（ADDR_ADD/ADDR_DEL）である

---

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

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

### 推奨読解順序

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

ifaddr構造体とsockaddr構造体がアドレス情報を保持しており、これらの理解が前提となる。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | if_var.h | `sys/net/if_var.h` | ifaddr構造体のifa_addr、ifa_ifpフィールド |
| 1-2 | in.h | `sys/netinet/in.h` | sockaddr_in構造体のsin_addrフィールド |
| 1-3 | in6_var.h | `sys/netinet6/in6_var.h` | IFA_IN6マクロの定義 |

**読解のコツ**: FreeBSDではアドレスファミリによって異なるsockaddr構造体が使用される。sa_familyフィールドで判別し、適切なキャストを行う。

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

rt_addrmsg()関数がルーティングメッセージの発行とdevctl通知の両方を担う。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | route.c | `sys/net/route.c` | rt_addrmsg()関数（611-651行目） |

**主要処理フロー**:
1. **618行目**: cmdのバリデーション（RTM_ADDまたはRTM_DELETE）
2. **623行目**: EVENTHANDLER_DIRECT_INVOKE(rt_addrmsg, ifa, cmd)
3. **626-634行目**: AF_INETの場合のdevctl_notify呼び出し
4. **637-645行目**: AF_INET6の場合のdevctl_notify呼び出し
5. **650行目**: rtsock_addrmsg()の呼び出し

#### Step 3: devctl通知の詳細を理解する

devctl_notifyの引数と通知フォーマットを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | route.c | `sys/net/route.c` | devctl_notify呼び出し（632-633行目、643-644行目） |

**主要処理フロー**:
- **630行目**: inet_ntoa_r()によるIPv4アドレスの文字列化
- **631行目**: "address=%s"フォーマットでstrbuf生成
- **632-633行目**: devctl_notify("IFNET", ifp->if_xname, "ADDR_ADD"/"ADDR_DEL", strbuf)

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

```
rt_addrmsg() [sys/net/route.c:611]
    |
    +-- EVENTHANDLER_DIRECT_INVOKE(rt_addrmsg)
    |
    +-- [AF_INET] inet_ntoa_r()
    |      +-- devctl_notify("IFNET", if_xname, "ADDR_ADD"/"ADDR_DEL", ...)
    |
    +-- [AF_INET6] ip6_sprintf()
    |      +-- devctl_notify("IFNET", if_xname, "ADDR_ADD"/"ADDR_DEL", ...)
    |
    +-- rtsock_addrmsg()
```

### データフロー図

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

ifaddr (ifa)      --->  rt_addrmsg()               --->  devctl(4)キュー
RTM_ADD/DELETE            |                              |
                          +-- アドレス文字列化            +-- devd(8)
                          +-- devctl_notify              |
                          +-- rtsock_addrmsg        --->  routing socket
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| route.c | `sys/net/route.c` | ソース | rt_addrmsg()の実装、devctl_notify呼び出し |
| if_var.h | `sys/net/if_var.h` | ヘッダー | ifaddr、ifnet構造体の定義 |
| in.h | `sys/netinet/in.h` | ヘッダー | sockaddr_in構造体、inet_ntoa_r()プロトタイプ |
| in6_var.h | `sys/netinet6/in6_var.h` | ヘッダー | IFA_IN6マクロ |
| devctl.h | `sys/sys/devctl.h` | ヘッダー | devctl_notify()のプロトタイプ |
| route_ctl.h | `sys/net/route/route_ctl.h` | ヘッダー | ルート制御関連定義 |
