Linux Kernel Network Stack

Linux カーネル ネットワークスタック 包括的技術ガイド

本ドキュメントは Linux カーネルのネットワークサブシステムを深掘りし、アーキテクチャの全体像から個々のコンポーネントの実装詳細、パフォーマンスチューニングまでを網羅的に解説する技術文書である。


目次

  1. ネットワークスタックアーキテクチャ概要
  2. ソケットレイヤーとソケットバッファ (sk_buff)
  3. TCP/IP 実装詳細
  4. TCP 輻輳制御アルゴリズム
  5. UDP 処理パス
  6. ルーティングサブシステムと FIB
  7. 近隣サブシステム (ARP/NDP)
  8. ネットワークデバイスドライバインターフェース (NAPI)
  9. XDP (eXpress Data Path)
  10. ネットワーク名前空間
  11. 仮想ネットワーキング
  12. ボンディングとチーミング
  13. トラフィック制御 (tc, qdisc)
  14. ソケットオプションとチューニング
  15. /proc/net/* と /sys/class/net/*
  16. ネットワークパフォーマンスチューニング
  17. ネットワーク診断・分析ツール
  18. まとめとベストプラクティス

1. ネットワークスタックアーキテクチャ概要

1.1 Linux ネットワークスタックの全体構造

Linux カーネルのネットワークスタックは、OSI参照モデルおよび TCP/IP モデルに沿って階層的に構成されている。ユーザー空間からハードウェアまでの全体像を以下に示す。

┌─────────────────────────────────────────────────────┐
│                  ユーザー空間                          │
│  ┌─────────────┐  ┌──────────┐  ┌───────────────┐   │
│  │ アプリケーション │  │  ライブラリ │  │ソケットAPI (BSD)│   │
│  └──────┬──────┘  └────┬─────┘  └───────┬───────┘   │
├─────────┼──────────────┼────────────────┼───────────┤
│         │     システムコール境界          │            │
│         ▼              ▼                ▼            │
│  ┌─────────────────────────────────────────────┐     │
│  │          ソケットレイヤー (L7-L5)             │     │
│  │   struct socket / struct sock               │     │
│  └─────────────────┬───────────────────────────┘     │
│                    │                                  │
│  ┌─────────────────▼───────────────────────────┐     │
│  │      トランスポートレイヤー (L4)               │     │
│  │   TCP / UDP / SCTP / DCCP / RAW             │     │
│  └─────────────────┬───────────────────────────┘     │
│                    │                                  │
│  ┌─────────────────▼───────────────────────────┐     │
│  │        ネットワークレイヤー (L3)               │     │
│  │   IPv4 / IPv6 / ルーティング / Netfilter     │     │
│  └─────────────────┬───────────────────────────┘     │
│                    │                                  │
│  ┌─────────────────▼───────────────────────────┐     │
│  │       データリンクレイヤー (L2)                │     │
│  │   ARP / NDP / ブリッジ / VLAN / tc           │     │
│  └─────────────────┬───────────────────────────┘     │
│                    │                                  │
│  ┌─────────────────▼───────────────────────────┐     │
│  │     デバイスドライバレイヤー (L1-L2)           │     │
│  │   NAPI / XDP / net_device                   │     │
│  └─────────────────┬───────────────────────────┘     │
│         カーネル空間  │                                │
├─────────────────────┼───────────────────────────────┤
│                    ▼                                  │
│  ┌─────────────────────────────────────────────┐     │
│  │           NIC ハードウェア                    │     │
│  └─────────────────────────────────────────────┘     │
└─────────────────────────────────────────────────────┘

1.2 パケット受信パスの詳細フロー

パケットが NIC に到着してからアプリケーションに届くまでのフローを詳細に追跡する。

NIC ハードウェア
    │
    ▼
[1] DMA によりパケットを Ring Buffer にコピー
    │
    ▼
[2] NIC がハードウェア割り込み (IRQ) を発行
    │
    ▼
[3] IRQ ハンドラ: napi_schedule() を呼び出し
    │  ※ ここで割り込みを無効化し NAPI ポーリングに移行
    │
    ▼
[4] NET_RX_SOFTIRQ (ソフト割り込み)
    │  net_rx_action() → napi_poll() → ドライバの poll 関数
    │
    ▼
[5] ドライバの poll 関数: sk_buff を割り当て、パケットデータを格納
    │  napi_gro_receive() → GRO (Generic Receive Offload) 処理
    │
    ▼
[6] netif_receive_skb() → __netif_receive_skb()
    │  ├── パケットタップ (tcpdump, AF_PACKET)
    │  ├── TC ingress 処理
    │  └── プロトコルハンドラへのディスパッチ
    │
    ▼
[7] L3: ip_rcv() → Netfilter PREROUTING
    │  → ip_rcv_finish() → ルーティング判定
    │
    ▼
[8] ローカル宛の場合: ip_local_deliver()
    │  → Netfilter INPUT → ip_local_deliver_finish()
    │
    ▼
[9] L4: tcp_v4_rcv() / udp_rcv()
    │  → ソケットルックアップ → ソケットバッファへの追加
    │
    ▼
[10] ソケットレイヤー: プロセスへの通知
     → wake_up_interruptible() / epoll_wait() 返却

1.3 パケット送信パスの詳細フロー

アプリケーション: send() / write() / sendmsg()
    │
    ▼
[1] ソケットレイヤー: sock_sendmsg()
    │  → inet_sendmsg() → プロトコル固有の送信関数
    │
    ▼
[2] L4: tcp_sendmsg() / udp_sendmsg()
    │  ├── TCP: セグメント化、シーケンス番号、ウィンドウ管理
    │  └── UDP: ヘッダ追加、チェックサム計算
    │
    ▼
[3] L3: ip_queue_xmit() / ip_push_pending_frames()
    │  ├── ルーティングルックアップ (FIB)
    │  ├── Netfilter OUTPUT フック
    │  ├── IP フラグメンテーション (必要な場合)
    │  └── Netfilter POSTROUTING フック
    │
    ▼
[4] L2: dev_queue_xmit()
    │  ├── TC egress 処理 (qdisc)
    │  ├── キューイング規律による制御
    │  └── dev_hard_start_xmit()
    │
    ▼
[5] ドライバ: ndo_start_xmit()
    │  → DMA マッピング → NIC の TX リングバッファに配置
    │
    ▼
[6] NIC ハードウェアがパケットを送信
    │
    ▼
[7] TX 完了割り込み → sk_buff の解放

1.4 カーネルソースコードの構成

ネットワークスタックのソースコードは主に以下のディレクトリに配置されている。

linux/
├── net/                          # プロトコル実装
│   ├── core/                     # コアネットワーキング
│   │   ├── dev.c                 # net_device 管理
│   │   ├── skbuff.c              # sk_buff 操作
│   │   ├── sock.c                # ソケットコア
│   │   ├── filter.c              # BPF フィルタ
│   │   └── flow_dissector.c      # フロー解析
│   ├── ipv4/                     # IPv4 プロトコルスタック
│   │   ├── tcp.c                 # TCP 実装
│   │   ├── tcp_input.c           # TCP 受信処理
│   │   ├── tcp_output.c          # TCP 送信処理
│   │   ├── tcp_cubic.c           # CUBIC 輻輳制御
│   │   ├── tcp_bbr.c             # BBR 輻輳制御
│   │   ├── udp.c                 # UDP 実装
│   │   ├── ip_input.c            # IP 入力処理
│   │   ├── ip_output.c           # IP 出力処理
│   │   ├── route.c               # ルーティング
│   │   ├── fib_trie.c            # FIB (LC-Trie)
│   │   └── arp.c                 # ARP
│   ├── ipv6/                     # IPv6 プロトコルスタック
│   ├── bridge/                   # ブリッジ
│   ├── sched/                    # トラフィック制御
│   ├── netfilter/                # Netfilter フレームワーク
│   └── xdp/                      # XDP 関連
├── drivers/net/                  # NIC ドライバ
│   ├── ethernet/                 # イーサネットドライバ
│   │   ├── intel/                # Intel NIC
│   │   ├── mellanox/             # Mellanox NIC
│   │   └── broadcom/             # Broadcom NIC
│   ├── bonding/                  # ボンディング
│   ├── veth.c                    # veth ペア
│   ├── vxlan/                    # VXLAN
│   └── macvlan.c                 # MACVLAN
└── include/
    ├── linux/
    │   ├── skbuff.h              # sk_buff 定義
    │   ├── netdevice.h           # net_device 定義
    │   └── tcp.h                 # TCP ヘッダ/構造体
    └── net/
        ├── sock.h                # ソケット構造体
        ├── tcp.h                 # TCP プロトコル
        └── ip.h                  # IP プロトコル

1.5 Netfilter フックポイント

Netfilter はパケット処理パス上に5つのフックポイントを提供し、iptables/nftables がこれを利用する。

                              ┌─────────────┐
                              │  ルーティング  │
                    ┌────────►│    判定      │────────┐
                    │         └─────────────┘        │
                    │              │                   │
                    │         ローカル宛               フォワード
                    │              │                   │
                    │              ▼                   ▼
  ───► NF_INET_PRE_ROUTING ► NF_INET_LOCAL_IN    NF_INET_FORWARD
                                   │                   │
                                   ▼                   │
                              アプリケーション           │
                                   │                   │
                                   ▼                   │
                          NF_INET_LOCAL_OUT            │
                                   │                   │
                                   ▼                   ▼
                            NF_INET_POST_ROUTING ◄─────┘
                                   │
                                   ▼
                               送信 ────►

2. ソケットレイヤーとソケットバッファ (sk_buff)

2.1 ソケット構造体の階層

Linux のソケットは複数の構造体が階層的に連携して動作する。

/* ユーザー空間から見えるソケット (VFS と連携) */
struct socket {
    socket_state            state;          /* 接続状態 */
    short                   type;           /* SOCK_STREAM, SOCK_DGRAM 等 */
    unsigned long           flags;          /* ソケットフラグ */
    struct file             *file;          /* 関連するファイル構造体 */
    struct sock             *sk;            /* 内部ソケット構造体 */
    const struct proto_ops  *ops;           /* プロトコル操作 */
};

/* ネットワークプロトコルの内部表現 */
struct sock {
    struct sock_common      __sk_common;    /* 共通フィールド */
    
    /* 受信バッファ */
    struct sk_buff_head     sk_receive_queue;
    int                     sk_rcvbuf;      /* 受信バッファサイズ */
    
    /* 送信バッファ */
    struct sk_buff_head     sk_write_queue;
    int                     sk_sndbuf;      /* 送信バッファサイズ */
    
    /* タイマー */
    struct timer_list       sk_timer;
    
    /* コールバック */
    void (*sk_data_ready)(struct sock *sk);
    void (*sk_write_space)(struct sock *sk);
    void (*sk_state_change)(struct sock *sk);
    
    /* メモリ管理 */
    atomic_t                sk_wmem_alloc;  /* 送信メモリ使用量 */
    atomic_t                sk_rmem_alloc;  /* 受信メモリ使用量 */
    
    /* TCP 固有: struct tcp_sock として拡張 */
    /* UDP 固有: struct udp_sock として拡張 */
};

/* TCP ソケットの拡張 */
struct tcp_sock {
    struct inet_connection_sock inet_conn;
    
    /* シーケンス番号管理 */
    u32     snd_una;        /* 送信未確認の最初のバイト */
    u32     snd_nxt;        /* 次に送信するシーケンス番号 */
    u32     rcv_nxt;        /* 次に受信を期待するシーケンス番号 */
    u32     snd_wnd;        /* 送信ウィンドウサイズ */
    u32     rcv_wnd;        /* 受信ウィンドウサイズ */
    
    /* 輻輳制御 */
    u32     snd_cwnd;       /* 輻輳ウィンドウ */
    u32     snd_ssthresh;   /* スロースタート閾値 */
    
    /* RTT 測定 */
    u32     srtt_us;        /* 平滑化RTT (マイクロ秒) */
    u32     mdev_us;        /* RTT偏差 */
    u32     rttvar_us;      /* RTT分散 */
    
    /* 輻輳制御アルゴリズムの状態 */
    struct  tcp_congestion_ops *ca_ops;
    u32     ca_state;
};

2.2 sk_buff 構造体の詳細

sk_buff (ソケットバッファ) はカーネル内でパケットを表現する最も重要なデータ構造である。

struct sk_buff {
    /* リスト管理 */
    struct sk_buff      *next;
    struct sk_buff      *prev;
    
    /* タイムスタンプ */
    ktime_t             tstamp;
    
    /* 所属するソケット */
    struct sock         *sk;
    
    /* ネットワークデバイス */
    struct net_device   *dev;
    
    /* データポインタ群 */
    /* 
     * ┌────────────────────────────────────────┐
     * │         head                            │
     * │         ↓                               │
     * │  [headroom]                             │
     * │         ↓                               │
     * │         data ──► パケットデータ開始      │
     * │                                         │
     * │         tail ──► パケットデータ終了      │
     * │         ↓                               │
     * │  [tailroom]                             │
     * │         ↓                               │
     * │         end                             │
     * └────────────────────────────────────────┘
     */
    unsigned char       *head;      /* バッファ先頭 */
    unsigned char       *data;      /* データ先頭 */
    unsigned int        tail;       /* データ末尾 */
    unsigned int        end;        /* バッファ末尾 */
    
    /* 各レイヤーヘッダへのオフセット */
    __u16               transport_header;   /* L4 ヘッダ */
    __u16               network_header;     /* L3 ヘッダ */
    __u16               mac_header;         /* L2 ヘッダ */
    
    /* パケット長 */
    unsigned int        len;        /* 全データ長 (フラグメント含む) */
    unsigned int        data_len;   /* フラグメントデータ長 */
    __u16               mac_len;    /* MAC ヘッダ長 */
    
