ubuntu 18のsrextでクラウド間SRv6 End.dx4を試す

# モチベーション
ubuntuのiproute2のipコマンドではSRv6のend.dx4がうまく機能しなかった。最新のiproute2コンパイルしてもダメだった。kernel 4.14で実装されたはずなのに。でも**srext**を試してみたら動いた。その時の忘備録。

###LinuxのSRv6 Endの対応状況
|Name	|Description	|Release|
|:--|:--|:--|
|End	|Endpoint function	|4.10 (February 2017), srext|
|End.X	|Endpoint function with Layer-3 cross-connect	|4.10 (February 2017), srext|
|End.T	|Endpoint function with specific IPv6 table lookup	|4.14 (November 2017)|
|End.DX2	|Endpoint with decapsulation and Layer-2 cross-connect	|4.14 (November 2017), srext|
|End.DX6	|Endpoint with decapsulation and IPv6 cross-connect	|4.14 (November 2017), srext|
|<b>End.DX4</b>	|<b>Endpoint with decapsulation and IPv4 cross-connect</b>	|4.14 (November 2017), <b>srext</B>|
|End.DT6	|Endpoint with decapsulation and IPv6 table lookup	|4.14 (November 2017)|
|End.DT4	|Endpoint with decapsulation and IPv4 table lookup	|In development|
|End.B6	|Endpoint bound to an SRv6 policy	|4.14 (November 2017)|
|End.B6.Encaps	|Endpoint bound to an SRv6 encapsulation Policy	|4.14 (November 2017)|
|End.BM	|Endpoint bound to an SR-MPLS Policy	|In development|
|End.S	|Endpoint in search of a target in table T	|In development|
|End.AD	|Endpoint to SR-unaware APP via dynamic proxy	|srext|
|End.AM	|Endpoint to SR-unaware APP via masquerading	|srext|


##srextとは
新しい目のSegment Routingの機能を実装した拡張linux カーネルモジュール
https://github.com/netgroup/SRv6-net-prog


##実験内容

中国人意外のアカウントではまだ使えないが、**Alibaba Cloudの中国アカウントのみで内モンゴルリージョンでIPv6が使える**。SRv6でIPv4をencapして日中間通信できないか？色々頑張って見たらできた。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/132165/a0ac45c4-0456-1090-4d9d-b6c60757c844.png)



```
# 動かなかったipコマンド
ip -6 route add 2406:xxxx:xxxx:xxxx::10 encap seg6local action End.DX4 nh4 10.0.0.70 dev eth0
# 動いた等価なsrextのコマンド
srconf localsid add 2406:xxxx:xxxx:xxxx::10 end.dx4 ip 10.0.0.70 eth0 
```
ちなみに本日2019/3/3時点で日本人が中国でIPv6を使えるパブリッククラウドのインスタンスを立ち上げるのはまだかなり敷居が高い。チャレンジしてみたい人は[こちら](https://qiita.com/makotaka/items/025d22dc6aadd9dd6523)参照。


# Install
ubuntu 18.04と18.10でインストール方法が異なる。

## Ubuntu 18.04の場合
現行srextはubuntu 18.04のデフォルトであるkernel 4.15に対応していないので、過去のバージョンをcheckoutして使う。


```
# apt update 
# apt -y install gcc make git 
# git clone https://github.com/netgroup/SRv6-net-prog 
# cd SRv6-net-prog/
# git checkout 76a6d8398bfb12b801a74de71897159b0aa8ad34
# cd srext
# make
# make install
# depmod -a
# modprobe srext
```

ip6_route_input_lookupの引数に変更があったようで、最新バージョンのファイルを手で直しても行けた。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/132165/e7a01ae9-5cfe-70fa-7479-d95740b0563a.png)

## Ubuntu 18.10の場合
こちらは現行srext対応kernelなので特に意識しなくともOK。

```
# apt update 
# apt -y install gcc make git 
# git clone https://github.com/netgroup/SRv6-net-prog 
# cd SRv6-net-prog/srext
# make
# make install
# depmod -a
# modprobe srext

```

## SRv6有効化
/etc/sysctl.conf に下記を追加

