# 機能設計書 40-NetLink

## 概要

本ドキュメントは、FreeBSDカーネルにおけるユーザ空間-カーネル間のネットワーク構成通信プロトコルであるNetlinkの機能設計書である。

### 本機能の処理概要

NetlinkはLinux由来のユーザ空間-カーネル間通信プロトコルであり、FreeBSDに移植された。ネットワークインタフェースの構成、ルーティングテーブルの操作、リンク状態の通知など、ネットワーク関連のカーネル情報へのアクセスを統一的なソケットインタフェースで提供する。

**業務上の目的・背景**：従来のioctl/PF_ROUTEソケットに代わる、より構造化されたカーネル-ユーザ間通信プロトコルを提供する。Linux互換性の向上と、ネットワーク構成操作のプログラマビリティの改善が目的である。ifconfigやrouteコマンドのバックエンドとしても使用される。

**機能の利用シーン**：ifconfigコマンドのNetlinkバックエンド、routeコマンドのNetlink対応、ネットワークモニタリングツール、ルーティングデーモン（FRR等）との連携、システムイベント通知で利用される。

**主要な処理内容**：
1. Netlinkソケット（AF_NETLINK）の管理
2. プロトコルハンドラの登録・管理（NETLINK_ROUTE, NETLINK_GENERIC等）
3. Netlinkメッセージの送受信・パース
4. メッセージライターによるレスポンス構築
5. グループ通知（マルチキャスト）
6. VNETサポート
7. ルーティング操作（NETLINK_ROUTE）
8. 汎用Netlinkプロトコル（NETLINK_GENERIC）
9. システムイベント通知

**関連システム・外部連携**：ifconfig（Netlinkバックエンド）、route（Netlinkバックエンド）、カーネルネットワークサブシステム、ルーティングテーブル

**権限による制御**：AF_NETLINKソケットの作成は一般的には可能だが、書き込み操作（ルーティング変更等）にはroot権限が必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | カーネル内部プロトコルのため該当する画面なし |

## 機能種別

カーネルプロトコル（ユーザ-カーネル間通信 / ネットワーク構成操作）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| プロトコル | int | Yes | NETLINK_ROUTE / NETLINK_GENERIC等 | 登録済みプロトコル |
| メッセージタイプ | uint16 | Yes | RTM_NEWROUTE / RTM_GETLINK等 | プロトコル毎の有効タイプ |
| メッセージフラグ | uint16 | No | NLM_F_REQUEST / NLM_F_DUMP等 | 有効なフラグ組み合わせ |
| ペイロード | TLV | Yes | Netlinkアトリビュート（TLV形式） | 有効なアトリビュート |

### 入力データソース

AF_NETLINKソケット（ユーザ空間アプリケーション）、カーネル内部通知

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| Netlinkメッセージ | nlmsghdr + payload | 応答データ（ルート情報、インタフェース情報等） |
| グループ通知 | nlmsghdr | マルチキャストグループへの通知メッセージ |
| エラー応答 | nlmsgerr | エラーコードとオリジナルメッセージの先頭 |

### 出力先

AF_NETLINKソケット（ユーザ空間）

## 処理フロー

### 処理シーケンス

```
1. Netlinkモジュールの初期化
   └─ vnet_nl_init()でVNET毎の制御構造を初期化
2. プロトコルハンドラの登録
   └─ netlink_register_proto()でコールバック関数を登録
3. ユーザ空間からのソケット作成
   └─ socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)
4. メッセージ受信
   └─ nl_receive_message()でメッセージをパース
5. プロトコルハンドラ呼び出し
   └─ nl_handlers[proto].cb()で処理を委譲
6. レスポンス構築
   └─ nlmsg_add() / nlmsg_end() でメッセージを構築
7. レスポンス送信
   └─ nl_writer_unicast() / nl_writer_group()で配信
```

### フローチャート