    /* プロトコル情報 */
    __be16              protocol;   /* パケットプロトコル */
    __u8                pkt_type;   /* パケットタイプ */
    __u8                ip_summed;  /* チェックサムステータス */
    
    /* マーキング */
    __u32               mark;       /* パケットマーク (Netfilter) */
    __u32               hash;       /* パケットハッシュ */
    
    /* クローンと参照 */
    refcount_t          users;      /* 参照カウンタ */
    unsigned char       cloned:1;   /* クローンフラグ */
};

2.3 sk_buff の操作関数

/* sk_buff の割り当て */
struct sk_buff *alloc_skb(unsigned int size, gfp_t priority);
struct sk_buff *netdev_alloc_skb(struct net_device *dev, unsigned int length);

/* データ領域の操作 */

/* headroom にスペースを追加 (プロトコルヘッダ追加用) */
void *skb_push(struct sk_buff *skb, unsigned int len);
/*
 * 操作前:  [headroom][ data ............... ]
 * 操作後:  [headrm][new|data .............. ]
 *                   ↑
 *                data が len バイト前に移動
 */

/* データ先頭からデータを削除 (ヘッダ解析後に呼ぶ) */
void *skb_pull(struct sk_buff *skb, unsigned int len);
/*
 * 操作前:  [headroom][header|payload....... ]
 * 操作後:  [headroom + header][payload..... ]
 *                              ↑
 *                         data が len バイト後ろに移動
 */

/* データ末尾にスペースを追加 */
void *skb_put(struct sk_buff *skb, unsigned int len);
/*
 * 操作前:  [data.......][tailroom........... ]
 * 操作後:  [data..............][tailroom.... ]
 *                         ↑
 *                    tail が len バイト後ろに移動
 */

/* headroom を確保 */
void skb_reserve(struct sk_buff *skb, int len);
/*
 * 操作前:  [ data (空) ][tailroom........... ]
 * 操作後:  [headroom][ data (空) ][tailroom. ]
 *                     ↑
 *               data と tail が len バイト後ろに移動
 */

2.4 sk_buff のライフサイクル

[割り当て] alloc_skb() / netdev_alloc_skb()
    │
    ▼
[ヘッドルーム確保] skb_reserve(skb, NET_IP_ALIGN + headroom)
    │
    ▼
[データ追加] skb_put() - ドライバがDMAで受信データを格納
    │
    ▼
[L2ヘッダ解析] eth_type_trans() → skb->protocol 設定
    │
    ▼
[L3処理] skb_pull() でL2ヘッダをスキップ
    │       ip_rcv() → skb->transport_header 設定
    │
    ▼
[L4処理] skb_pull() でL3ヘッダをスキップ
    │       tcp_v4_rcv() → ソケットキューに追加
    │
    ▼
[ユーザー空間へコピー] skb_copy_datagram_msg()
    │
    ▼
[解放] kfree_skb() / consume_skb()

3. TCP/IP 実装詳細

3.1 TCP コネクション確立 (3ウェイハンドシェイク)

クライアント                              サーバー
    │                                      │
    │  ┌─────────────────────────┐         │
    ├──┤ SYN (seq=x)             ├────────►│ tcp_v4_rcv()
    │  └─────────────────────────┘         │   → tcp_v4_do_rcv()
    │                                      │     → tcp_rcv_state_process()
    │  ┌─────────────────────────┐         │       → tcp_v4_conn_request()
    │◄─┤ SYN+ACK (seq=y,ack=x+1)├─────────┤         → SYN Cookie / SYN Queue
    │  └─────────────────────────┘         │
    │                                      │
    │  ┌─────────────────────────┐         │
    ├──┤ ACK (seq=x+1, ack=y+1) ├────────►│ tcp_check_req()
    │  └─────────────────────────┘         │   → SYN Queue → Accept Queue
    │                                      │
    │        ESTABLISHED                   │  ESTABLISHED

SYN Queue と Accept Queue

                  SYN 受信
                     │
                     ▼
              ┌──────────────┐
              │  SYN Queue   │  ← tcp_max_syn_backlog で制御
              │ (半開接続)    │     SYN Cookie 有効時は無制限
              └──────┬───────┘
                     │ ACK 受信
                     ▼
              ┌──────────────┐
              │ Accept Queue │  ← listen() の backlog で制御
              │ (完了接続)    │     somaxconn でシステム上限
              └──────┬───────┘
                     │ accept()
                     ▼
              アプリケーション
# SYN Queue / Accept Queue のチューニング
# SYN Queue サイズ
sysctl -w net.ipv4.tcp_max_syn_backlog=65535

# Accept Queue サイズ (システム上限)
sysctl -w net.core.somaxconn=65535

# SYN Cookie 有効化 (SYN Flood 対策)
sysctl -w net.ipv4.tcp_syncookies=1

# TIME_WAIT ソケットの再利用
sysctl -w net.ipv4.tcp_tw_reuse=1

# 確認コマンド
ss -tnl  # Listen ソケットの Send-Q が Accept Queue サイズ
ss -tn state syn-recv  # SYN Queue の接続

3.2 TCP データ送信処理

/* tcp_sendmsg() の簡略化フロー */
int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
{
    struct tcp_sock *tp = tcp_sk(sk);
    struct sk_buff *skb;
    int copied = 0;
    
    lock_sock(sk);
    
    while (msg_data_left(msg)) {
        /* 送信バッファの空きを確認 */
        if (sk_stream_wspace(sk) <= 0) {
            /* バッファが満杯 → プロセスをスリープ */
            sk_stream_wait_memory(sk, &timeo);
        }
        
        /* 既存のSKBの末尾にデータを追加できるか確認 */
        skb = tcp_write_queue_tail(sk);
        if (skb && skb->len < size_goal) {
            /* 既存SKBに追加 */
            copy = min(size_goal - skb->len, remaining);
            skb_add_data(skb, &msg->msg_iter, copy);
        } else {
            /* 新しいSKBを割り当て */
            skb = sk_stream_alloc_skb(sk, 0, sk->sk_allocation);
            skb_entail(sk, skb);  /* 送信キューに追加 */
            skb_add_data(skb, &msg->msg_iter, copy);
        }
        
        copied += copy;
        
        /* Nagle アルゴリズムの判定 */
        if (forced_push(tp) || !tcp_nagle_test(tp, skb, mss_now, TCP_NAGLE_PUSH)) {
            tcp_push(sk, msg->msg_flags, mss_now, tp->nonagle);
        }
    }
    
    release_sock(sk);
    return copied;
}

3.3 TCP セグメンテーションと GSO/TSO

アプリケーションデータ (64KB)
    │
    ▼
┌──────────────────────────┐
│ tcp_sendmsg()            │
│ → 大きなSKBとして格納     │
└────────────┬─────────────┘
             │
             ▼
┌──────────────────────────┐
│ TSO (TCP Segmentation    │  ← NIC がハードウェアで分割
│      Offload) 有効?      │
├──────────┬───────────────┤
│ YES      │ NO            │
│          │               │
│          ▼               │
│ GSO (Generic             │
│ Segmentation Offload)    │
│ → ソフトウェアで分割      │
└──────────┼───────────────┘
           │
           ▼
    MSS サイズの TCP セグメント群
    ┌─────┐┌─────┐┌─────┐┌─────┐
    │1460B││1460B││1460B││...  │
    └─────┘└─────┘└─────┘└─────┘
# TSO/GSO の確認と設定
ethtool -k eth0 | grep -E '(tcp-segmentation|generic-segmentation)'
# tcp-segmentation-offload: on
# generic-segmentation-offload: on

# TSO 無効化 (デバッグ用)
ethtool -K eth0 tso off

# GSO 無効化
ethtool -K eth0 gso off

3.4 TCP タイマー

TCP は複数のタイマーを使用して信頼性と効率性を実現する。

┌───────────────────┬──────────────────────────────────────────────┐
│ タイマー名         │ 説明                                         │
├───────────────────┼──────────────────────────────────────────────┤
│ 再送タイマー       │ ACK未受信時のセグメント再送                    │
│ (Retransmit)      │ RTO = srtt + 4 * rttvar                     │
│                   │ 指数バックオフ (最大120秒)                     │
├───────────────────┼──────────────────────────────────────────────┤
│ 遅延ACKタイマー    │ ACK送信を遅延させてバッチ化                    │
│ (Delayed ACK)     │ 40ms or 2パケット受信でACK送信                │
├───────────────────┼──────────────────────────────────────────────┤
│ Keepalive タイマー │ アイドル接続の生存確認                         │
│                   │ デフォルト: 7200秒後に開始、75秒間隔9回        │
├───────────────────┼──────────────────────────────────────────────┤
│ TIME_WAIT タイマー │ 接続終了後の待機                              │
│                   │ 2 * MSL (通常60秒)                           │
├───────────────────┼──────────────────────────────────────────────┤
│ Zero Window Probe │ 受信ウィンドウがゼロの時の探索                 │
│                   │ 指数バックオフで最大120秒                      │
├───────────────────┼──────────────────────────────────────────────┤
│ FIN_WAIT2 タイマー │ FIN_WAIT2 状態のタイムアウト                  │
│                   │ tcp_fin_timeout (デフォルト60秒)              │
└───────────────────┴──────────────────────────────────────────────┘
# TCP タイマー関連のチューニング
# Keepalive 設定
sysctl -w net.ipv4.tcp_keepalive_time=600     # 最初のKeepaliveまで
sysctl -w net.ipv4.tcp_keepalive_intvl=60     # Keepalive間隔
sysctl -w net.ipv4.tcp_keepalive_probes=5     # 最大プローブ回数

# FIN_WAIT2 タイムアウト
sysctl -w net.ipv4.tcp_fin_timeout=30

# 再送回数
sysctl -w net.ipv4.tcp_retries1=3      # ソフトエラー閾値
sysctl -w net.ipv4.tcp_retries2=15     # ハードエラー閾値 (接続断)

# SYN 再送回数
sysctl -w net.ipv4.tcp_syn_retries=3
sysctl -w net.ipv4.tcp_synack_retries=3

3.5 TCP 状態遷移図

                    ┌───────────┐
             ┌──────┤  CLOSED   │◄────────────────────────┐
             │      └───────────┘                          │
             │ listen()  │ connect()                       │ タイムアウト
             │           │ (SYN送信)                       │
             ▼           ▼                                 │
      ┌──────────┐  ┌──────────┐                          │
      │  LISTEN  │  │ SYN_SENT │                          │
      └────┬─────┘  └────┬─────┘                          │
           │              │ SYN+ACK受信                    │
     SYN受信│              │ (ACK送信)                      │
    (SYN+ACK│              │                               │
      送信) │              │                               │
           ▼              ▼                                │
      ┌──────────┐  ┌───────────┐                         │
      │ SYN_RECV │  │ESTABLISHED│◄──────────┐             │
      └────┬─────┘  └─────┬─────┘           │             │
           │              │                  │             │
     ACK受信│         close()               │             │
           │         (FIN送信)               │             │
           │              │                  │             │
           └──────┐       ▼                  │             │
                  │  ┌──────────┐            │             │
                  └►│FIN_WAIT_1│     FIN受信 │             │
                    └────┬─────┘     (ACK送信)│             │
                         │                   │             │
                    ACK受信│     ┌────────────┘             │
                         │     │                           │
                         ▼     ▼                           │
                   ┌──────────┐  ┌──────────┐             │
                   │FIN_WAIT_2│  │CLOSE_WAIT│             │
                   └────┬─────┘  └────┬─────┘             │
                        │              │                   │
                   FIN受信│         close()                │
                  (ACK送信)│        (FIN送信)               │
                        │              │                   │
                        ▼              ▼                   │
                   ┌──────────┐  ┌──────────┐             │
                   │TIME_WAIT │  │ LAST_ACK │             │
                   └────┬─────┘  └────┬─────┘             │
                        │              │ ACK受信            │
                   2MSL │              └──────────────────►│
                   タイムアウト                              │
                        └─────────────────────────────────►┘

4. TCP 輻輳制御アルゴリズム

4.1 輻輳制御の基本概念

TCP 輻輳制御はネットワークの混雑を検知し、送信レートを適切に調整するメカニズムである。

送信レート
    ▲
    │        ┌─ Congestion Avoidance ─┐
    │       /                          \
    │      /                            \  ← パケットロス検出
    │     /                              \
    │    / Slow Start                     \  ssthresh = cwnd/2
    │   / (指数的増加)                      \  cwnd = ssthresh
    │  /                                    \
    │ /                                      \────── Recovery
    │/                                        \    /
    └──────────────────────────────────────────────► 時間

4.2 CUBIC (デフォルトアルゴリズム)

CUBIC は Linux カーネル 2.6.19 以降のデフォルト輻輳制御アルゴリズムである。ウィンドウサイズの増加を3次関数(キュービック関数)でモデル化する。

W(t) = C * (t - K)^3 + W_max

ここで:
  C = スケーリング定数 (デフォルト: 0.4)
  K = ∛(W_max * β / C)  (ウィンドウが W_max に戻るまでの時間)
  W_max = パケットロス時のウィンドウサイズ
  β = 乗法減少係数 (デフォルト: 0.7)
  t = 最後のパケットロスからの経過時間
ウィンドウサイズ
    ▲
    │                    ____________________
    │                   /    W_max           \
    │                  /                      \
    │                 /                        \  ← ロス
    │                /                          \
    │          _____/                            \___
    │         /   ↑                                  \
    │        / 凹部分: RTT に非依存                     \
    │       /  (高RTTリンクで有利)                       \
    │      /                                            \
    │_____/                                              \___
    └────────────────────────────────────────────────────────► 時間
                     K                        K
