Linuxで使用できるSRv6 Behaviorの動作とiproute2コマンドのまとめ

研究でSRv6のBehaviorをまとめているのですが，記事にも残そうということで書きます．

## はじめに

LinuxでSRv6ネットワークを動かしていると，SRv6の挙動を調べたいときがよくあります．
トラブルシューティングのときとかは特に，LinuxのソースコードやRFCを読んでいます．
毎回RFCを漁るのも読んで理解するのも面倒なので，備忘録として残します．LinuxでSRv6を学習している人の一助となれば嬉しいです．

図は，[Zashas/Thesis-SRv6-BPF](https://github.com/Zashas/Thesis-SRv6-BPF)や[Ciscoの資料](https://www.cisco.com/c/dam/assets/sol/service-provider/digital-transformation/pdfs/0912-msn-ckn.pptx)を参考に作成しています．

## 動作確認環境

iproute2のコマンドは，以下の環境で動作確認しています．

- Ubuntu:22.04
- Linux: 6.4.6
    - https://kernel.ubuntu.com/mainline/v6.4.6/amd64/ からダウンロードしてインストール
- iproute2: 6.5.0
    - https://mirrors.edge.kernel.org/pub/linux/utils/net/iproute2/

## SRv6 behavior

SRv6のSIDは，以下の構造となっています．

![srv6_sid.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2661127/f9721201-29c2-01c4-2d54-7f84bca40b57.png)

- LOC: SIDを保有するノードへルーティングするための情報
- FUNCT: SIDを保有するノードで実施される処理を指定する値
- ARG: FUNCTで使用される値

このFUNCTで指定できる処理そのものをBehaviorと呼びます．

## SR Policy headend behaviors

SR Policy Headend behaivorでは，パケットにSRポリシー(SRH)を関連付けます．

### H.Encaps [(RFC8986)](https://datatracker.ietf.org/doc/html/rfc8986#section-5.1)

H.Encapsでは，パケットをSRHとIPv6ヘッダで新たにカプセル化します．カプセル化するIPv6ヘッダの送信元はH.Encapsを行うノードのアドレスであり，宛先はSegment List[Segment Left] のアドレスです．

iproute2での設定は以下です．

```bash
# ip -6 route add <ipv6 prefix> encap seg6 mode encap segs <segs> dev <intf>
ip -6 route add fd00:beef::/32 encap seg6 mode encap segs fd00:a::,fd00:b::,fd00:c:: dev eth1
```

![head_encap.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2661127/14d2cf27-4a38-95ae-aa6f-07cec5c75174.png)


### H.Insert [(****draft-filsfils-spring-srv6-net-pgm-insertion-09****)](https://www.ietf.org/archive/id/draft-filsfils-spring-srv6-net-pgm-insertion-09.html#name-endb6insert-endpoint-bound-)

H.Insertは，IPv6パケットに対してSRHを付加します．また，元の宛先は，SegmetList[0]に格納されます．

iproute2での設定は以下です．

```bash
# ip -6 route add <ipv6 prefix> encap seg6 mode inline segs <segs> dev <intf>
ip -6 route add fd00:beef::/32 encap seg6 mode inline segs fd00:a::,fd00:b:: dev eth1
```

![head_insert.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2661127/2d90ed38-4b00-593b-bf6b-d0887fbb0f0c.png)


## SRv6 Endpoint behavior

Endpoint behaviorとは，パケットで指定されたセグメントを持つノードで行われる処理のことです．
以下で詳細を説明します．なお，説明で使用するFunctionの値は，[IANAのSRv6 Endpoint Behaviors Registory](https://www.iana.org/assignments/segment-routing/segment-routing.xhtml)を参考にしています．


### End [(RFC8986)](https://datatracker.ietf.org/doc/html/rfc8986#name-end-endpoint)

Endは，SegmentLeftをデクリメントし，IPv6宛先アドレスを書き換えてFIBから宛先を検索して送信します．

また，以下の以下の場合分けがあります．

- SegmentLeftが0の場合は，SRH処理は行わず，SRH直後のヘッダーを処理します．
- Hoplimitが1以下である場合，Code0でICMP Time Exceededを送信します．
- SRHの更新処理の前に，SRHのLast EntryがSRHより外を参照していないことと，SRHのSegmentLeftがLast Entry + 1を超えていないことを検証し，違反している場合にはCode0のICMP Parameter Problemを送信します．

iproute2での設定は以下です．

```bash
# ip -6 route add <ipv6 prefix> encap seg6local action End [flavors <flavors>] dev <intf>
ip -6 route add fd00:a::1/128 encap seg6local action End dev eth1
ip -6 route add fd00:a::3/128 encap seg6local action End flavors usp dev eth1
ip -6 route add fd00:100::/32 encap seg6local action End flavors next-csid dev eth1
```

![end.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2661127/cb1887df-c87d-2074-c486-f5ef22047b44.png)


### End.T [(RFC8986)](https://datatracker.ietf.org/doc/html/rfc8986#section-4.3)

End.Tは，SegmentLeftをデクリメントし，IPv6宛先アドレスを書き換えて指定したネクストホップに送信します．また，Endでの場合分け処理もあります．

iproute2での設定は以下です．

```bash
# ip -6 route add <ipv6 prefix> encap seg6local action End.T table <table id> dev <intf>
ip -6 route add fd00:a::9/128 encap seg6local action End.T table 10 dev eth1
```

![end_t.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2661127/665a1b84-ded5-317e-e2ab-54121e2a7bdc.png)


### End.X [(RFC8986)](https://datatracker.ietf.org/doc/html/rfc8986#name-endx-l3-cross-connect)

End.Xは，SegmentLeftをデクリメントし，IPv6宛先アドレスを書き換えて指定したテーブルから宛先を検索して送信します．また，Endでの場合分け処理もあります．

iproute2での設定は以下です．

```bash
# ip -6 route add <ipv6 prefix> encap seg6local action End.X nh6 <next hop> dev <intf>
ip -6 route add fd00:a::5/128 encap seg6local action End.X nh6 fd00::1 dev eth1
```

![end_x.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2661127/ae71703f-04e4-f66d-44c4-4c01f5950866.png)


### End.DX6 [(RFC8986)](https://datatracker.ietf.org/doc/html/rfc8986#name-enddx6-decapsulation-and-ip)

End.DX6は，SRHを削除して，指定されたIPv6ネクストホップに送信します．End.DX6のSegmentはLast Segment(SegmentList[0]のセグメント)である必要があるため，SegmentLeftが0でない場合は，Code0のICMP Parameter Problemを送信します．

iproute2での設定は以下です．

```bash
# ip -6 route add <ipv6 prefix> encap seg6local action End.DX6 nh6 <next hop> dev <intf>
ip -6 route add fd00:a::10/128 encap seg6local action End.DX6 nh6 fd00::1 dev eth1
```

![end_dx6.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2661127/115347bc-f53d-73eb-1e16-892349618b84.png)


### End.DX4 [(RFC8986)](https://datatracker.ietf.org/doc/html/rfc8986#name-enddx4-decapsulation-and-ip)

End.DX4は，SRHを削除して，指定されたIPv4ネクストホップに送信します．End.DX4のSegmentはLast Segmentである必要があるため，SegmentLeftが0でない場合は，Code0のICMP Parameter Problemを送信します．

iproute2での設定は以下です．

```bash
# ip -6 route add <ipv6 prefix> encap seg6local action End.DX4 nh4 <next hop> dev <intf>
ip -6 route add fd00:a::11/128 encap seg6local action End.DX4 nh4 192.168.0.1 dev eth1
```

![end_dx4.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2661127/2258ae00-c1c9-f24d-b75b-eb4af991aa16.png)


### End.DT6 [(RFC8986)](https://datatracker.ietf.org/doc/html/rfc8986#name-enddt6-decapsulation-and-sp)

End.DT6は，SRHを削除して，指定されたIPv6のFIBテーブルから宛先を検索して送信します．End.DT6のSegmentはLast Segmentである必要があるため，SegmentLeftが0でない場合は，Code0のICMP Parameter Problemを送信します．

iproute2での設定は以下です．

```bash
# ip -6 route add <ipv6 prefix> encap seg6local action End.DT6 {table | vrftable} <table id> dev <intf>
ip -6 route add fd00:a::12/128 encap seg6local action End.DT6 table 10 dev eth1
ip -6 route add fd00:a::12/128 encap seg6local action End.DT6 vrftable 10 dev eth1
```

![end_dt6.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2661127/3dcdf614-f41f-852b-2b68-4c09e5b9c0e3.png)


### End.DT4 [(RFC8986)](https://datatracker.ietf.org/doc/html/rfc8986#name-enddt4-decapsulation-and-sp)

End.DT4は，SRHを削除して，指定されたIPv4のFIBテーブルから宛先を検索して送信します．End.DT4のSegmentはLast Segmentである必要があるため，SegmentLeftが0でない場合は，Code0のICMP Parameter Problemを送信します．

iproute2での設定は以下です．

```bash
# ip -6 route add <ipv6 prefix> encap seg6local action End.DT4 vrftable <table id> dev <intf>
ip -6 route add fd00:a::13/128 encap seg6local action End.DT4 vrftable 10 dev eth1
```

![end_dt4.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2661127/b43a521c-bb7d-3646-daf5-04200d72662f.png)


### End.DT46 [(RFC8986)](https://datatracker.ietf.org/doc/html/rfc8986#name-enddt46-decapsulation-and-s)

End.DT46は，SRHを削除して，指定されたFIBテーブルから宛先を検索して送信します．End.DT46のSegmentはLast Segmentである必要があるため，SegmentLeftが0でない場合は，Code0のICMP Parameter Problemを送信します．

iproute2での設定は以下です．

```bash
# ip -6 route add <ipv6 prefix> encap seg6local action End.DT46 vrftable <table id> dev <intf>
ip -6 route add fd00:a::14/128 encap seg6local action End.DT46 vrftable 10 dev eth1
```

![end_dt46.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2661127/cf9d66ae-83d0-c9d1-2a86-aec58c2387ed.png)


### End.B6.Encaps  [(RFC8986)](https://datatracker.ietf.org/doc/html/rfc8986#name-endb6encaps-endpoint-bound-)

End.B6.Encapsは，SegmentLeftをデクリメントし，新しいSRHとIPv6ヘッダでカプセル化して送信します．

iproute2での設定は以下です．

```bash
# ip -6 route add <ipv6 prefix> encap seg6local action End.B6.Encaps srh segs <segs>  [hmac <key id>] dev <intf>
ip -6 route add fd00:a::e/128 encap seg6local action End.B6.Encaps srh segs fd00:aa::,fd00:bb:: dev eth1
```

![end_b6_encap.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2661127/883591b2-ceff-bca9-ee3a-bbb295afa1ac.png)


### End.B6 (End.B6.Insert) [(****draft-filsfils-spring-srv6-net-pgm-insertion-09****)](https://www.ietf.org/archive/id/draft-filsfils-spring-srv6-net-pgm-insertion-09.html#name-endb6insert-endpoint-bound-)

End.B6.Insertは，指定されたSegment List (SRH)をパケットに新たに追加します．

End.B6.InsertはLast Segmentでない必要があるので，Segment Leftが0の場合，ICMP Parameter Problemメッセージを送信します．また，IPv6宛先アドレスは，新しいSegmentListで更新され，元のSRHのSegment Leftはデクリメントされません．

iproute2での設定は以下です．

```bash
# ip -6 route add <ipv6 prefix> encap seg6local action End.B6 srh segs <segs>  [hmac <key id>] dev <intf>
ip -6 route add fd00:a::d/128 encap seg6local action End.B6 srh segs fd00:aa::,fd00:bb:: dev eth1 
```

![end_b6.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2661127/c17aff0f-cb1a-2bb8-e15b-3e0d3fadc736.png)


## おわりに

まだL2VPNの挙動など調べきれていない部分があるので，将来的にそのあたりも調べたいと思っています．

## 参考文献
- [RFC8986](https://datatracker.ietf.org/doc/rfc8986/)
-  [draft-filsfils-spring-srv6-net-pgm-insertion-09](https://www.ietf.org/archive/id/draft-filsfils-spring-srv6-net-pgm-insertion-09.html)
- [ip-route(8) - Linux manual page](https://man7.org/linux/man-pages/man8/ip-route.8.html)
- [Zashas/Thesis-SRv6-BPF](https://github.com/Zashas/Thesis-SRv6-BPF)
- https://www.cisco.com/c/dam/assets/sol/service-provider/digital-transformation/pdfs/0912-msn-ckn.pptx
- [tinynetwork/tinet/examples/basic_srv6](https://github.com/tinynetwork/tinet/tree/master/examples/basic_srv6)