```
# Alibaba CloudはデフォルトでIPv6がdisableになってるので下記4行で有効化する。AWSは不要。
net.ipv6.conf.all.disable_ipv6=0
net.ipv6.conf.default.disable_ipv6=0
net.ipv6.conf.lo.disable_ipv6=0
net.ipv6.conf.eth0.disable_ipv6 =0

# Segment routing 有効化、hmacは面倒なので今は無効化
net.ipv6.conf.all.seg6_require_hmac = 0
net.ipv6.conf.all.seg6_enabled=1
net.ipv6.conf.default.seg6_enabled=1
net.ipv6.conf.eth0.seg6_enabled=1
net.ipv6.conf.lo.seg6_enabled=1

# forwarding有効化
net.ipv4.conf.all.forwarding=1
net.ipv6.conf.all.forwarding=1
```

/etc/sysctl.conf の設定を反映させる

```
# sysctl -p
```

##設定（阿里云＞Public DNS方向）
### T.Encaps側(阿里云)
とりあえずT.Encapsはipコマンドで問題なさそう。

```
ip route add  8.8.8.8/32 encap seg6 mode encap segs 2406:xxxx.xxxx.xxxx::10 dev eth0
```

###End.Dx4側(AWS)

```
# srconf localsid add 2406:xxxx:xxxx:xxxx::10 end.dx4 ip 10.0.0.70 eth0
```

##設定（Public DNS＞阿里云方向）
この戻りの方向がはるかに難しい。パブリッククラウドはネットワークの制約が色々あって裏技的な方法でしか成功していない。。。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/132165/7450c75c-3af2-223e-9573-f2333f12805f.png)


### ネットワーク設計

- AWSと阿里云で同じprefixを使う(ここでは10.0.0.0/24)
- AWSでは必ずNAT gatewayをend.dx4のクロスコネクト先として使う。iptablesでmasqueradeしてVPCルータへクロスコネクトしてEIPで出て行く方法は私は成功しなかった。該当パケットに対してiptablesのnat tableのPOSTROUTING chainが機能しないように見える。
- AWSのEC2インスタンスのセカンダリーIPとして阿里云のIPアドレスを設定する。ここでは10.0.0.83。os上はセカンダリーIPをinterfaceに直接設定しない。下記はAWSのECSのステータス

```
# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc fq_codel state UP group default qlen 1000
    link/ether 0a:37:0d:59:9d:9c brd ff:ff:ff:ff:ff:ff
    inet 10.0.0.10/24 brd 10.0.0.255 scope global dynamic eth0
       valid_lft 2811sec preferred_lft 2811sec
    inet6 2406:xxxx:xxxx:xxxx::10/128 scope global dynamic noprefixroute 
       valid_lft 384sec preferred_lft 84sec
    inet6 fe80::837:dff:fe59:9d9c/64 scope link 
       valid_lft forever preferred_lft forever
# ip route
default via 10.0.0.1 dev eth0 proto dhcp src 10.0.0.10 metric 100 
10.0.0.0/24 dev eth0 proto kernel scope link src 10.0.0.10 
10.0.0.1 dev eth0 proto dhcp scope link src 10.0.0.10 metric 100 
10.0.0.83  encap seg6 mode encap segs 1 [ 2408:xxxx:xxxx:xxxxx::1 ] dev eth0 scope link 
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/132165/44350382-26ca-2b32-76b0-1bd4caec97a4.png)

- AWSの該当インスタンスの**送信元/送信先の変更チェック**を無効にする

![image.png](https://qiita-image-store.s3.amazonaws.com/0/132165/980f0577-6993-7360-268f-30ce5cfe2b39.png)


### T.Encaps側(AWS)

```
ip route add  10.0.0.83/32 encap seg6 mode encap segs 2408:xxxx:xxxx:xxxx::1 dev eth0
```

### End.Dx4側(阿里云)

```
srconf localsid add 2408:xxxx:xxxx:xxxx::1  end.dx4 ip 10.0.0.83 lo
```

### テスト
```
# dig www.google.com @8.8.8.8