/* net/ipv4/tcp_cubic.c の主要部分 */
static void bictcp_cong_avoid(struct sock *sk, u32 ack, u32 acked)
{
    struct tcp_sock *tp = tcp_sk(sk);
    struct bictcp *ca = inet_csk_ca(sk);
    
    if (!tcp_is_cwnd_limited(sk))
        return;
    
    if (tcp_in_slow_start(tp)) {
        /* スロースタート: 指数的増加 */
        tcp_slow_start(tp, acked);
        return;
    }
    
    /* CUBIC の輻輳回避 */
    bictcp_update(ca, tcp_snd_cwnd(tp), acked);
    tcp_cong_avoid_ai(tp, ca->cnt, acked);
}
# 現在の輻輳制御アルゴリズムを確認
sysctl net.ipv4.tcp_congestion_control
# net.ipv4.tcp_congestion_control = cubic

# 利用可能なアルゴリズムを確認
sysctl net.ipv4.tcp_available_congestion_control
# net.ipv4.tcp_available_congestion_control = reno cubic

# 許可されたアルゴリズムを確認
sysctl net.ipv4.tcp_allowed_congestion_control

4.3 BBR (Bottleneck Bandwidth and Round-trip propagation time)

BBR は Google が開発した輻輳制御アルゴリズムで、パケットロスではなく帯域幅と RTT のモデルベースで制御する。

┌────────────────────────────────────────────────┐
│              BBR の状態マシン                     │
│                                                │
│   ┌──────────┐    ┌──────────┐                 │
│   │ STARTUP  │───►│  DRAIN   │                 │
│   │(帯域探索) │    │(キュー排出)│                 │
│   └──────────┘    └────┬─────┘                 │
│                        │                        │
│                        ▼                        │
│               ┌──────────────┐                  │
│        ┌──────┤ PROBE_BW     │◄─────┐          │
│        │      │(定常状態)     │      │          │
│        │      └──────────────┘      │          │
│        │                            │          │
│        ▼                            │          │
│   ┌──────────┐                      │          │
│   │PROBE_RTT │──────────────────────┘          │
│   │(RTT測定) │                                  │
│   └──────────┘                                  │
└────────────────────────────────────────────────┘

BBR の送信レート計算:

sending_rate = BtlBw * pacing_gain
cwnd = BtlBw * RTprop * cwnd_gain

BtlBw = ボトルネック帯域幅 (最大配信レートの推定)
RTprop = 最小RTT (伝搬遅延の推定)

PROBE_BW での pacing_gain サイクル:
  [5/4, 3/4, 1, 1, 1, 1, 1, 1]
  ↑帯域探索  ↑排出  ↑定常状態...
# BBR の有効化
modprobe tcp_bbr
sysctl -w net.ipv4.tcp_congestion_control=bbr

# BBR v2 (実験的) の有効化
modprobe tcp_bbr2
sysctl -w net.ipv4.tcp_congestion_control=bbr2

# FQ (Fair Queuing) qdisc との組み合わせ推奨
tc qdisc replace dev eth0 root fq

# BBR の動作状態をモニタリング
ss -tin | grep -A 5 bbr
# 出力例:
# bbr wscale:7,7 rto:204 rtt:1.5/0.5 ato:40 mss:1448
# cwnd:10 ssthresh:7 bytes_sent:1234 bytes_acked:1234
# delivery_rate 900Mbps app_limited

4.4 Reno

TCP Reno は最も基本的な輻輳制御アルゴリズムである。

ウィンドウサイズ
    ▲
    │      /\      /\      /\
    │     /  \    /  \    /  \
    │    /    \  /    \  /    \
    │   / SS   \/CA    \/      \
    │  /       半減   半減      \
    │ /                          \
    │/                            \
    └──────────────────────────────► 時間
    
SS = Slow Start (指数的増加)
CA = Congestion Avoidance (線形増加: cwnd += 1/cwnd per ACK)
# アルゴリズムの比較テスト
# 接続ごとに輻輳制御を設定 (C/Python)
# setsockopt(fd, IPPROTO_TCP, TCP_CONGESTION, "bbr", 3);

# iperf3 での比較テスト
iperf3 -c server -C cubic -t 30 --json > cubic_result.json
iperf3 -c server -C bbr -t 30 --json > bbr_result.json

4.5 輻輳制御アルゴリズムの比較

┌────────────┬─────────┬──────────┬─────────┬───────────────┐
│ 特性       │ Reno    │ CUBIC    │ BBR     │ BBR v2        │
├────────────┼─────────┼──────────┼─────────┼───────────────┤
│ ロス検出   │ 3重ACK  │ 3重ACK   │ 不使用  │ モデル+ロス   │
│ RTT依存性  │ 高い    │ 低い     │ 測定    │ 測定          │
│ 帯域利用率 │ 低い    │ 中程度   │ 高い    │ 高い          │
│ バッファ   │ 多く必要│ 中程度   │ 少ない  │ 少ない        │
│ 公平性     │ RTT依存 │ RTT独立  │ 課題あり│ 改善          │
│ 長距離回線 │ 不利    │ 有利     │ 最適    │ 最適          │
│ 無線環境   │ 不利    │ やや不利 │ 有利    │ 有利          │
│ カーネル   │ デフォルト│ 2.6.19+│ 4.9+   │ 5.18+ (実験)  │
└────────────┴─────────┴──────────┴─────────┴───────────────┘

5. UDP 処理パス

5.1 UDP の受信処理

/* net/ipv4/udp.c */
int udp_rcv(struct sk_buff *skb)
{
    return __udp4_lib_rcv(skb, &udp_table, IPPROTO_UDP);
}

int __udp4_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
                    int proto)
{
    struct sock *sk;
    struct udphdr *uh;
    unsigned short ulen;
    struct rtable *rt = skb_rtable(skb);
    __be32 saddr, daddr;
    
    /* UDP ヘッダの検証 */
    uh = udp_hdr(skb);
    ulen = ntohs(uh->len);
    
    /* チェックサム検証 */
    if (udp_lib_checksum_complete(skb))
        goto csum_error;
    
    /* ソケットルックアップ (4タプルハッシュ) */
    sk = __udp4_lib_lookup_skb(skb, uh->source, uh->dest, udptable);
    
    if (sk) {
        /* ソケットが見つかった → 受信キューに追加 */
        int ret = udp_unicast_rcv_skb(sk, skb, uh);
        return ret;
    }
    
    /* マルチキャストの場合 */
    if (rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))
        return __udp4_lib_mcast_deliver(net, skb, uh,
                                         saddr, daddr, udptable);
    
    /* 宛先不明 → ICMP Port Unreachable */
    icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
    kfree_skb(skb);
    return 0;
}

5.2 UDP の送信処理

int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
{
    struct inet_sock *inet = inet_sk(sk);
    struct udp_sock *up = udp_sk(sk);
    struct flowi4 *fl4;
    struct sk_buff *skb;
    int err;
    
    /* 宛先アドレスの決定 */
    if (msg->msg_name) {
        /* sendto() で指定された宛先 */
        daddr = usin->sin_addr.s_addr;
        dport = usin->sin_port;
    } else {
        /* connect() で設定済みの宛先 */
        daddr = inet->inet_daddr;
        dport = inet->inet_dport;
    }
    
    /* ルーティングルックアップ */
    fl4 = &inet->cork.fl.u.ip4;
    rt = ip_route_output_flow(net, fl4, sk);
    
    /* Cork モード (複数の sendmsg をまとめて送信) */
    if (up->pending) {
        lock_sock(sk);
        goto do_append_data;
    }
    
    /* IP レイヤーでデータを構築 */
    err = ip_make_skb(sk, fl4, getfrag, msg, ulen,
                      sizeof(struct udphdr), &ipc, &rt,
                      &cork, msg->msg_flags);
    
    /* UDP ヘッダの追加とチェックサム計算 */
    skb = ip_make_skb(...);
    err = udp_send_skb(skb, fl4, &cork);
    
    return err;
}

5.3 UDP パフォーマンスの最適化

# UDP バッファサイズの調整
sysctl -w net.core.rmem_max=26214400        # 受信バッファ最大 (25MB)
sysctl -w net.core.rmem_default=1048576     # 受信バッファデフォルト (1MB)
sysctl -w net.core.wmem_max=26214400        # 送信バッファ最大 (25MB)
sysctl -w net.core.wmem_default=1048576     # 送信バッファデフォルト (1MB)

# UDP メモリ制限
sysctl -w net.ipv4.udp_mem="8388608 12582912 16777216"
# [min pressure max] ページ単位

# UDP 受信バッファ使用量の監視
cat /proc/net/udp
# sl  local_address rem_address   st tx_queue rx_queue ...
#  0: 00000000:0035 00000000:0000 07 00000000:00000000 ...

# ドロップの監視
cat /proc/net/snmp | grep Udp
# Udp: InDatagrams NoPorts InErrors OutDatagrams RcvbufErrors SndbufErrors
/* 高性能 UDP アプリケーションのパターン */
#include <sys/socket.h>
#include <netinet/in.h>

/* recvmmsg: 複数データグラムの一括受信 */
struct mmsghdr msgs[VLEN];
struct iovec iovecs[VLEN];
char bufs[VLEN][BUFSIZE];

for (int i = 0; i < VLEN; i++) {
    iovecs[i].iov_base = bufs[i];
    iovecs[i].iov_len  = BUFSIZE;
    msgs[i].msg_hdr.msg_iov = &iovecs[i];
    msgs[i].msg_hdr.msg_iovlen = 1;
}

int retval = recvmmsg(fd, msgs, VLEN, 0, NULL);

/* sendmmsg: 複数データグラムの一括送信 */
int retval = sendmmsg(fd, msgs, VLEN, 0);

/* GRO (Generic Receive Offload) for UDP */
int val = 1;
setsockopt(fd, SOL_UDP, UDP_GRO, &val, sizeof(val));

/* GSO for UDP (Linux 4.18+) */
int gso_size = 1472;  /* MSS サイズ */
setsockopt(fd, SOL_UDP, UDP_SEGMENT, &gso_size, sizeof(gso_size));

6. ルーティングサブシステムと FIB

6.1 FIB (Forwarding Information Base) アーキテクチャ

┌──────────────────────────────────────────────┐
│              ルーティングテーブル               │
│                                              │
│  ┌──────────┐    ┌──────────┐                │
│  │  FIB     │    │  FIB     │                │
│  │  Rules   │───►│  Tables  │                │
│  │(ポリシー) │    │(テーブル)  │                │
│  └──────────┘    └────┬─────┘                │
│                       │                       │
│              ┌────────┼────────┐              │
│              │        │        │              │
│              ▼        ▼        ▼              │
│         ┌────────┐┌────────┐┌────────┐       │
│         │ local  ││  main  ││ default│       │
│         │(Table  ││(Table  ││(Table  │       │
│         │ 255)   ││ 254)   ││ 253)   │       │
│         └────────┘└────────┘└────────┘       │
│                                              │
│  各テーブルの内部:                             │
│  ┌──────────────────────────────┐             │
│  │  LC-Trie (Level Compressed  │             │
│  │  Trie) データ構造            │             │
│  │                              │             │
│  │  最長プレフィックスマッチ     │             │
│  │  O(log n) のルックアップ     │             │
│  └──────────────────────────────┘             │
└──────────────────────────────────────────────┘

6.2 ルーティングルックアップのフロー

/* ip_route_output_flow() の簡略化フロー */

1. ルーティングキャッシュの確認 (fib_lookup)
   │
   ▼
2. FIB Rules の評価 (ポリシールーティング)
   │
   ├── Rule 0: lookup local    (ローカルアドレス)
   ├── Rule 32766: lookup main (メインテーブル)
   └── Rule 32767: lookup default
   │
   ▼
3. FIB テーブルのルックアップ (LC-Trie)
   │
   ├── 最長プレフィックスマッチ
   └── fib_info (ネクストホップ情報) を返却
   │
   ▼
4. 結果を dst_entry としてキャッシュ
   │
   └── skb->_skb_refdst に設定

6.3 ルーティング操作コマンド

# ルーティングテーブルの表示
ip route show                    # メインテーブル
ip route show table local        # ローカルテーブル
ip route show table all          # 全テーブル

# 出力例:
# default via 10.0.0.1 dev eth0 proto dhcp metric 100
# 10.0.0.0/24 dev eth0 proto kernel scope link src 10.0.0.100 metric 100
# 172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1

# ルーティングの追加・削除
ip route add 192.168.1.0/24 via 10.0.0.1 dev eth0
ip route add 10.10.0.0/16 via 10.0.0.254 dev eth0 metric 200
ip route del 192.168.1.0/24

# マルチパスルーティング (ECMP)
ip route add 10.0.0.0/8 \
    nexthop via 192.168.1.1 dev eth0 weight 1 \
    nexthop via 192.168.2.1 dev eth1 weight 1

# ブラックホールルート
ip route add blackhole 10.99.0.0/16

# ポリシールーティング (送信元ベース)
ip rule add from 192.168.1.0/24 table 100
ip route add default via 10.0.0.1 table 100
ip rule add from 192.168.2.0/24 table 200
ip route add default via 10.0.1.1 table 200

# ルーティングの確認
ip route get 8.8.8.8
# 8.8.8.8 via 10.0.0.1 dev eth0 src 10.0.0.100 uid 0
#     cache

# FIB ルールの表示
ip rule show
# 0:      from all lookup local
# 32766:  from all lookup main
# 32767:  from all lookup default

# ルーティングキャッシュの統計
cat /proc/net/rt_cache  # (古いカーネル)
ip -s route show cache  # ルートキャッシュの統計

6.4 FIB の内部データ構造 (LC-Trie)

          ルートノード
          /          \
       0              1
      / \            / \
    00   01        10   11
    │     │        │     │
  /24   /24      /24   /24
 リーフ  リーフ   リーフ  リーフ

LC-Trie (Level Compressed Trie):
- パス圧縮: 分岐のないパスを1ノードに圧縮
- レベル圧縮: 同一レベルの分岐を配列で表現
- ルックアップ: O(W/k) (W=アドレスビット長, k=圧縮レベル)

7. 近隣サブシステム (ARP/NDP)

7.1 ARP (Address Resolution Protocol) 処理

