Session Goal
このセッションで終わらせたいこと
Session 01 のゴールは、BGP neighbor を「設定コマンドの束」としてではなく、 「入力が足りると state が進み、足りないと途中で止まるロジック」として説明できるようになることです。
- `peer_ip` だけでは足りない理由を言える
- TCP failure と OPEN failure の違いを言える
- `Established` に至るまでの state 名を追える
- どの `if` で止まったかを source から説明できる
Toy Model Boundary
この lesson で実際に state を進める field
hold_time、keepalive_time、capabilities は realistic な session surface として config に置いています。ただし、この lesson の最小 state machine が実際に branch しているのは peer_ip、tcp_reachable、AS 番号、open_message_ok、keepalive_received です。
Core Idea
BGPSessionConfig が neighbor に必要な入力をまとめる
`session.py` では、neighbor を張るための入力が `BGPSessionConfig` に集められています。 単に `peer_ip` を知っているだけでは成立せず、local AS と remote AS、TCP 到達性、OPEN の成否、KEEPALIVE 受信まで 揃って初めて `Established` まで進みます。
Read The Source
まずは dataclass の field を読む
@dataclass(frozen=True)
class BGPSessionConfig:
peer_ip: str
peer_as: int
local_as: int
tcp_reachable: bool
hold_time: int = 180
keepalive_time: int = 60
capabilities: tuple[BGPCapability, ...] = field(default_factory=tuple)
open_message_ok: bool = True
keepalive_received: bool = True
ここでは pseudo-code を捨てて、実際の field をそのまま読めば十分です。 各入力が欠けたときに、どこで止まるかを考えます。
| field | なぜ必要か |
|---|---|
peer_ip |
TCP の接続先が必要。そもそも相手に届かなければ OPEN まで進まない。 |
peer_as |
相手が想定した AS かどうかを判断するために必要。eBGP / iBGP の区別にも直結する。 |
local_as |
自分が誰として名乗るかが必要。OPEN message に含まれる。 |
tcp_reachable |
BGP は TCP の上に乗る。TCP が張れなければ BGP state machine は進まない。 |
hold_time / keepalive_time |
session を維持するための時間条件。交渉と監視の両方に関わる。 |
capabilities |
Multiprotocol extensions など、何を話せるかの前提を揃えるために必要。 |
Read Order
この順番で読むと迷いにくい
BGPSessionConfigの field を見て、必要入力を先に掴むSessionStateを見て、どんな停止地点があるか知るestablish_neighbor()を上から追って early return を確認する- walkthrough script を実行して、各 scenario がどの state で終わるか見る
State Machine
establish_neighbor() は state の遷移として書ける
def establish_neighbor(config: BGPSessionConfig) -> SessionState:
state = SessionState.IDLE
if not config.peer_ip:
return state
state = SessionState.CONNECT
if not config.tcp_reachable:
return SessionState.ACTIVE
state = SessionState.OPEN_SENT
if config.peer_as <= 0 or config.local_as <= 0:
return state
if not config.open_message_ok:
return state
state = SessionState.OPEN_CONFIRM
if not config.keepalive_received:
return state
return SessionState.ESTABLISHED
「neighbor が張れない」と言うとき、本当はどこで return しているかを見ないといけません。 `ACTIVE` で返るなら TCP 到達性、`OPEN_SENT` で返るなら AS 番号や OPEN negotiation、`OPEN_CONFIRM` で返るなら KEEPALIVE まであと一歩、 という読み方になります。
Failure Reading
if 文のどこで落ちるかを説明できるようにする
1. peer_ip が空ではないか 2. tcp_reachable が true か 3. peer_as と local_as が妥当か 4. open_message_ok が true か 5. keepalive_received が true か
ここで大事なのは、session 失敗を「BGP が壊れた」でまとめないことです。 どの条件が満たされず、どの `if` で止まったかを分けて読むのが `Protocol in Code` の中級コースの狙いです。
Walkthrough
手元で 6 つの scenario を流す
GitHub repo 側には Session 01 用の walkthrough script を置いてあります。 これを流すと、`Idle`、`Active`、`OpenSent`、`OpenConfirm`、`Established` のどこで止まるかをまとめて確認できます。
cd protocol-in-code PYTHONPATH=src python3 examples/bgp/session_01_walkthrough.py
Done Check
Session 01 を終えたと言える条件
- BGP は TCP 到達性の前に始まらない、と説明できる
- AS mismatch や OPEN failure は `OpenSent` 付近の問題だと説明できる
- KEEPALIVE 未達は `OpenConfirm` から `Established` へ進めない問題だと説明できる
- `neighbor が張れない` を 1 つの曖昧な言い方で終わらせず、停止地点を言い分けられる
Next
次は UPDATE を state change として読む
neighbor が `Established` になったあと、何が route table を変えるのかを見るのが Module 02 です。 次は GitHub 上の `update.py` を開いて、UPDATE を `apply_update()` と `withdraw()` の 2 種類の操作として読みます。