; <<>> DiG 9.11.3-1ubuntu1.5-Ubuntu <<>> www.google.com @8.8.8.8
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 62463
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;www.google.com.			IN	A

;; ANSWER SECTION:
www.google.com.		225	IN	A	172.217.27.68

;; Query time: 232 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Sun Mar 03 17:17:07 CST 2019
;; MSG SIZE  rcvd: 59

```


# 備考
## iproute2のip routeコマンド、期待通り機能せず！
キャプチャしてみると理解できないheader typeだというICMPエラーメッセージを返しているみたい。


```
# ip -6 route add 2406:xxxx:xxxx:xxxx::10 encap seg6local action End.DX4 nh4 10.0.0.70 dev eth0
# tshark -f'ip6'
    1 0.000000000    10.0.0.83 → 8.8.8.8      ICMP 162 Echo (ping) request  id=0x5c2c, seq=29/7424, ttl=64
    2 0.000036491 2406:xxxx:xxxx:xxxx::10 → 2408:xxxx:xxxx:xxxx::1 ICMPv6 210 Parameter Problem (unrecognized Next Header type encountered)
```

色々勘違いしてたり、間違ってたら色々指摘お願いします！
私の理解が足りないのかもしれないけど、パケットヘッダー自体は変じゃないように見える。ちなみにend.dx6はほぼ同じ設定でiproute2だけで期待通り動いた。webで検索する限り、きちんと動かしている人たちの設定との差分はみなさんlocalsidにループバックアドレスを使ってるけど、私はeth0のアドレスを使っているところかな？仕様上実インターフェースのeht0でもokでは？パブリッククラウドのインスタンス使ってるのでループバックアドレスに自由にアドレスアサインして使うのは厳しいんですわ。
以下のパケットに対してiproute2のend.dx4設定では処理できずにICMPエラー返すけど拡張モジュールのsrextは私が期待した処理する。segment leftがゼロ、next headerがIPIPなのでsrextの挙動が正しい気がしますがどうでしょ？

```
# tshark -f'ip6' -V

Frame 1: 162 bytes on wire (1296 bits), 162 bytes captured (1296 bits) on interface 0
    Interface id: 0 (eth0)
        Interface name: eth0
    Encapsulation type: Ethernet (1)
    Arrival Time: Mar  3, 2019 07:07:36.102696292 UTC
    [Time shift for this packet: 0.000000000 seconds]
    Epoch Time: 1551596856.102696292 seconds
    [Time delta from previous captured frame: 0.000000000 seconds]
    [Time delta from previous displayed frame: 0.000000000 seconds]
    [Time since reference or first frame: 0.000000000 seconds]
    Frame Number: 1
    Frame Length: 162 bytes (1296 bits)
    Capture Length: 162 bytes (1296 bits)
    [Frame is marked: False]
    [Frame is ignored: False]
    [Protocols in frame: eth:ethertype:ipv6:ipv6.routing:ip:icmp:data]
Ethernet II, Src: 0a:28:0d:b8:c3:b4 (0a:28:0d:b8:c3:b4), Dst: 0a:37:0d:59:9d:9c (0a:37:0d:59:9d:9c)
    Destination: 0a:37:0d:59:9d:9c (0a:37:0d:59:9d:9c)
        Address: 0a:37:0d:59:9d:9c (0a:37:0d:59:9d:9c)
        .... ..1. .... .... .... .... = LG bit: Locally administered address (this is NOT the factory default)
        .... ...0 .... .... .... .... = IG bit: Individual address (unicast)
    Source: 0a:28:0d:b8:c3:b4 (0a:28:0d:b8:c3:b4)
        Address: 0a:28:0d:b8:c3:b4 (0a:28:0d:b8:c3:b4)
        .... ..1. .... .... .... .... = LG bit: Locally administered address (this is NOT the factory default)
        .... ...0 .... .... .... .... = IG bit: Individual address (unicast)
    Type: IPv6 (0x86dd)