```mermaid
flowchart TD
    A[モジュールロード] --> B[vnet_nl_init]
    B --> C[netlink_register_proto]
    C --> D[ユーザsocket AF_NETLINK]
    D --> E[sendmsg: Netlinkメッセージ送信]
    E --> F[nl_receive_message: パース]
    F --> G{プロトコル判定}
    G -->|NETLINK_ROUTE| H[ルーティングハンドラ]
    G -->|NETLINK_GENERIC| I[汎用ハンドラ]
    H --> J[nlmsg_add/end: レスポンス構築]
    I --> J
    J --> K[nl_writer_unicast: 応答送信]
    K --> L[ユーザrecvmsg]

    M[カーネルイベント] --> N[nl_writer_group: グループ通知]
    N --> O[全購読者に配信]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-40-01 | プロトコル最大数 | 最大20個のNetlinkプロトコルハンドラを登録可能（NL_MAX_HANDLERS=20） | 常時 |
| BR-40-02 | VNET対応 | 各VNETインスタンスが独立したNetlink制御構造を保持 | VNET環境 |
| BR-40-03 | グループ通知 | NLP_MAX_GROUPS（64の倍数）のマルチキャストグループをサポート | グループ操作時 |
| BR-40-04 | アンロード制限 | アクティブなソケットが存在する場合、モジュールのアンロード不可（EBUSY） | MOD_UNLOAD時 |

### 計算ロジック

特になし

## データベース操作仕様

該当なし

### 操作別データベース影響一覧

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| EINVAL | 無効プロトコル | 範囲外のプロトコル番号 | 有効なプロトコル番号を使用 |
| EPROTONOSUPPORT | 非対応 | 未登録のプロトコルハンドラ | モジュールのロード確認 |
| EBUSY | ビジー | アクティブソケット存在時のアンロード | ソケットクローズ後に再試行 |
| EPERM | 権限不足 | 非root権限での書き込み操作 | root権限で実行 |

### リトライ仕様

なし

## トランザクション仕様

各Netlinkメッセージの処理はアトミック。ダンプ操作（NLM_F_DUMP）は複数メッセージに分割されて返される。

## パフォーマンス要件

Netlinkメッセージのパースとレスポンス構築は効率的なTLV操作で実装されている。グローバルロック（nl_global_mtx）はプロトコルハンドラの登録/解除時のみ使用され、データパスへの影響は最小限。

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

- AF_NETLINKソケット作成は一般ユーザでも可能（情報取得のため）
- ルーティングテーブル変更等の書き込み操作にはroot権限が必要
- jail環境でのNetlinkアクセス制御（prison対応）
- VNET分離によるネットワーク名前空間の隔離

## 備考

FreeBSDのNetlink実装はLinuxのNetlinkプロトコルとの互換性を提供するが、FreeBSD固有の拡張も含む。netlink_snl.h等のSNL（Simple Netlink Library）ヘッダによりユーザ空間での使用が容易化されている。

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | netlink.h | `sys/netlink/netlink.h` | Netlinkメッセージヘッダ、プロトコル番号定義 |
| 1-2 | netlink_var.h | `sys/netlink/netlink_var.h` | struct nl_control（VNET制御構造）、struct nl_proto_handler |
| 1-3 | netlink_ctl.h | `sys/netlink/netlink_ctl.h` | カーネル内部制御API |

**読解のコツ**: nl_proto_handler配列がプロトコル番号に対するコールバック関数のテーブルである。NL_MAX_HANDLERS=20で最大20プロトコルをサポート。各VNETが独立したnl_control構造を持つ。

#### Step 2: モジュール初期化を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | netlink_module.c | `sys/netlink/netlink_module.c` | モジュール初期化/終了、VNET初期化、プロトコルハンドラ登録 |

**主要処理フロー**:
1. **54-56行目**: NL_MAX_HANDLERS=20、nl_handlers配列
2. **61-64行目**: VNET_DEFINE(struct nl_control, nl_ctl) - VNET毎の制御構造
3. **66-70行目**: nl_global_mtx - グローバルロック
4. **74-85行目**: vnet_nl_init() - VNET初期化（rm_init、リスト挿入）
5. **101-109行目**: nl_verify_proto() - プロトコル番号の検証
6. **117-129行目**: netlink_register_proto() - プロトコルハンドラ登録
7. **184-217行目**: netlink_modevent() - MOD_LOAD/MOD_UNLOAD処理

#### Step 3: ソケットドメインを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | netlink_domain.c | `sys/netlink/netlink_domain.c` | AF_NETLINKソケットの作成、送受信処理 |

**主要処理フロー**:
- **62-65行目**: NLP_MAX_GROUPS static_assert
- **67-74行目**: NLCTL_TRACKER/RLOCK/WLOCK マクロ
- **76-80行目**: nl_sendspace/nl_recvspace sysctl

#### Step 4: メッセージ処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | netlink_message_parser.c | `sys/netlink/netlink_message_parser.c` | メッセージパース処理 |
| 4-2 | netlink_message_writer.c | `sys/netlink/netlink_message_writer.c` | メッセージ構築処理 |
| 4-3 | netlink_io.c | `sys/netlink/netlink_io.c` | I/O処理 |

#### Step 5: ルーティングハンドラを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | netlink_route.c | `sys/netlink/netlink_route.c` | NETLINK_ROUTEプロトコルハンドラ |
| 5-2 | route/ | `sys/netlink/route/` | ルーティング関連サブモジュール |

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

```
netlink_modevent(MOD_LOAD) [netlink_module.c:184]
    +-- nl_osd_register()
    |