┌─────────────────────────────────────────────┐
│              近隣キャッシュ                    │
│                                              │
│  状態遷移:                                    │
│                                              │
│  NUD_NONE → NUD_INCOMPLETE → NUD_REACHABLE  │
│                    │              │           │
│                    │              ▼           │
│                    │         NUD_DELAY        │
│                    │              │           │
│                    │              ▼           │
│                    │         NUD_PROBE        │
│                    │              │           │
│                    ▼              ▼           │
│               NUD_FAILED    NUD_STALE        │
│                                              │
│  NUD = Neighbor Unreachability Detection     │
└─────────────────────────────────────────────┘
# ARP テーブルの表示
ip neigh show
# 10.0.0.1 dev eth0 lladdr aa:bb:cc:dd:ee:ff REACHABLE
# 10.0.0.2 dev eth0 lladdr 11:22:33:44:55:66 STALE
# 10.0.0.3 dev eth0  FAILED

# ARP エントリの追加・削除
ip neigh add 10.0.0.10 lladdr aa:bb:cc:dd:ee:ff dev eth0 nud permanent
ip neigh del 10.0.0.10 dev eth0
ip neigh change 10.0.0.10 lladdr 11:22:33:44:55:66 dev eth0

# ARP キャッシュのフラッシュ
ip neigh flush dev eth0

# ARP 関連のカーネルパラメータ
sysctl -w net.ipv4.neigh.eth0.gc_stale_time=120    # STALE タイムアウト
sysctl -w net.ipv4.neigh.eth0.base_reachable_time_ms=30000  # REACHABLE 時間
sysctl -w net.ipv4.neigh.default.gc_thresh1=128     # GC 開始閾値
sysctl -w net.ipv4.neigh.default.gc_thresh2=512     # GC ソフトリミット
sysctl -w net.ipv4.neigh.default.gc_thresh3=1024    # GC ハードリミット

# Gratuitous ARP の送信
arping -A -I eth0 10.0.0.100

# ARP プロキシの有効化
sysctl -w net.ipv4.conf.eth0.proxy_arp=1

7.2 NDP (Neighbor Discovery Protocol) - IPv6

# IPv6 近隣テーブル
ip -6 neigh show
# fe80::1 dev eth0 lladdr aa:bb:cc:dd:ee:ff router REACHABLE

# IPv6 ルーターディスカバリ設定
sysctl -w net.ipv6.conf.eth0.accept_ra=1           # RA 受信
sysctl -w net.ipv6.conf.eth0.router_solicitations=3 # RS 送信回数
sysctl -w net.ipv6.conf.eth0.accept_ra_defrtr=1    # デフォルトルータ受入

# DAD (Duplicate Address Detection)
sysctl -w net.ipv6.conf.eth0.dad_transmits=1       # DAD パケット数

8. ネットワークデバイスドライバインターフェース (NAPI)

8.1 NAPI (New API) の概要

NAPI は高速ネットワーク処理のためのカーネルインターフェースで、割り込み駆動からポーリングへの適応的な切り替えを実現する。

従来方式 (割り込み駆動):
  パケット到着 → IRQ → 処理 → IRQ → 処理 → IRQ → 処理
  ※ 高負荷時に割り込みストーム発生

NAPI 方式 (割り込み + ポーリング):
  パケット到着 → IRQ → [割り込み無効化] → ポーリング → ポーリング → ...
                                            → [バジェット消費 or キュー空]
                                            → [割り込み再有効化]
┌─────────────────────────────────────────────────┐
│                NAPI 処理フロー                    │
│                                                  │
│  [NIC: パケット受信]                              │
│       │                                          │
│       ▼                                          │
│  [ハード IRQ] → napi_schedule()                  │
│       │         ├── NAPI を softirq キューに追加  │
│       │         └── 割り込み無効化                 │
│       ▼                                          │
│  [NET_RX_SOFTIRQ]                                │
│       │                                          │
│       ▼                                          │
│  net_rx_action()                                 │
│       │                                          │
│       ▼                                          │
│  napi_poll() → ドライバの poll 関数               │
│       │                                          │
│       ├── パケットを処理 (budget まで)             │
│       │   ├── sk_buff 割り当て                    │
│       │   ├── DMA からデータコピー                 │
│       │   └── napi_gro_receive()                 │
│       │                                          │
│       ├── budget 消費済み?                        │
│       │   ├── YES → 次の softirq サイクルへ       │
│       │   └── NO  → napi_complete_done()         │
│       │             → 割り込み再有効化             │
│       │                                          │
│       └── GRO 処理                               │
│           ├── 同一フローのパケットを結合            │
│           └── netif_receive_skb() へ              │
└─────────────────────────────────────────────────┘

8.2 NAPI ドライバの実装例

/* NAPI 対応ドライバの基本構造 */
#include <linux/netdevice.h>
#include <linux/etherdevice.h>

struct my_nic_priv {
    struct napi_struct napi;
    struct net_device *netdev;
    void __iomem *regs;
    dma_addr_t rx_ring_dma;
    struct sk_buff *rx_skbs[RX_RING_SIZE];
    int rx_head;
};

/* ドライバ初期化 */
static int my_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
    struct net_device *netdev;
    struct my_nic_priv *priv;
    
    netdev = alloc_etherdev(sizeof(struct my_nic_priv));
    priv = netdev_priv(netdev);
    
    /* NAPI の初期化 (weight はポーリング1回あたりの最大処理数) */
    netif_napi_add(netdev, &priv->napi, my_nic_poll, NAPI_POLL_WEIGHT);
    /* NAPI_POLL_WEIGHT = 64 (デフォルト) */
    
    register_netdev(netdev);
    napi_enable(&priv->napi);
    
    return 0;
}

/* ハードウェア割り込みハンドラ */
static irqreturn_t my_nic_interrupt(int irq, void *dev_id)
{
    struct my_nic_priv *priv = dev_id;
    
    /* 割り込み原因の確認 */
    u32 status = readl(priv->regs + IRQ_STATUS);
    
    if (status & RX_IRQ) {
        /* RX 割り込み無効化 + NAPI スケジュール */
        writel(0, priv->regs + RX_IRQ_MASK);
        napi_schedule(&priv->napi);
    }
    
    return IRQ_HANDLED;
}

/* NAPI ポーリング関数 */
static int my_nic_poll(struct napi_struct *napi, int budget)
{
    struct my_nic_priv *priv = container_of(napi, struct my_nic_priv, napi);
    int work_done = 0;
    
    while (work_done < budget) {
        struct sk_buff *skb;
        int pkt_len;
        
        /* Ring Buffer にパケットがあるか確認 */
        if (!rx_ring_has_data(priv))
            break;
        
        /* パケット情報の取得 */
        pkt_len = get_rx_pkt_len(priv, priv->rx_head);
        
        /* sk_buff の割り当てとデータコピー */
        skb = napi_alloc_skb(napi, pkt_len);
        if (!skb)
            break;
        
        /* DMA バッファから sk_buff にコピー */
        dma_sync_single_for_cpu(&priv->pdev->dev,
                                priv->rx_ring_dma + priv->rx_head * BUF_SIZE,
                                pkt_len, DMA_FROM_DEVICE);
        skb_put_data(skb, rx_buf_addr(priv, priv->rx_head), pkt_len);
        
        /* プロトコル設定 */
        skb->protocol = eth_type_trans(skb, priv->netdev);
        
        /* チェックサムオフロード */
        skb->ip_summed = CHECKSUM_UNNECESSARY;
        
        /* GRO 処理へ渡す */
        napi_gro_receive(napi, skb);
        
        priv->rx_head = (priv->rx_head + 1) % RX_RING_SIZE;
        work_done++;
    }
    
    /* 全パケット処理済み → 割り込み再有効化 */
    if (work_done < budget) {
        napi_complete_done(napi, work_done);
        writel(1, priv->regs + RX_IRQ_MASK);  /* RX 割り込み有効化 */
    }
    
    return work_done;
}

8.3 GRO (Generic Receive Offload)

GRO なし:
  [パケット1: 1500B] → netif_receive_skb()
  [パケット2: 1500B] → netif_receive_skb()
  [パケット3: 1500B] → netif_receive_skb()
  → 3回のプロトコルスタック処理

GRO あり:
  [パケット1: 1500B] ┐
  [パケット2: 1500B] ├→ napi_gro_receive() で結合
  [パケット3: 1500B] ┘
  → [結合パケット: 4500B] → netif_receive_skb()
  → 1回のプロトコルスタック処理

結合条件:
  - 同一フロー (5タプル一致)
  - TCP の場合: シーケンス番号が連続
  - 同一 NIC から受信
# GRO の確認と制御
ethtool -k eth0 | grep generic-receive-offload
# generic-receive-offload: on

ethtool -K eth0 gro on    # GRO 有効化
ethtool -K eth0 gro off   # GRO 無効化 (デバッグ用)

# NAPI 統計
cat /proc/net/softnet_stat
# カラム: processed, dropped, time_squeeze, (cpu_collision), received_rps, flow_limit_count
# 各行が CPU コアに対応

9. XDP (eXpress Data Path)

9.1 XDP アーキテクチャ

XDP はドライバレベルでパケット処理を行う高性能フレームワークで、eBPF プログラムをNICドライバに直接アタッチする。

従来のパケットパス:
  NIC → DMA → Ring Buffer → sk_buff 割当 → netif_receive_skb()
  → プロトコルスタック → ソケット → アプリケーション

XDP パケットパス:
  NIC → DMA → Ring Buffer → XDP プログラム実行
                                   │
                    ┌──────────────┼──────────────┐
                    │              │              │
                    ▼              ▼              ▼
               XDP_DROP       XDP_TX        XDP_REDIRECT
              (即座に破棄)  (同一NICから    (別NIC/CPU/
                           送り返す)     AF_XDPソケットへ)
                                              │
                                              ▼
                                         XDP_PASS
                                     (通常パスへ進む)

9.2 XDP の動作モード

┌─────────────────────────────────────────────────────┐
│ モード          │ 説明                  │ 性能       │
├─────────────────┼───────────────────────┼───────────┤
│ Native XDP      │ ドライバ内で実行       │ 最高性能   │
│ (XDP_DRV)       │ sk_buff 割当前に処理   │           │
├─────────────────┼───────────────────────┼───────────┤
│ Generic XDP     │ netif_receive_skb()後 │ 中程度     │
│ (XDP_SKB)       │ 全NICで動作可能        │           │
├─────────────────┼───────────────────────┼───────────┤
│ Offloaded XDP   │ NIC ハードウェア上で   │ 超高性能   │
│ (XDP_HW)        │ SmartNIC が必要        │           │
└─────────────────┴───────────────────────┴───────────┘

9.3 XDP プログラムの実装例

/* DDoS 対策: SYN Flood フィルタ */
#include <linux/bpf.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <bpf/bpf_helpers.h>

/* レートリミットマップ */
struct {
    __uint(type, BPF_MAP_TYPE_LRU_HASH);
    __uint(max_entries, 100000);
    __type(key, __be32);          /* 送信元 IP */
    __type(value, __u64);         /* タイムスタンプ */
} syn_rate_map SEC(".maps");

/* ブラックリストマップ */
struct {
    __uint(type, BPF_MAP_TYPE_HASH);
    __uint(max_entries, 10000);
    __type(key, __be32);          /* IP アドレス */
    __type(value, __u8);          /* フラグ */
} blacklist SEC(".maps");

SEC("xdp")
int xdp_syn_filter(struct xdp_md *ctx)
{
    void *data = (void *)(long)ctx->data;
    void *data_end = (void *)(long)ctx->data_end;
    
    /* L2 ヘッダのパース */
    struct ethhdr *eth = data;
    if ((void *)(eth + 1) > data_end)
        return XDP_PASS;
    
    if (eth->h_proto != __constant_htons(ETH_P_IP))
        return XDP_PASS;
    
    /* L3 ヘッダのパース */
    struct iphdr *iph = (void *)(eth + 1);
    if ((void *)(iph + 1) > data_end)
        return XDP_PASS;
    
    if (iph->protocol != IPPROTO_TCP)
        return XDP_PASS;
    
    /* ブラックリスト確認 */
    __u8 *blocked = bpf_map_lookup_elem(&blacklist, &iph->saddr);
    if (blocked)
        return XDP_DROP;
    
    /* L4 ヘッダのパース */
    struct tcphdr *tcph = (void *)iph + (iph->ihl * 4);
    if ((void *)(tcph + 1) > data_end)
        return XDP_PASS;
    
    /* SYN パケットのレートリミット */
    if (tcph->syn && !tcph->ack) {
        __u64 now = bpf_ktime_get_ns();
        __u64 *last_seen = bpf_map_lookup_elem(&syn_rate_map, &iph->saddr);
        
        if (last_seen) {
            /* 100ms 以内に再度 SYN → DROP */
            if (now - *last_seen < 100000000ULL)
                return XDP_DROP;
        }
        
        bpf_map_update_elem(&syn_rate_map, &iph->saddr, &now, BPF_ANY);
    }
    
    return XDP_PASS;
}

char _license[] SEC("license") = "GPL";

9.4 XDP の利用とデプロイ

# XDP プログラムのコンパイル
clang -O2 -target bpf -c xdp_filter.c -o xdp_filter.o

# XDP プログラムのアタッチ
# Native モード
ip link set dev eth0 xdpdrv obj xdp_filter.o sec xdp

# Generic モード (全NIC対応)
ip link set dev eth0 xdpgeneric obj xdp_filter.o sec xdp

# XDP の確認
ip link show dev eth0
# 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 xdp qdisc mq state UP
#     prog/xdp id 42 tag abc123...

# XDP の削除
ip link set dev eth0 xdp off

# bpftool での管理
bpftool prog list                    # BPF プログラム一覧
bpftool prog show id 42              # 詳細表示
bpftool map list                     # BPF マップ一覧
bpftool map dump id 10               # マップ内容ダンプ
bpftool net list                     # ネットワーク BPF 一覧