Internet Protocol Version 6, Src: 2408:xxxx:xxxx:xxxx::1, Dst: 2406:xxxx:xxxx:xxxx::10
    0110 .... = Version: 6
    .... 0000 0000 .... .... .... .... .... = Traffic Class: 0x00 (DSCP: CS0, ECN: Not-ECT)
        .... 0000 00.. .... .... .... .... .... = Differentiated Services Codepoint: Default (0)
        .... .... ..00 .... .... .... .... .... = Explicit Congestion Notification: Not ECN-Capable Transport (0)
    .... .... .... 0000 0000 0000 0000 0000 = Flow Label: 0x00000
    Payload Length: 108
    Next Header: Routing Header for IPv6 (43)
    Hop Limit: 231
    Source: 2408:xxxx:xxxx:xxxx::1
    Destination: 2406:xxxx:xxxx:xxxx::10
    Routing Header for IPv6 (Segment Routing)
        Next Header: IPIP (4)
        Length: 2
        [Length: 24 bytes]
        Type: Segment Routing (4)
        Segments Left: 0
        First segment: 0
        Flags: 0x00
            0... .... = Unused: 0x0
            .0.. .... = Protected: False
            ..0. .... = OAM: False
            ...0 .... = Alert: Not Present
            .... 0... = HMAC: Not Present
            .... .000 = Unused: 0x0
            [Expert Info (Note/Undecoded): Dissection for SRH TLVs not yet implemented]
                [Dissection for SRH TLVs not yet implemented]
                [Severity level: Note]
                [Group: Undecoded]
        Reserved: 0000
        Address[0]: 2406:xxxx:xxxx:xxxx::10
        [Segments in Traversal Order]
            Address[0]: 2406:xxxx:xxxx:xxxx::10
Internet Protocol Version 4, Src: 10.0.0.83, Dst: 8.8.8.8
    0100 .... = Version: 4
    .... 0101 = Header Length: 20 bytes (5)
    Differentiated Services Field: 0x00 (DSCP: CS0, ECN: Not-ECT)
        0000 00.. = Differentiated Services Codepoint: Default (0)
        .... ..00 = Explicit Congestion Notification: Not ECN-Capable Transport (0)
    Total Length: 84
    Identification: 0x9f34 (40756)
    Flags: 0x4000, Don't fragment
        0... .... .... .... = Reserved bit: Not set
        .1.. .... .... .... = Don't fragment: Set
        ..0. .... .... .... = More fragments: Not set
        ...0 0000 0000 0000 = Fragment offset: 0
    Time to live: 64
    Protocol: ICMP (1)
    Header checksum: 0x8112 [validation disabled]
    [Header checksum status: Unverified]
    Source: 10.0.0.83
    Destination: 8.8.8.8
Internet Control Message Protocol
    Type: 8 (Echo (ping) request)
    Code: 0
    Checksum: 0x1e65 [correct]
    [Checksum Status: Good]
    Identifier (BE): 23596 (0x5c2c)
    Identifier (LE): 11356 (0x2c5c)
    Sequence number (BE): 344 (0x0158)
    Sequence number (LE): 22529 (0x5801)
    Timestamp from icmp data: Mar  3, 2019 07:07:36.000000000 UTC
    [Timestamp from icmp data (relative): 0.102696292 seconds]
    Data (48 bytes)

0000  08 6a 01 00 00 00 00 00 10 11 12 13 14 15 16 17   .j..............
0010  18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27   ........ !"#$%&'
0020  28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37   ()*+,-./01234567
        Data: 086a010000000000101112131415161718191a1b1c1d1e1f...
        [Length: 48]

```

##課題
実はtcp、例えばcurl/wgetだとまだうまくいってない。パケットは変じゃないように見えるので戻ったパケットの扱いの問題なんだろうね。要追加研究。

## 参考
以下、大変参考になりました。

SRv6 using iproute2/quagga (End.DX4/L3VPN)
https://qiita.com/naotomatsumoto/items/a1fe19daa124e3101d83

Linux kernel 4.14以降でのSRv6設定(2018/06/08時点で検証中)
https://www.wavesplitter.jp/index.php/191/linux-kernel-414srv6

## 最後に
以上は私の趣味の領域です。所属するいかなる組織の考え方も反映していません。