Linux Kernel Network Stack
Linux カーネル ネットワークスタック 包括的技術ガイド
本ドキュメントは Linux カーネルのネットワークサブシステムを深掘りし、アーキテクチャの全体像から個々のコンポーネントの実装詳細、パフォーマンスチューニングまでを網羅的に解説する技術文書である。
目次
- ネットワークスタックアーキテクチャ概要
- ソケットレイヤーとソケットバッファ (sk_buff)
- TCP/IP 実装詳細
- TCP 輻輳制御アルゴリズム
- UDP 処理パス
- ルーティングサブシステムと FIB
- 近隣サブシステム (ARP/NDP)
- ネットワークデバイスドライバインターフェース (NAPI)
- XDP (eXpress Data Path)
- ネットワーク名前空間
- 仮想ネットワーキング
- ボンディングとチーミング
- トラフィック制御 (tc, qdisc)
- ソケットオプションとチューニング
- /proc/net/* と /sys/class/net/*
- ネットワークパフォーマンスチューニング
- ネットワーク診断・分析ツール
- まとめとベストプラクティス
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 Kernel Networking: Implementation and Theory (Rami Rosen)
- Understanding Linux Network Internals (Christian Benvenuti)
- Linux Kernel Source Code: https://github.com/torvalds/linux
- Linux Networking Documentation: https://www.kernel.org/doc/html/latest/networking/
- Brendan Gregg's Blog: https://www.brendangregg.com/
- LKML (Linux Kernel Mailing List)
本ドキュメントは Linux カーネル 5.x/6.x 系列を対象としている。カーネルバージョンによって一部のパラメータや機能が異なる場合がある。