# AF_XDP (XDP Socket) の利用
# ユーザー空間で直接パケット処理
# DPDK に代わる高性能パケット処理基盤

9.5 XDP パフォーマンス特性

パケット処理性能 (64バイトパケット, 1コア):
┌──────────────────┬───────────────┬──────────────┐
│ 処理方式          │ パケット/秒   │ レイテンシ     │
├──────────────────┼───────────────┼──────────────┤
│ iptables         │ ~2-3 Mpps    │ ~10-20 μs    │
│ nftables         │ ~3-5 Mpps    │ ~5-10 μs     │
│ XDP (Generic)    │ ~5-10 Mpps   │ ~3-5 μs      │
│ XDP (Native)     │ ~20-30 Mpps  │ ~1-2 μs      │
│ XDP (Offloaded)  │ ~40+ Mpps    │ ~0.5 μs      │
│ DPDK             │ ~30-40 Mpps  │ ~1 μs        │
└──────────────────┴───────────────┴──────────────┘
※ 実際の値はハードウェアと処理内容に依存

10. ネットワーク名前空間

10.1 ネットワーク名前空間の概要

ネットワーク名前空間は、ネットワークスタック全体を分離する Linux カーネルの機能である。

┌─────────────────────────────────────────────────────────┐
│ ホスト (デフォルト名前空間)                                │
│                                                          │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐   │
│  │ 名前空間 A    │  │ 名前空間 B    │  │ 名前空間 C    │   │
│  │              │  │              │  │              │   │
│  │ eth0 (veth)  │  │ eth0 (veth)  │  │ eth0 (veth)  │   │
│  │ 10.0.1.1/24  │  │ 10.0.2.1/24  │  │ 10.0.3.1/24  │   │
│  │              │  │              │  │              │   │
│  │ ルーティング  │  │ ルーティング  │  │ ルーティング   │   │
│  │ テーブル      │  │ テーブル      │  │ テーブル      │   │
│  │              │  │              │  │              │   │
│  │ iptables     │  │ iptables     │  │ iptables     │   │
│  │ ルール       │  │ ルール       │  │ ルール       │   │
│  └──────┬───────┘  └──────┬───────┘  └──────┬───────┘   │
│         │                  │                  │           │
│         ▼                  ▼                  ▼           │
│  ┌─────────────────────────────────────────────────┐     │
│  │              veth ペア / ブリッジ                 │     │
│  └─────────────────────┬───────────────────────────┘     │
│                        │                                  │
│                    eth0 (物理)                             │
└────────────────────────┴──────────────────────────────────┘

各名前空間が独自に持つリソース:

  • ネットワークインターフェース
  • ルーティングテーブル
  • iptables/nftables ルール
  • ソケット
  • /proc/net/* エントリ
  • ARP テーブル

10.2 ネットワーク名前空間の操作

# 名前空間の作成
ip netns add ns1
ip netns add ns2

# 名前空間の一覧
ip netns list

# veth ペアの作成と名前空間への配置
ip link add veth0 type veth peer name veth1
ip link set veth1 netns ns1

# 名前空間内でインターフェースを設定
ip netns exec ns1 ip addr add 10.0.1.1/24 dev veth1
ip netns exec ns1 ip link set veth1 up
ip netns exec ns1 ip link set lo up

# ホスト側の設定
ip addr add 10.0.1.254/24 dev veth0
ip link set veth0 up

# 名前空間内でコマンド実行
ip netns exec ns1 ping 10.0.1.254
ip netns exec ns1 ss -tnl
ip netns exec ns1 ip route show

# 名前空間間のルーティング
ip netns exec ns1 ip route add default via 10.0.1.254

# IP フォワーディングの有効化 (ホスト側)
sysctl -w net.ipv4.ip_forward=1

# NAT 設定 (名前空間からインターネットへ)
iptables -t nat -A POSTROUTING -s 10.0.1.0/24 -o eth0 -j MASQUERADE

# 名前空間の削除
ip netns del ns1

# nsenter での名前空間移動
nsenter --net=/var/run/netns/ns1 bash

# プロセスの名前空間確認
ls -la /proc/<PID>/ns/net

10.3 Docker/Kubernetes とネットワーク名前空間

# Docker コンテナの名前空間確認
docker inspect -f '{{.State.Pid}}' <container_id>
# PID を使って名前空間に入る
nsenter -t <PID> -n ip addr show

# Kubernetes Pod の名前空間
# crictl で PID を取得
crictl inspect <container_id> | jq '.info.pid'

# 名前空間のリンク (Docker)
pid=$(docker inspect -f '{{.State.Pid}}' my_container)
ln -sf /proc/$pid/ns/net /var/run/netns/my_container
ip netns exec my_container ip addr

11. 仮想ネットワーキング

11.1 veth (Virtual Ethernet) ペア

┌────────────────┐          ┌────────────────┐
│  名前空間 A     │          │  名前空間 B     │
│                │          │                │
│   ┌────────┐   │          │   ┌────────┐   │
│   │ veth-a │   │←────────►│   │ veth-b │   │
│   └────────┘   │  仮想     │   └────────┘   │
│                │  ケーブル  │                │
└────────────────┘          └────────────────┘
# veth ペアの作成
ip link add veth-a type veth peer name veth-b

# MTU 設定
ip link set veth-a mtu 9000
ip link set veth-b mtu 9000

# 統計情報
ip -s link show veth-a
ethtool -S veth-a

11.2 Linux Bridge

┌─────────────────────────────────────────┐
│            Linux Bridge (br0)            │
│                                          │
│    ┌──────┐  ┌──────┐  ┌──────┐         │
│    │port 1│  │port 2│  │port 3│         │
│    └──┬───┘  └──┬───┘  └──┬───┘         │
│       │         │         │              │
│  MAC テーブル (FDB: Forwarding Database) │
│  ┌──────────────────────────────────┐    │
│  │ MAC            │ Port │ VLAN    │    │
│  ├──────────────────────────────────┤    │
│  │ aa:bb:cc:11:.. │ 1    │ -       │    │
│  │ aa:bb:cc:22:.. │ 2    │ -       │    │
│  └──────────────────────────────────┘    │
└────┬────────┬────────┬───────────────────┘
     │        │        │
   veth0    veth1    eth1
     │        │        │
   NS-A     NS-B    物理NW
# ブリッジの作成と設定
ip link add br0 type bridge
ip link set br0 up
ip addr add 10.0.0.1/24 dev br0

# ポートの追加
ip link set eth1 master br0
ip link set veth0 master br0
ip link set veth1 master br0

# STP (Spanning Tree Protocol) の設定
ip link set br0 type bridge stp_state 1
ip link set br0 type bridge priority 32768
ip link set br0 type bridge forward_delay 15

# FDB (MAC アドレステーブル) の表示
bridge fdb show br br0
# aa:bb:cc:11:22:33 dev veth0 master br0

# VLAN フィルタリング
ip link set br0 type bridge vlan_filtering 1
bridge vlan add dev eth1 vid 100 pvid untagged
bridge vlan add dev veth0 vid 200

# ブリッジの詳細情報
bridge link show
brctl showstp br0  # STP 状態

11.3 VXLAN (Virtual Extensible LAN)

Host A (10.0.0.1)                    Host B (10.0.0.2)
┌──────────────────┐                ┌──────────────────┐
│  VM/Container     │                │  VM/Container     │
│  192.168.1.10     │                │  192.168.1.20     │
│       │           │                │       │           │
│  ┌────▼────┐      │                │  ┌────▼────┐      │
│  │  br0    │      │                │  │  br0    │      │
│  └────┬────┘      │                │  └────┬────┘      │
│       │           │                │       │           │
│  ┌────▼────┐      │                │  ┌────▼────┐      │
│  │ vxlan0  │      │                │  │ vxlan0  │      │
│  │VNI:1000 │      │                │  │VNI:1000 │      │
│  └────┬────┘      │                │  └────┬────┘      │
│       │           │                │       │           │
│  ┌────▼────┐      │                │  ┌────▼────┐      │
│  │  eth0   │      │                │  │  eth0   │      │
│  │10.0.0.1 │      │                │  │10.0.0.2 │      │
│  └────┬────┘      │                │  └────┬────┘      │
└───────┼───────────┘                └───────┼───────────┘
        │                                    │
        └────── アンダーレイネットワーク ──────┘
                  (UDP 4789)
VXLAN パケットフォーマット:
┌──────────┬──────────┬──────────┬──────────┬──────────┬──────────┐
│ 外部     │ 外部     │ 外部     │ VXLAN    │ 内部     │ 内部     │
│ Ethernet │ IP       │ UDP      │ Header   │ Ethernet │ IP       │
│          │          │ (dst:4789│ (VNI)    │          │          │
│ 14 bytes │ 20 bytes │ 8 bytes) │ 8 bytes  │ 14 bytes │ ...      │
└──────────┴──────────┴──────────┴──────────┴──────────┴──────────┘
オーバーヘッド: 50 bytes → MTU に注意 (通常 1450 or ジャンボフレーム推奨)
# VXLAN インターフェースの作成
ip link add vxlan0 type vxlan \
    id 1000 \
    dstport 4789 \
    local 10.0.0.1 \
    group 239.1.1.1 \
    dev eth0 \
    ttl 64

# ユニキャストモード
ip link add vxlan0 type vxlan \
    id 1000 \
    dstport 4789 \
    local 10.0.0.1 \
    remote 10.0.0.2 \
    dev eth0

ip link set vxlan0 up
ip link set vxlan0 master br0

# FDB エントリの手動設定
bridge fdb append 00:00:00:00:00:00 dev vxlan0 dst 10.0.0.2  # BUM トラフィック
bridge fdb append aa:bb:cc:dd:ee:ff dev vxlan0 dst 10.0.0.2  # 特定MAC

# VXLAN の確認
ip -d link show vxlan0
bridge fdb show dev vxlan0

11.4 MACVLAN / IPVLAN

MACVLAN モード:
┌─────────────────────────────────────┐
│           物理 NIC (eth0)            │
│           MAC: aa:bb:cc:00:00:00    │
├──────────┬──────────┬───────────────┤
│ macvlan0 │ macvlan1 │ macvlan2      │
│ MAC:..01 │ MAC:..02 │ MAC:..03     │
│ 10.0.0.1 │ 10.0.0.2 │ 10.0.0.3    │
└──────────┴──────────┴───────────────┘

MACVLAN モードの種類:
- bridge:  macvlan 間で直接通信可能
- vepa:    外部スイッチ経由で通信
- private: macvlan 間の通信を禁止
- passthru: 1つの macvlan のみ (NIC を直接利用)
# MACVLAN の作成
ip link add macvlan0 link eth0 type macvlan mode bridge
ip addr add 10.0.0.10/24 dev macvlan0
ip link set macvlan0 up

# IPVLAN の作成 (同一 MAC アドレス)
ip link add ipvlan0 link eth0 type ipvlan mode l2
ip addr add 10.0.0.20/24 dev ipvlan0
ip link set ipvlan0 up

# IPVLAN モード:
# l2: L2 レベルで動作 (ブリッジ相当)
# l3: L3 レベルで動作 (ルーティング)
# l3s: L3 + Source アドレス検証

12. ボンディングとチーミング

12.1 ボンディング (bonding)

┌──────────────────────────────────────┐
│           bond0                       │
│     (論理インターフェース)              │
│           │                           │
│     ┌─────┼─────┐                     │
│     │           │                     │
│   eth0        eth1                    │
│  (slave)    (slave)                   │
│     │           │                     │
│   Switch-A   Switch-B                 │
└──────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ モード    │ 説明                     │ スイッチ要件          │
├───────────┼──────────────────────────┼──────────────────────┤
│ mode 0    │ balance-rr               │ 不要                 │
│ (RR)      │ ラウンドロビン            │ (パケット順序乱れ)    │
├───────────┼──────────────────────────┼──────────────────────┤
│ mode 1    │ active-backup            │ 不要                 │
│           │ アクティブ・スタンバイ     │                      │
├───────────┼──────────────────────────┼──────────────────────┤
│ mode 2    │ balance-xor              │ 不要                 │
│ (XOR)     │ ハッシュベース負荷分散    │ (静的LAG推奨)        │
├───────────┼──────────────────────────┼──────────────────────┤
│ mode 3    │ broadcast                │ 不要                 │
│           │ 全スレーブに送信          │                      │
├───────────┼──────────────────────────┼──────────────────────┤
│ mode 4    │ 802.3ad (LACP)           │ LACP 対応必須        │
│           │ リンクアグリゲーション     │                      │
├───────────┼──────────────────────────┼──────────────────────┤
│ mode 5    │ balance-tlb              │ 不要                 │
│ (TLB)     │ 送信負荷分散             │                      │
├───────────┼──────────────────────────┼──────────────────────┤
│ mode 6    │ balance-alb              │ 不要                 │
│ (ALB)     │ 送受信負荷分散            │                      │
└───────────┴──────────────────────────┴──────────────────────┘
# ボンディングの設定 (ip コマンド)
modprobe bonding

# bond0 の作成
ip link add bond0 type bond mode 802.3ad
ip link set bond0 type bond miimon 100
ip link set bond0 type bond lacp_rate fast
ip link set bond0 type bond xmit_hash_policy layer3+4

# スレーブの追加
ip link set eth0 down
ip link set eth0 master bond0
ip link set eth1 down
ip link set eth1 master bond0

# bond0 の設定
ip addr add 10.0.0.1/24 dev bond0
ip link set bond0 up

# ボンディング状態の確認
cat /proc/net/bonding/bond0
# Bonding Mode: IEEE 802.3ad Dynamic link aggregation
# Transmit Hash Policy: layer3+4 (1)
# MII Status: up
# MII Polling Interval (ms): 100
# LACP rate: fast
#
# Slave Interface: eth0
# MII Status: up
# Speed: 10000 Mbps
# Duplex: full
# Link Failure Count: 0
# Aggregator ID: 1
#
# Slave Interface: eth1
# MII Status: up
# Speed: 10000 Mbps
# Duplex: full

# systemd-networkd での設定例 (/etc/systemd/network/)
# 25-bond0.netdev
# [NetDev]
# Name=bond0
# Kind=bond
# [Bond]
# Mode=802.3ad
# MIIMonitorSec=100ms
# LACPTransmitRate=fast
# TransmitHashPolicy=layer3+4

# 25-bond0.network
# [Match]
# Name=bond0
# [Network]
# Address=10.0.0.1/24
# Gateway=10.0.0.254

12.2 チーミング (teaming)

# teamd による設定
teamd -d -t team0 -c '
{
    "device": "team0",
    "runner": {
        "name": "lacp",
        "active": true,
        "fast_rate": true,
        "tx_hash": ["eth", "ipv4", "ipv6"]
    },
    "link_watch": {
        "name": "ethtool"
    },
    "ports": {
        "eth0": {},
        "eth1": {}
    }
}'

# team0 の設定
ip addr add 10.0.0.1/24 dev team0
ip link set team0 up

# 状態確認
teamdctl team0 state
teamnl team0 ports

13. トラフィック制御 (tc, qdisc)

13.1 TC アーキテクチャ

┌──────────────────────────────────────────────────┐
│              TC (Traffic Control) 構成             │
│                                                   │
│  送信パス:                                        │
│                                                   │
│  アプリケーション                                  │
│       │                                           │
│       ▼                                           │
│  ┌─────────────────────────────┐                  │
│  │   Qdisc (Queuing Discipline)│ ← キューイング   │
│  │   ┌───────────────────────┐ │                  │
│  │   │  Classes              │ │ ← 分類           │
│  │   │  ┌─────────────────┐  │ │                  │
│  │   │  │ Filters         │  │ │ ← フィルタ       │
│  │   │  └─────────────────┘  │ │                  │
│  │   └───────────────────────┘ │                  │
│  └─────────────┬───────────────┘                  │
│                │                                   │
│                ▼                                   │
│           デバイスドライバ                          │
│                                                   │
│  受信パス (ingress):                               │
│                                                   │
│  デバイスドライバ                                   │
│       │                                           │
│       ▼                                           │
│  ┌─────────────────────────────┐                  │
│  │  Ingress Qdisc              │                  │
│  │  (フィルタのみ、キューなし)   │                  │
│  └─────────────────────────────┘                  │
│       │                                           │
│       ▼                                           │
│  ネットワークスタック                               │
└──────────────────────────────────────────────────┘

13.2 主要な Qdisc

クラスレス Qdisc:
┌──────────┬──────────────────────────────────────┐
│ pfifo_fast│ 3バンドの優先度キュー (デフォルト)     │
│ fq       │ Fair Queuing (BBR と組み合わせ推奨)    │
│ fq_codel │ Fair Queuing + CoDel                  │
│ cake     │ Common Applications Kept Enhanced      │
│ tbf      │ Token Bucket Filter                   │
│ sfq      │ Stochastic Fair Queuing               │
│ netem    │ Network Emulator (テスト用)             │
│ noqueue  │ キューなし (ループバック等)              │
└──────────┴──────────────────────────────────────┘

クラスフル Qdisc:
┌──────────┬──────────────────────────────────────┐
│ htb      │ Hierarchical Token Bucket             │
│ hfsc     │ Hierarchical Fair Service Curve        │
│ cbq      │ Class Based Queuing                   │
│ prio     │ Priority Queuing                      │
│ drr      │ Deficit Round Robin                   │
│ mqprio   │ Multi Queue Priority                  │
└──────────┴──────────────────────────────────────┘

13.3 実践的な TC 設定例

# === HTB による帯域制御 ===

# 既存の qdisc を削除
tc qdisc del dev eth0 root 2>/dev/null

# ルート qdisc: HTB
tc qdisc add dev eth0 root handle 1: htb default 30

# ルートクラス: 総帯域 1Gbps
tc class add dev eth0 parent 1: classid 1:1 htb \
    rate 1gbit ceil 1gbit burst 15k

# 子クラス: 高優先度 (VoIP等) - 保証 200Mbps, 最大 500Mbps
tc class add dev eth0 parent 1:1 classid 1:10 htb \
    rate 200mbit ceil 500mbit burst 15k prio 1

# 子クラス: 中優先度 (Web等) - 保証 500Mbps, 最大 1Gbps
tc class add dev eth0 parent 1:1 classid 1:20 htb \
    rate 500mbit ceil 1gbit burst 15k prio 2

# 子クラス: 低優先度 (バックアップ等) - 保証 100Mbps, 最大 500Mbps
tc class add dev eth0 parent 1:1 classid 1:30 htb \
    rate 100mbit ceil 500mbit burst 15k prio 3

# 各クラスに fq_codel を追加
tc qdisc add dev eth0 parent 1:10 handle 10: fq_codel
tc qdisc add dev eth0 parent 1:20 handle 20: fq_codel
tc qdisc add dev eth0 parent 1:30 handle 30: fq_codel

# フィルタ: DSCP マーキングに基づく分類
tc filter add dev eth0 parent 1: protocol ip prio 1 \
    u32 match ip tos 0xb8 0xfc flowid 1:10  # EF (Expedited Forwarding)

tc filter add dev eth0 parent 1: protocol ip prio 2 \
    u32 match ip dport 80 0xffff flowid 1:20
tc filter add dev eth0 parent 1: protocol ip prio 2 \
    u32 match ip dport 443 0xffff flowid 1:20

# === netem: ネットワーク遅延/ロスのシミュレーション ===
# 100ms の遅延を追加
tc qdisc add dev eth0 root netem delay 100ms

# 遅延 + ジッター
tc qdisc add dev eth0 root netem delay 100ms 20ms distribution normal

# パケットロス 1%
tc qdisc add dev eth0 root netem loss 1%

# 帯域制限 (TBF)
tc qdisc add dev eth0 root tbf rate 10mbit burst 32kbit latency 400ms

# 複合: 遅延 + ロス + 帯域制限
tc qdisc add dev eth0 root handle 1: netem delay 50ms loss 0.5%
tc qdisc add dev eth0 parent 1: handle 2: tbf rate 100mbit burst 32kbit latency 400ms

# === FQ (Fair Queuing) - BBR と併用 ===
tc qdisc replace dev eth0 root fq pacing

# === 設定の確認 ===
tc qdisc show dev eth0
tc class show dev eth0
tc filter show dev eth0
tc -s qdisc show dev eth0   # 統計付き

# === Ingress フィルタリング ===
tc qdisc add dev eth0 ingress
tc filter add dev eth0 parent ffff: protocol ip \
    u32 match ip src 10.0.0.0/8 action drop

13.4 CAKE (Common Applications Kept Enhanced)

# CAKE - モダンな AQM + 帯域制御
tc qdisc replace dev eth0 root cake bandwidth 100mbit

# オプション例
tc qdisc replace dev eth0 root cake \
    bandwidth 100mbit \
    rtt 50ms \
    besteffort \
    flowblind \
    nat \
    wash \
    ingress

# ISP の上り制限対策
tc qdisc replace dev eth0 root cake bandwidth 90mbit overhead 44 mpu 84

14. ソケットオプションとチューニング

14.1 主要なソケットオプション

#include <sys/socket.h>
#include <netinet/tcp.h>
#include <netinet/in.h>

int fd = socket(AF_INET, SOCK_STREAM, 0);

/* === SOL_SOCKET レベル === */