vnet_nl_init() [netlink_module.c:74]
    +-- rm_init(&V_nl_ctl.ctl_lock)
    +-- CK_LIST_INSERT_HEAD(&vnets_head)
    |
netlink_register_proto() [netlink_module.c:117]
    +-- nl_handlers[proto].cb = handler
    |
[ソケット操作]
socket(AF_NETLINK) → netlink_domain.c
    +-- nl_create() → PCB作成
    |
sendmsg() → nl_sosend()
    +-- nl_receive_message()
        +-- nlmsg_parse()
        +-- nl_handlers[proto].cb() → プロトコルハンドラ
            +-- [NETLINK_ROUTE]
            |   +-- netlink_route.c ハンドラ
            +-- [NETLINK_GENERIC]
                +-- netlink_generic.c ハンドラ
    |
    +-- nl_writer_unicast() / nl_writer_group()
        +-- recvmsg() でユーザ空間に配信
```

### データフロー図

```
[ユーザ空間]                    [カーネル]

socket(AF_NETLINK) ──────> nl_create()
    |
sendmsg(nlmsghdr) ───────> nl_receive_message()
                                |
                           nlmsg_parse() ──> TLV解析
                                |
                           nl_handlers[proto].cb()
                                |
                           処理（ルーティング/IF管理等）
                                |
                           nlmsg_add()/nlmsg_end()
                                |
                           nl_writer_unicast() ──> recvmsg()
                                |
[グループ通知]
カーネルイベント ────────> nl_writer_group()
                                |
                           全グループ購読者 ──> recvmsg()
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| netlink_module.c | `sys/netlink/netlink_module.c` | ソース | モジュール初期化・プロトコル登録 |
| netlink_domain.c | `sys/netlink/netlink_domain.c` | ソース | ソケットドメイン実装 |
| netlink_io.c | `sys/netlink/netlink_io.c` | ソース | I/O処理 |
| netlink_message_parser.c | `sys/netlink/netlink_message_parser.c` | ソース | メッセージパース |
| netlink_message_writer.c | `sys/netlink/netlink_message_writer.c` | ソース | メッセージ構築 |
| netlink_route.c | `sys/netlink/netlink_route.c` | ソース | NETLINK_ROUTEハンドラ |
| netlink_generic.c | `sys/netlink/netlink_generic.c` | ソース | NETLINK_GENERICハンドラ |
| netlink_sysevent.c | `sys/netlink/netlink_sysevent.c` | ソース | システムイベント通知 |
| netlink_glue.c | `sys/netlink/netlink_glue.c` | ソース | レガシーインタフェース連携 |
| netlink.h | `sys/netlink/netlink.h` | ヘッダ | Netlinkプロトコル定義 |
| netlink_var.h | `sys/netlink/netlink_var.h` | ヘッダ | 内部構造体定義 |
| netlink_snl.h | `sys/netlink/netlink_snl.h` | ヘッダ | SNL（Simple Netlink Library） |
| netlink_snl_route.h | `sys/netlink/netlink_snl_route.h` | ヘッダ | SNLルーティング拡張 |
| route/ | `sys/netlink/route/` | ディレクトリ | ルーティングサブモジュール |