/* 送信バッファサイズ */
int sndbuf = 1048576;  /* 1MB */
setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf));

/* 受信バッファサイズ */
int rcvbuf = 1048576;
setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf));

/* アドレス再利用 (TIME_WAIT のポートを即座に再利用) */
int reuse = 1;
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));

/* ポート再利用 (複数プロセスで同一ポートをバインド) */
setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &reuse, sizeof(reuse));

/* Keepalive 有効化 */
int keepalive = 1;
setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &keepalive, sizeof(keepalive));

/* 送信タイムアウト */
struct timeval tv = { .tv_sec = 5, .tv_usec = 0 };
setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));

/* 受信タイムアウト */
setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));

/* タイムスタンプ */
int ts = 1;
setsockopt(fd, SOL_SOCKET, SO_TIMESTAMP, &ts, sizeof(ts));

/* === IPPROTO_TCP レベル === */

/* Nagle アルゴリズムの無効化 (低レイテンシ用) */
int nodelay = 1;
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &nodelay, sizeof(nodelay));

/* Cork (データの蓄積送信) */
int cork = 1;
setsockopt(fd, IPPROTO_TCP, TCP_CORK, &cork, sizeof(cork));

/* Quick ACK モード */
int quickack = 1;
setsockopt(fd, IPPROTO_TCP, TCP_QUICKACK, &quickack, sizeof(quickack));

/* Keepalive パラメータ */
int idle = 60;
setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &idle, sizeof(idle));
int interval = 10;
setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &interval, sizeof(interval));
int maxpkt = 5;
setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &maxpkt, sizeof(maxpkt));

/* 輻輳制御アルゴリズムの設定 */
char cc[] = "bbr";
setsockopt(fd, IPPROTO_TCP, TCP_CONGESTION, cc, strlen(cc));

/* TCP ユーザータイムアウト (ms) */
unsigned int timeout = 30000;  /* 30秒 */
setsockopt(fd, IPPROTO_TCP, TCP_USER_TIMEOUT, &timeout, sizeof(timeout));

/* TCP Fast Open */
int tfo = 5;  /* キューサイズ */
setsockopt(fd, IPPROTO_TCP, TCP_FASTOPEN, &tfo, sizeof(tfo));

/* TCP_INFO の取得 */
struct tcp_info info;
socklen_t len = sizeof(info);
getsockopt(fd, IPPROTO_TCP, TCP_INFO, &info, &len);
printf("State: %d\n", info.tcpi_state);
printf("RTT: %u us\n", info.tcpi_rtt);
printf("RTT variance: %u us\n", info.tcpi_rttvar);
printf("Cwnd: %u\n", info.tcpi_snd_cwnd);
printf("Ssthresh: %u\n", info.tcpi_snd_ssthresh);
printf("Retransmits: %u\n", info.tcpi_retransmits);

/* === IPPROTO_IP レベル === */

/* TOS (Type of Service) */
int tos = IPTOS_LOWDELAY;  /* 0x10 */
setsockopt(fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos));

/* TTL */
int ttl = 64;
setsockopt(fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));

/* マルチキャストグループ参加 */
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = inet_addr("239.1.1.1");
mreq.imr_interface.s_addr = INADDR_ANY;
setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));

14.2 高性能サーバーのソケット設定パターン

/* 高性能 TCP サーバーの設定テンプレート */
int create_high_performance_server(int port)
{
    int fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
    
    /* アドレス再利用 */
    int opt = 1;
    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
    setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt));
    
    /* TCP_NODELAY (低レイテンシ) */
    setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt));
    
    /* TCP_DEFER_ACCEPT (データ到着まで accept を遅延) */
    int defer = 5;
    setsockopt(fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &defer, sizeof(defer));
    
    /* TCP Fast Open */
    int tfo = 1024;
    setsockopt(fd, IPPROTO_TCP, TCP_FASTOPEN, &tfo, sizeof(tfo));
    
    /* バッファサイズ */
    int bufsize = 4 * 1024 * 1024;  /* 4MB */
    setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof(bufsize));
    setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bufsize, sizeof(bufsize));
    
    /* Keepalive */
    opt = 1;
    setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &opt, sizeof(opt));
    int idle = 60, intvl = 10, cnt = 5;
    setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &idle, sizeof(idle));
    setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &intvl, sizeof(intvl));
    setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &cnt, sizeof(cnt));
    
    /* バインドとリッスン */
    struct sockaddr_in addr = {
        .sin_family = AF_INET,
        .sin_port = htons(port),
        .sin_addr.s_addr = INADDR_ANY,
    };
    bind(fd, (struct sockaddr *)&addr, sizeof(addr));
    listen(fd, 65535);
    
    return fd;
}

15. /proc/net/* と /sys/class/net/*

15.1 /proc/net/ の主要ファイル

# === ソケットとコネクション ===

# TCP 接続一覧
cat /proc/net/tcp
#  sl  local_address rem_address   st tx_queue rx_queue tr tm->when ...
#   0: 0100007F:1F90 00000000:0000 0A 00000000:00000000 00:00000000 ...
# st: 0A = LISTEN, 01 = ESTABLISHED, 06 = TIME_WAIT

# TCP6 接続一覧
cat /proc/net/tcp6

# UDP ソケット一覧
cat /proc/net/udp

# UNIX ドメインソケット
cat /proc/net/unix

# Raw ソケット
cat /proc/net/raw

# === プロトコル統計 ===

# SNMP 統計 (TCP/UDP/IP カウンタ)
cat /proc/net/snmp
# Ip: Forwarding DefaultTTL InReceives InHdrErrors ...
# Tcp: RtoAlgorithm RtoMin RtoMax MaxConn ActiveOpens PassiveOpens ...
# Udp: InDatagrams NoPorts InErrors OutDatagrams RcvbufErrors ...
# Icmp: InMsgs InErrors InCmpErrors ...

# ネットワーク統計 (拡張)
cat /proc/net/netstat
# TcpExt: SyncookiesSent SyncookiesRecv SyncookiesFailed ...
# IpExt: InNoRoutes InTruncatedPkts ...

# === ルーティング ===

# ルーティングテーブル
cat /proc/net/route
# Iface   Destination Gateway  Flags RefCnt Use Metric Mask ...

# IPv6 ルート
cat /proc/net/ipv6_route

# FIB 統計
cat /proc/net/fib_trie
cat /proc/net/fib_triestat

# === ARP ===

# ARP テーブル
cat /proc/net/arp
# IP address    HW type  Flags  HW address         Mask  Device
# 10.0.0.1      0x1      0x2    aa:bb:cc:dd:ee:ff  *     eth0

# === デバイス統計 ===

# ネットワークデバイス統計
cat /proc/net/dev
# Inter-|   Receive                                        |  Transmit
#  face |bytes    packets errs drop fifo frame compressed multicast|bytes    ...
#   eth0: 12345678  98765   0    0    0     0      0        0  87654321 ...

# === ソフト割り込み ===

# softnet 統計 (CPU ごと)
cat /proc/net/softnet_stat
# 各行 = CPU コア
# col1: processed   (処理パケット数)
# col2: dropped     (ドロップ数)
# col3: time_squeeze (ポーリング時間不足)

# === Netfilter ===

# conntrack テーブル
cat /proc/net/nf_conntrack
# conntrack エントリ数
cat /proc/sys/net/netfilter/nf_conntrack_count
cat /proc/sys/net/netfilter/nf_conntrack_max

# === ボンディング ===
cat /proc/net/bonding/bond0

15.2 /sys/class/net/ の主要エントリ

# デバイスの一覧
ls /sys/class/net/
# eth0  lo  docker0  br0  veth12345

# === デバイス情報 ===

# MAC アドレス
cat /sys/class/net/eth0/address

# MTU
cat /sys/class/net/eth0/mtu
# MTU の変更
echo 9000 > /sys/class/net/eth0/mtu

# 動作状態
cat /sys/class/net/eth0/operstate  # up/down/unknown

# リンク速度 (Mbps)
cat /sys/class/net/eth0/speed

# インターフェースフラグ
cat /sys/class/net/eth0/flags

# TX キュー長
cat /sys/class/net/eth0/tx_queue_len

# === 統計 ===

# RX/TX 統計 (詳細)
cat /sys/class/net/eth0/statistics/rx_bytes
cat /sys/class/net/eth0/statistics/rx_packets
cat /sys/class/net/eth0/statistics/rx_errors
cat /sys/class/net/eth0/statistics/rx_dropped
cat /sys/class/net/eth0/statistics/tx_bytes
cat /sys/class/net/eth0/statistics/tx_packets
cat /sys/class/net/eth0/statistics/tx_errors
cat /sys/class/net/eth0/statistics/tx_dropped
cat /sys/class/net/eth0/statistics/collisions

# === キュー設定 ===

# RX/TX キュー数
ls /sys/class/net/eth0/queues/
# rx-0  rx-1  rx-2  rx-3  tx-0  tx-1  tx-2  tx-3

# RPS (Receive Packet Steering) CPU マスク
cat /sys/class/net/eth0/queues/rx-0/rps_cpus
# RPS フローテーブルサイズ
cat /sys/class/net/eth0/queues/rx-0/rps_flow_cnt

# XPS (Transmit Packet Steering) CPU マスク
cat /sys/class/net/eth0/queues/tx-0/xps_cpus

# === デバイスドライバ情報 ===
ls /sys/class/net/eth0/device/driver/
readlink /sys/class/net/eth0/device/driver
# ../../../bus/pci/drivers/ixgbe

15.3 /proc/sys/net/ カーネルパラメータ

# === コア設定 ===
# 受信バッファ (デフォルト/最大)
sysctl net.core.rmem_default    # 212992
sysctl net.core.rmem_max        # 212992

# 送信バッファ (デフォルト/最大)
sysctl net.core.wmem_default    # 212992
sysctl net.core.wmem_max        # 212992

# バックログキューサイズ
sysctl net.core.netdev_max_backlog   # 1000
sysctl net.core.netdev_budget        # 300 (NAPI budget)
sysctl net.core.netdev_budget_usecs  # 2000

# somaxconn (listen backlog 上限)
sysctl net.core.somaxconn            # 4096

# === IPv4 設定 ===
# IP フォワーディング
sysctl net.ipv4.ip_forward           # 0

# TCP メモリ (ページ単位)
sysctl net.ipv4.tcp_mem              # min pressure max
sysctl net.ipv4.tcp_rmem             # min default max (バイト)
sysctl net.ipv4.tcp_wmem             # min default max (バイト)

# TCP タイムスタンプ
sysctl net.ipv4.tcp_timestamps       # 1

# TCP ウィンドウスケーリング
sysctl net.ipv4.tcp_window_scaling   # 1

# TCP SACK (Selective ACK)
sysctl net.ipv4.tcp_sack             # 1

# ローカルポート範囲
sysctl net.ipv4.ip_local_port_range  # 32768 60999

# ARP パラメータ
sysctl net.ipv4.neigh.default.gc_thresh1  # 128
sysctl net.ipv4.neigh.default.gc_thresh2  # 512
sysctl net.ipv4.neigh.default.gc_thresh3  # 1024

16. ネットワークパフォーマンスチューニング

16.1 受信パスの最適化

# ============================================
# 1. Ring Buffer サイズの調整
# ============================================
# 現在の設定確認
ethtool -g eth0
# Ring parameters for eth0:
# Pre-set maximums:
# RX:		4096
# TX:		4096
# Current hardware settings:
# RX:		256
# TX:		256

# 最大に設定
ethtool -G eth0 rx 4096 tx 4096

# ============================================
# 2. 割り込みコアレッシング (Interrupt Coalescing)
# ============================================
ethtool -c eth0
# Coalesce parameters for eth0:
# rx-usecs: 3
# rx-frames: 0
# tx-usecs: 3
# tx-frames: 0

# 調整 (スループット重視)
ethtool -C eth0 rx-usecs 100 rx-frames 64
ethtool -C eth0 tx-usecs 100 tx-frames 64

# 調整 (レイテンシ重視)
ethtool -C eth0 rx-usecs 0 rx-frames 1
ethtool -C eth0 adaptive-rx on adaptive-tx on

# ============================================
# 3. RSS (Receive Side Scaling)
# ============================================
# 受信キュー数の確認
ethtool -l eth0
# Channel parameters for eth0:
# Pre-set maximums:
# Combined:	16
# Current hardware settings:
# Combined:	4

# キュー数を増やす
ethtool -L eth0 combined 16

# RSS ハッシュキーとインダイレクションテーブルの確認
ethtool -x eth0
# RX flow hash indirection table for eth0:
#     0:      0     1     2     3     4     5     6     7
#     8:      0     1     2     3     4     5     6     7

# RSS ハッシュフィールドの設定
ethtool -N eth0 rx-flow-hash tcp4 sdfn  # src/dst IP + src/dst port

# ============================================
# 4. RPS (Receive Packet Steering) - ソフトウェア RSS
# ============================================
# 全 CPU を使用 (8 CPU の場合)
echo ff > /sys/class/net/eth0/queues/rx-0/rps_cpus

# 各キューに異なる CPU を割り当て
echo 01 > /sys/class/net/eth0/queues/rx-0/rps_cpus  # CPU 0
echo 02 > /sys/class/net/eth0/queues/rx-1/rps_cpus  # CPU 1
echo 04 > /sys/class/net/eth0/queues/rx-2/rps_cpus  # CPU 2
echo 08 > /sys/class/net/eth0/queues/rx-3/rps_cpus  # CPU 3

# ============================================
# 5. RFS (Receive Flow Steering)
# ============================================
# グローバルフローテーブルサイズ
sysctl -w net.core.rps_sock_flow_entries=32768

# 各キューのフローテーブルサイズ
echo 4096 > /sys/class/net/eth0/queues/rx-0/rps_flow_cnt
echo 4096 > /sys/class/net/eth0/queues/rx-1/rps_flow_cnt

# ============================================
# 6. XPS (Transmit Packet Steering)
# ============================================
# TX キューと CPU のマッピング
echo 01 > /sys/class/net/eth0/queues/tx-0/xps_cpus  # CPU 0
echo 02 > /sys/class/net/eth0/queues/tx-1/xps_cpus  # CPU 1
echo 04 > /sys/class/net/eth0/queues/tx-2/xps_cpus  # CPU 2
echo 08 > /sys/class/net/eth0/queues/tx-3/xps_cpus  # CPU 3

# ============================================
# 7. IRQ アフィニティ
# ============================================
# NIC 割り込みの CPU 割り当て確認
cat /proc/interrupts | grep eth0
#  42:  1234567  0       0       0  IR-PCI-MSI  eth0-TxRx-0
#  43:  0       2345678  0       0  IR-PCI-MSI  eth0-TxRx-1

# IRQ アフィニティの設定
echo 1 > /proc/irq/42/smp_affinity   # CPU 0
echo 2 > /proc/irq/43/smp_affinity   # CPU 1
echo 4 > /proc/irq/44/smp_affinity   # CPU 2
echo 8 > /proc/irq/45/smp_affinity   # CPU 3

# irqbalance の停止 (手動設定時)
systemctl stop irqbalance

16.2 送信パスの最適化

# ============================================
# TCP 送信バッファ
# ============================================
# min default max (バイト)
sysctl -w net.ipv4.tcp_wmem="4096 65536 16777216"

# ============================================
# TCP セグメンテーションオフロード
# ============================================
ethtool -k eth0 | grep offload
# tcp-segmentation-offload: on
# generic-segmentation-offload: on
# generic-receive-offload: on
# large-receive-offload: off

# ============================================
# Pacing (BBR 使用時)
# ============================================
tc qdisc replace dev eth0 root fq pacing

16.3 カーネルパラメータの最適チューニングセット

#!/bin/bash
# ============================================
# 高性能サーバー向けネットワークチューニング
# ============================================

# --- メモリ設定 ---
# TCP バッファ: min=4KB, default=256KB, max=16MB
sysctl -w net.ipv4.tcp_rmem="4096 262144 16777216"
sysctl -w net.ipv4.tcp_wmem="4096 262144 16777216"

# コアバッファ
sysctl -w net.core.rmem_max=16777216
sysctl -w net.core.wmem_max=16777216
sysctl -w net.core.rmem_default=262144
sysctl -w net.core.wmem_default=262144

# TCP メモリ (ページ単位: 4KB)
sysctl -w net.ipv4.tcp_mem="786432 1048576 1572864"

# --- 接続管理 ---
sysctl -w net.core.somaxconn=65535
sysctl -w net.ipv4.tcp_max_syn_backlog=65535
sysctl -w net.core.netdev_max_backlog=65535

# --- 輻輳制御 ---
sysctl -w net.ipv4.tcp_congestion_control=bbr
sysctl -w net.core.default_qdisc=fq

# --- TCP オプション ---
sysctl -w net.ipv4.tcp_timestamps=1
sysctl -w net.ipv4.tcp_sack=1
sysctl -w net.ipv4.tcp_window_scaling=1
sysctl -w net.ipv4.tcp_fastopen=3           # クライアント+サーバー

# --- TIME_WAIT ---
sysctl -w net.ipv4.tcp_tw_reuse=1
sysctl -w net.ipv4.tcp_fin_timeout=15

# --- Keepalive ---
sysctl -w net.ipv4.tcp_keepalive_time=300
sysctl -w net.ipv4.tcp_keepalive_intvl=30
sysctl -w net.ipv4.tcp_keepalive_probes=5

# --- ポート範囲 ---
sysctl -w net.ipv4.ip_local_port_range="1024 65535"

# --- SYN Flood 対策 ---
sysctl -w net.ipv4.tcp_syncookies=1
sysctl -w net.ipv4.tcp_max_tw_buckets=2000000

# --- バックログ ---
sysctl -w net.core.netdev_budget=600
sysctl -w net.core.netdev_budget_usecs=8000

# --- conntrack (ロードバランサー/ファイアウォール向け) ---
sysctl -w net.netfilter.nf_conntrack_max=2000000
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_established=600
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_time_wait=30

# --- ARP ---
sysctl -w net.ipv4.neigh.default.gc_thresh1=4096
sysctl -w net.ipv4.neigh.default.gc_thresh2=8192
sysctl -w net.ipv4.neigh.default.gc_thresh3=16384

# --- IPv6 ---
sysctl -w net.ipv6.conf.all.disable_ipv6=0  # 必要に応じて

# --- ECN (Explicit Congestion Notification) ---
sysctl -w net.ipv4.tcp_ecn=1

echo "ネットワークチューニング完了"

16.4 NUMA 対応の最適化

# NUMA トポロジの確認
numactl --hardware
# node 0 cpus: 0 1 2 3 4 5 6 7
# node 1 cpus: 8 9 10 11 12 13 14 15

# NIC の NUMA ノード確認
cat /sys/class/net/eth0/device/numa_node
# 0

# NIC と同じ NUMA ノードの CPU に IRQ を割り当て
# (eth0 が NUMA node 0 の場合、CPU 0-7 を使用)
for i in $(seq 42 49); do
    echo 0-7 > /proc/irq/$i/smp_affinity_list
done

# アプリケーションも同じ NUMA ノードで実行
numactl --cpunodebind=0 --membind=0 ./my_server
# または
taskset -c 0-7 ./my_server

17. ネットワーク診断・分析ツール

17.1 ss (Socket Statistics)

# ss は netstat の後継で、はるかに高速

# 全 TCP 接続の表示
ss -tan
# State  Recv-Q  Send-Q  Local Address:Port  Peer Address:Port
# LISTEN 0       128     0.0.0.0:80          0.0.0.0:*
# ESTAB  0       0       10.0.0.1:80         10.0.0.2:54321

# Listen ソケット
ss -tnl
# Recv-Q = 現在の Accept Queue 使用数
# Send-Q = Accept Queue の最大サイズ (backlog)

# 接続中のソケット
ss -tn state established

# タイマー情報付き
ss -tno
# timer:(keepalive,24min,0)  or  timer:(on,200ms,3)

# プロセス情報付き
ss -tnp
# ESTAB  0  0  10.0.0.1:80  10.0.0.2:54321  users:(("nginx",pid=1234,fd=5))

# 詳細な TCP 情報
ss -tin
# ESTAB  0  0  10.0.0.1:80  10.0.0.2:54321
#   cubic wscale:7,7 rto:200 rtt:0.5/0.25 ato:40 mss:1448
#   pmtu:1500 rcvmss:1448 advmss:1448 cwnd:10 ssthresh:7
#   bytes_sent:1234 bytes_acked:1234 bytes_received:5678
#   segs_out:100 segs_in:200
#   send 231.7Mbps lastsnd:100 lastrcv:50 lastack:50
#   pacing_rate 462.9Mbps delivery_rate 115.8Mbps

# メモリ使用量付き
ss -tnm
# skmem:(r0,rb131072,t0,tb16384,f0,w0,o0,bl0,d0)
# r=受信キューメモリ, rb=受信バッファサイズ
# t=送信キューメモリ, tb=送信バッファサイズ

# 状態別のフィルタリング
ss -tan state time-wait
ss -tan state syn-recv
ss -tan state fin-wait-1

# ポート/アドレスでフィルタ
ss -tan 'sport = :80'
ss -tan 'dport = :443'
ss -tan 'dst 10.0.0.0/24'
ss -tan '( sport = :80 or sport = :443 )'

# UDP ソケット
ss -uan

# UNIX ドメインソケット
ss -x

# 統計サマリー
ss -s
# Total: 350
# TCP:   256 (estab 200, closed 10, orphaned 0, timewait 10)
# Transport    Total   IP   IPv6
# RAW          0       0    0
# UDP          12      8    4
# TCP          246     200  46
# INET         258     208  50

17.2 ip コマンド

# === インターフェース管理 ===
ip link show                    # 全インターフェース
ip link show dev eth0           # 特定のインターフェース
ip -s link show                 # 統計付き
ip -d link show                 # 詳細情報

ip link set eth0 up             # インターフェース有効化
ip link set eth0 down           # インターフェース無効化
ip link set eth0 mtu 9000       # MTU 変更
ip link set eth0 promisc on     # プロミスキャスモード

# === アドレス管理 ===
ip addr show                    # アドレス一覧
ip addr add 10.0.0.1/24 dev eth0   # アドレス追加
ip addr del 10.0.0.1/24 dev eth0   # アドレス削除
ip addr flush dev eth0          # 全アドレス削除

# === ルーティング ===
ip route show                   # ルーティングテーブル
ip route get 8.8.8.8            # 経路確認
ip route add 10.1.0.0/16 via 10.0.0.254
ip route del 10.1.0.0/16
ip route flush cache            # ルートキャッシュクリア

# === 近隣 (ARP/NDP) ===
ip neigh show
ip neigh add 10.0.0.10 lladdr aa:bb:cc:dd:ee:ff dev eth0
ip neigh flush dev eth0

# === 名前空間 ===
ip netns list
ip netns exec ns1 ip addr show

# === モニタリング ===
ip monitor all                  # リアルタイム変更監視
ip monitor route                # ルーティング変更
ip monitor neigh                # ARP 変更
ip monitor link                 # リンク状態変更

# === トンネル ===
ip tunnel show
ip link add gre1 type gre remote 10.0.0.2 local 10.0.0.1 ttl 64

17.3 ethtool

# 基本情報
ethtool eth0
# Settings for eth0:
#   Speed: 10000Mb/s
#   Duplex: Full
#   Auto-negotiation: on
#   Link detected: yes

# ドライバ情報
ethtool -i eth0
# driver: ixgbe
# version: 5.1.0-k
# firmware-version: 0x800035da

# 統計
ethtool -S eth0 | head -30
# NIC statistics:
#      rx_packets: 123456789
#      tx_packets: 987654321
#      rx_bytes: 12345678901234
#      rx_errors: 0
#      tx_errors: 0

# オフロード設定
ethtool -k eth0
# Features for eth0:
# rx-checksumming: on
# tx-checksumming: on
# scatter-gather: on
# tcp-segmentation-offload: on
# generic-segmentation-offload: on
# generic-receive-offload: on

# オフロードの変更
ethtool -K eth0 tso on gso on gro on lro off

# Ring Buffer
ethtool -g eth0
ethtool -G eth0 rx 4096 tx 4096

# 割り込みコアレッシング
ethtool -c eth0
ethtool -C eth0 adaptive-rx on adaptive-tx on

# チャネル (キュー) 数
ethtool -l eth0
ethtool -L eth0 combined 16

# RSS 設定
ethtool -x eth0                # インダイレクションテーブル
ethtool -X eth0 equal 8        # 8キューに均等分散

# パーマネントMACアドレス
ethtool -P eth0

# リンクテスト
ethtool -t eth0 online

# EEE (Energy Efficient Ethernet)
ethtool --show-eee eth0

# タイムスタンプ機能
ethtool -T eth0

17.4 tc (Traffic Control)

# qdisc の表示 (統計付き)
tc -s qdisc show dev eth0
# qdisc fq_codel 0: root refcnt 2 limit 10240p flows 1024 quantum 1514
#  target 5ms interval 100ms memory_limit 32Mb ecn drop_batch 64
#  Sent 12345678 bytes 98765 pkt (dropped 0, overlimits 0 requeues 0)
#  backlog 0b 0p requeues 0
#   maxpacket 1514 drop_overlimit 0 new_flow_count 100
#   ecn_mark 0 new_flows_len 0 old_flows_len 0

# フィルタの表示
tc filter show dev eth0

# クラスの表示
tc -s class show dev eth0

17.5 iperf3 (ネットワーク帯域テスト)

# サーバー起動
iperf3 -s
iperf3 -s -p 5201 -D  # デーモンモード、ポート指定

# === TCP テスト ===
# 基本テスト
iperf3 -c server_ip -t 30

# マルチストリーム
iperf3 -c server_ip -P 8 -t 30

# 双方向テスト
iperf3 -c server_ip --bidir -t 30

# ウィンドウサイズ指定
iperf3 -c server_ip -w 4M

# JSON 出力
iperf3 -c server_ip -t 30 --json > result.json

# 輻輳制御アルゴリズム指定
iperf3 -c server_ip -C bbr -t 30

# MSS 指定
iperf3 -c server_ip -M 1400

# === UDP テスト ===
# 帯域指定
iperf3 -c server_ip -u -b 1G -t 30

# パケットサイズ指定
iperf3 -c server_ip -u -b 1G -l 1400 -t 30

# === 結果の解釈 ===
# [ ID] Interval       Transfer     Bitrate       Retr  Cwnd
# [  5] 0.00-10.00 sec 1.10 GBytes  941 Mbits/sec  0    3.12 MBytes
# Retr = 再送回数 (0 が理想)
# Cwnd = 輻輳ウィンドウ

17.6 tcpdump

# 基本的なキャプチャ
tcpdump -i eth0
tcpdump -i any                  # 全インターフェース

# フィルタ
tcpdump -i eth0 host 10.0.0.1
tcpdump -i eth0 port 80
tcpdump -i eth0 'tcp port 443 and host 10.0.0.1'
tcpdump -i eth0 'tcp[tcpflags] & (tcp-syn|tcp-fin) != 0'  # SYN/FIN
tcpdump -i eth0 'tcp[tcpflags] & tcp-rst != 0'            # RST

# 詳細表示
tcpdump -i eth0 -v              # 詳細
tcpdump -i eth0 -vv             # より詳細
tcpdump -i eth0 -X              # ヘキサ+ASCII
tcpdump -i eth0 -nn             # 名前解決なし

# ファイル出力
tcpdump -i eth0 -w capture.pcap -c 10000  # 10000 パケットまで
tcpdump -i eth0 -w capture.pcap -G 3600 -W 24  # 1時間ローテ、24ファイル

# ファイルからの読み取り
tcpdump -r capture.pcap
tcpdump -r capture.pcap 'tcp port 80'

# パケットサイズ
tcpdump -i eth0 -s 0            # 全パケットキャプチャ (スナップレン無制限)
tcpdump -i eth0 -s 96           # ヘッダのみ

# TCP ハンドシェイクの分析
tcpdump -i eth0 -nn 'tcp[tcpflags] & (tcp-syn) != 0'

# DNS クエリ
tcpdump -i eth0 -nn port 53

# HTTP リクエスト (暗号化されていない場合)
tcpdump -i eth0 -A 'tcp port 80 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)'

17.7 その他のツール

# === nstat (ネットワーク統計) ===
nstat -z                        # 全カウンタ (ゼロ含む)
nstat -s                        # SNMP 形式
nstat TcpRetransSegs            # 特定カウンタ

# === conntrack (接続追跡) ===
conntrack -L                    # 接続一覧
conntrack -C                    # 接続数
conntrack -S                    # 統計
conntrack -E                    # リアルタイム監視
conntrack -D -s 10.0.0.1        # 特定接続の削除

# === bpftrace (eBPF トレーシング) ===
# TCP 再送の追跡
bpftrace -e 'kprobe:tcp_retransmit_skb {
    printf("retrans: %s:%d -> %s:%d\n",
        ntop(((struct sock *)arg0)->__sk_common.skc_rcv_saddr),
        ((struct sock *)arg0)->__sk_common.skc_num,
        ntop(((struct sock *)arg0)->__sk_common.skc_daddr),
        ((struct sock *)arg0)->__sk_common.skc_dport);
}'

# TCP 接続レイテンシ
bpftrace -e 'kprobe:tcp_v4_connect { @start[tid] = nsecs; }
kretprobe:tcp_v4_connect /@start[tid]/ {
    @usecs = hist((nsecs - @start[tid]) / 1000);
    delete(@start[tid]);
}'

# === perf (パフォーマンス分析) ===
perf top -e net:*               # ネットワーク関連イベント
perf record -e 'net:*' -a -- sleep 10
perf script

# === netperf ===
netperf -H server_ip -t TCP_RR -l 30   # リクエスト/レスポンス
netperf -H server_ip -t TCP_STREAM -l 30  # ストリーム
netperf -H server_ip -t UDP_RR -l 30   # UDP RR

18. まとめとベストプラクティス

18.1 パフォーマンスチューニングのチェックリスト

[ ] NIC Ring Buffer を最大に設定
[ ] RSS (受信キュー数) を CPU コア数に合わせて設定
[ ] IRQ アフィニティを NUMA ノードに合わせて設定
[ ] TCP バッファサイズを適切に設定 (BDP に基づく)
[ ] 輻輳制御アルゴリズムの選択 (BBR 推奨)
[ ] qdisc の設定 (fq + BBR or fq_codel)
[ ] GRO/TSO/GSO の有効化
[ ] somaxconn と tcp_max_syn_backlog の増加
[ ] ローカルポート範囲の拡大
[ ] TIME_WAIT の最適化
[ ] Keepalive パラメータの調整
[ ] conntrack テーブルサイズの調整 (必要な場合)
[ ] ARP テーブルサイズの調整 (大規模環境)

18.2 トラブルシューティングのフロー

問題: パケットドロップ
    │
    ├── NIC レベル?
    │   ├── ethtool -S eth0 | grep -i drop
    │   ├── ethtool -S eth0 | grep -i error
    │   └── Ring Buffer サイズ確認
    │
    ├── カーネルレベル?
    │   ├── cat /proc/net/softnet_stat (time_squeeze)
    │   ├── netdev_max_backlog 確認
    │   └── nstat TcpExtListenOverflows
    │
    ├── ソケットレベル?
    │   ├── ss -tnm (バッファ使用量)
    │   ├── cat /proc/net/snmp (Udp: RcvbufErrors)
    │   └── バッファサイズ確認
    │
    └── アプリケーションレベル?
        ├── アプリケーションの処理速度
        └── epoll/select の効率

問題: 高レイテンシ
    │
    ├── ネットワーク?
    │   ├── ping / mtr / traceroute
    │   └── tcpdump でRTT確認
    │
    ├── TCP 設定?
    │   ├── Nagle + 遅延ACK の相互作用
    │   ├── TCP_NODELAY の設定
    │   └── 輻輳制御アルゴリズム
    │
    └── システム?
        ├── softirq の CPU 使用率
        ├── NUMA ミスマッチ
        └── コンテキストスイッチ

18.3 BDP (Bandwidth Delay Product) に基づくバッファ計算

BDP = 帯域幅 × RTT

例: 10Gbps リンク、RTT = 10ms の場合
  BDP = 10,000,000,000 bits/sec × 0.010 sec
      = 100,000,000 bits
      = 12,500,000 bytes (約 12MB)

→ TCP バッファは最低 12MB に設定

sysctl -w net.ipv4.tcp_rmem="4096 262144 12582912"
sysctl -w net.ipv4.tcp_wmem="4096 262144 12582912"
sysctl -w net.core.rmem_max=12582912
sysctl -w net.core.wmem_max=12582912

18.4 永続的な設定

# /etc/sysctl.d/99-network-tuning.conf に永続化
cat > /etc/sysctl.d/99-network-tuning.conf << 'EOF'
# TCP バッファ
net.ipv4.tcp_rmem = 4096 262144 16777216
net.ipv4.tcp_wmem = 4096 262144 16777216
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216

# 接続管理
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
net.core.netdev_max_backlog = 65535

# 輻輳制御
net.ipv4.tcp_congestion_control = bbr
net.core.default_qdisc = fq

# TCP オプション
net.ipv4.tcp_fastopen = 3
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 15

# ポート範囲
net.ipv4.ip_local_port_range = 1024 65535
EOF

# 適用
sysctl -p /etc/sysctl.d/99-network-tuning.conf

# NIC 設定の永続化 (systemd-networkd)
# /etc/systemd/network/10-eth0.link
cat > /etc/systemd/network/10-eth0.link << 'EOF'
[Match]
MACAddress=aa:bb:cc:dd:ee:ff

[Link]
Name=eth0
MTUBytes=9000
RxBufferSize=4096
TxBufferSize=4096
EOF

参考資料


本ドキュメントは Linux カーネル 5.x/6.x 系列を対象としている。カーネルバージョンによって一部のパラメータや機能が異なる場合がある。