VNet peering された 2 つの Hub に、それぞれ ExpressRoute で接続された VNet 同士を、通信可能にする
TL;DR
- オンプレミス #1 - [ER] -> VNet #1 -> VNet #2 -> [ER] - オンプレミス #2 という構成を作る
- この構成を実現するための手段の 1 つとして VXLAN と FRRouting を使う
- サンプルの Bicep ファイルもおつけしておきました
ぷりふぇーす
文字で表現するとなかなかわかりづらいと思いますが、こちらのアーキテクチャっぽいのものを作ります。
インフラの準備
Bicep ファイルはこちらです。
以下のリソースが大体 1 時間もあれば作られるかと思います。
- VNet x4
- [existing] ExpressRoute circuit x2
- ExpressRoute Gateway x4
- Connection (for ExpressRoute) x4
- Azure Bastion x4
- Azure Route Server x2
- Azure VM x4
main.bicep
param location01 string = 'eastasia'
param circuit01 object
param circuit02 object
param sshKeyRGName string
param isInitialDeploy bool = false
var useExisting = !isInitialDeploy
param publicKeyName string
resource public_key 'Microsoft.Compute/sshPublicKeys@2022-03-01' existing = {
name: publicKeyName
scope: resourceGroup(sshKeyRGName)
}
/* ****************************** hub00 ****************************** */
var hub00Suffix = 'hub00'
resource hub00 'Microsoft.Network/virtualNetworks@2022-01-01' = {
name: 'vnet-${hub00Suffix}'
location: location01
properties: {
addressSpace: {
addressPrefixes: [
'10.0.0.0/16'
]
}
subnets: [
{
name: 'default'
properties: {
addressPrefix: '10.0.0.0/24'
}
}
{
name: 'AzureBastionSubnet'
properties: {
addressPrefix: '10.0.100.0/24'
}
}
{
name: 'GatewaySubnet'
properties: {
addressPrefix: '10.0.200.0/24'
}
}
{
name: 'RouteServerSubnet'
properties: {
addressPrefix: '10.0.210.0/24'
}
}
]
}
resource defaultsubnet 'subnets' existing = {
name: 'default'
}
}
var ergw00Name = 'ergw-${hub00Suffix}'
module ergw00 '../lib/ergw.bicep' = {
name: ergw00Name
params: {
location: location01
gatewayName: ergw00Name
vnetName: hub00.name
useExisting: useExisting
}
}
resource conn_hub00 'Microsoft.Network/connections@2022-01-01' = {
name: 'conn-${hub00Suffix}'
location: location01
properties: {
connectionType: 'ExpressRoute'
virtualNetworkGateway1: {
id: ergw00.outputs.ergwId
}
peer: {
id: circuit01.id
}
authorizationKey: circuit01.authorizationKey1
}
}
module bast00 '../lib/bastion.bicep' = {
name: 'bast-${hub00Suffix}'
params: {
location: location01
vnetName: hub00.name
}
}
var rs00Name = 'rs-${hub00Suffix}'
module rs00 '../lib/route-server.bicep' = {
name: rs00Name
params: {
location: location01
routeServerName: rs00Name
vnetName: hub00.name
bgpConnections: [
{
name: vm_hub00.name
ip: vm_hub00.outputs.privateIP
asn: '65001'
}
]
useExisting: useExisting
}
dependsOn: [
conn_hub00
]
}
var vm00Name = 'vm-${hub00Suffix}'
module vm_hub00 '../lib/ubuntu2004.bicep' = {
name: vm00Name
params: {
location: location01
keyData: public_key.properties.publicKey
subnetId: hub00::defaultsubnet.id
vmName: vm00Name
enableIPForwarding: true
}
}
/* ****************************** hub10 ****************************** */
var hub10Suffix = 'hub10'
resource hub10 'Microsoft.Network/virtualNetworks@2022-01-01' = {
name: 'vnet-${hub10Suffix}'
location: location01
properties: {
addressSpace: {
addressPrefixes: [
'10.10.0.0/16'
]
}
subnets: [
{
name: 'default'
properties: {
addressPrefix: '10.10.0.0/24'
}
}
{
name: 'AzureBastionSubnet'
properties: {
addressPrefix: '10.10.100.0/24'
}
}
{
name: 'GatewaySubnet'
properties: {
addressPrefix: '10.10.200.0/24'
}
}
{
name: 'RouteServerSubnet'
properties: {
addressPrefix: '10.10.210.0/24'
}
}
]
}
resource defaultsubnet 'subnets' existing = {
name: 'default'
}
}
module peering_hub0010 '../lib/vnet-peering.bicep' = {
name: 'peering-${hub00Suffix}-${hub10Suffix}'
params: {
vnet01Name: hub00.name
vnet02Name: hub10.name
}
}
var ergw10Name = 'ergw-${hub10Suffix}'
module ergw10 '../lib/ergw.bicep' = {
name: ergw10Name
params: {
location: location01
gatewayName: ergw10Name
vnetName: hub10.name
useExisting: useExisting
}
}
resource conn_hub10 'Microsoft.Network/connections@2022-01-01' = {
name: 'conn-${hub10Suffix}'
location: location01
properties: {
connectionType: 'ExpressRoute'
virtualNetworkGateway1: {
id: ergw10.outputs.ergwId
}
peer: {
id: circuit02.id
}
authorizationKey: circuit02.authorizationKey1
}
}
module bast10 '../lib/bastion.bicep' = {
name: 'bast-${hub10Suffix}'
params: {
location: location01
vnetName: hub10.name
}
}
var rs10Name = 'rs-${hub10Suffix}'
module rs10 '../lib/route-server.bicep' = {
name: rs10Name
params: {
location: location01
routeServerName: rs10Name
vnetName: hub10.name
bgpConnections: [
{
name: vm_hub10.name
ip: vm_hub10.outputs.privateIP
asn: '65001'
}
]
useExisting: useExisting
}
dependsOn: [
conn_hub10
]
}
var vm10Name = 'vm-${hub10Suffix}'
module vm_hub10 '../lib/ubuntu2004.bicep' = {
name: vm10Name
params: {
location: location01
keyData: public_key.properties.publicKey
subnetId: hub10::defaultsubnet.id
vmName: vm10Name
enableIPForwarding: true
}
}
/* ****************************** hub100 ****************************** */
var hub100Suffix = 'hub100'
resource hub100 'Microsoft.Network/virtualNetworks@2022-01-01' = {
name: 'vnet-${hub100Suffix}'
location: location01
properties: {
addressSpace: {
addressPrefixes: [
'10.100.0.0/16'
]
}
subnets: [
{
name: 'default'
properties: {
addressPrefix: '10.100.0.0/24'
}
}
{
name: 'AzureBastionSubnet'
properties: {
addressPrefix: '10.100.100.0/24'
}
}
{
name: 'GatewaySubnet'
properties: {
addressPrefix: '10.100.200.0/24'
}
}
{
name: 'RouteServerSubnet'
properties: {
addressPrefix: '10.100.210.0/24'
}
}
]
}
resource defaultsubnet 'subnets' existing = {
name: 'default'
}
}
var ergw100Name = 'ergw-${hub100Suffix}'
module ergw100 '../lib/ergw.bicep' = {
name: ergw100Name
params: {
location: location01
gatewayName: ergw100Name
vnetName: hub100.name
useExisting: useExisting
}
}
resource conn_hub100 'Microsoft.Network/connections@2022-01-01' = {
name: 'conn-${hub100Suffix}'
location: location01
properties: {
connectionType: 'ExpressRoute'
virtualNetworkGateway1: {
id: ergw100.outputs.ergwId
}
peer: {
id: circuit01.id
}
authorizationKey: circuit01.authorizationKey2
}
dependsOn: [
conn_hub00
]
}
module bast100 '../lib/bastion.bicep' = {
name: 'bast-${hub100Suffix}'
params: {
location: location01
vnetName: hub100.name
}
}
var vm100Name = 'vm-${hub100Suffix}'
module vm_hub100 '../lib/ubuntu2004.bicep' = {
name: vm100Name
params: {
location: location01
keyData: public_key.properties.publicKey
subnetId: hub100::defaultsubnet.id
vmName: vm100Name
enableIPForwarding: true
}
}
/* ****************************** hub110 ****************************** */
var hub110Suffix = 'hub110'
resource hub110 'Microsoft.Network/virtualNetworks@2022-01-01' = {
name: 'vnet-${hub110Suffix}'
location: location01
properties: {
addressSpace: {
addressPrefixes: [
'10.110.0.0/16'
]
}
subnets: [
{
name: 'default'
properties: {
addressPrefix: '10.110.0.0/24'
}
}
{
name: 'AzureBastionSubnet'
properties: {
addressPrefix: '10.110.100.0/24'
}
}
{
name: 'GatewaySubnet'
properties: {
addressPrefix: '10.110.200.0/24'
}
}
{
name: 'RouteServerSubnet'
properties: {
addressPrefix: '10.110.210.0/24'
}
}
]
}
resource defaultsubnet 'subnets' existing = {
name: 'default'
}
}
var ergw110Name = 'ergw-${hub110Suffix}'
module ergw110 '../lib/ergw.bicep' = {
name: ergw110Name
params: {
location: location01
gatewayName: ergw110Name
vnetName: hub110.name
useExisting: useExisting
}
}
resource conn_hub110 'Microsoft.Network/connections@2022-01-01' = {
name: 'conn-${hub110Suffix}'
location: location01
properties: {
connectionType: 'ExpressRoute'
virtualNetworkGateway1: {
id: ergw110.outputs.ergwId
}
peer: {
id: circuit02.id
}
authorizationKey: circuit02.authorizationKey2
}
dependsOn: [
conn_hub10
]
}
module bast110 '../lib/bastion.bicep' = {
name: 'bast-${hub110Suffix}'
params: {
location: location01
vnetName: hub110.name
}
}
var vm110Name = 'vm-${hub110Suffix}'
module vm_hub110 '../lib/ubuntu2004.bicep' = {
name: vm110Name
params: {
location: location01
keyData: public_key.properties.publicKey
subnetId: hub110::defaultsubnet.id
vmName: vm110Name
enableIPForwarding: true
}
}
Ubuntu Server 20.04 の NVA 化 (VXLAN)
BGP については FRRouting を利用しますが、その前提として VXLAN の設定しておきます。
VXLAN の設定についてはこちらの記事が前提にあります。
- NVA #1 は以下の設定が必要 (10.0.0.4 → 10.10.0.4)
ip link add vxlan0 type vxlan id 77 remote 10.10.0.4 dstport 4789 dev eth0
ip link set up vxlan0
ip address add 169.254.0.1/24 dev vxlan0
- NVA #2 は以下の設定が必要 (10.10.0.4 → 10.0.0.4)
ip link add vxlan0 type vxlan id 77 remote 10.0.0.4 dstport 4789 dev eth0
ip link set up vxlan0
ip address add 169.254.0.2/24 dev vxlan0
上記記事に沿って、これらの script (をちょっと修正したもの) を /etc/network/if-post-up.d/vxlan
に配置します。
VM を一度再起動し、ip link
や ip addr
で vxlan0
が生えていること、および ping
で疎通が取れることを確認します。
$ ip -d link show vxlan0
3: vxlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/ether 9a:5f:72:27:62:4b brd ff:ff:ff:ff:ff:ff promiscuity 0 minmtu 68 maxmtu 65535
vxlan id 77 remote 10.10.0.4 dev eth0 srcport 0 0 dstport 4789 ttl auto ageing 300 udpcsum noudp6zerocsumtx noudp6zerocsumrx addrgenmode eui64 numtxqueues 1 numrxqueues 1 gso_max_size 62780 gso_max_segs 65535
$ ip addr show vxlan0
3: vxlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN group default qlen 1000
link/ether 9a:5f:72:27:62:4b brd ff:ff:ff:ff:ff:ff
inet 169.254.0.1/24 scope global vxlan0
valid_lft forever preferred_lft forever
inet6 fe80::985f:72ff:fe27:624b/64 scope link
valid_lft forever preferred_lft forever
$ ping -c 4 169.254.0.2
PING 169.254.0.2 (169.254.0.2) 56(84) bytes of data.
64 bytes from 169.254.0.2: icmp_seq=1 ttl=64 time=2.26 ms
64 bytes from 169.254.0.2: icmp_seq=2 ttl=64 time=0.915 ms
64 bytes from 169.254.0.2: icmp_seq=3 ttl=64 time=1.22 ms
64 bytes from 169.254.0.2: icmp_seq=4 ttl=64 time=0.999 ms
--- 169.254.0.2 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3010ms
rtt min/avg/max/mdev = 0.915/1.348/2.259/0.537 ms
Ubuntu Server 20.04 の NVA 化 (FRRouting)
FRRouting の config は以下のような感じです。[1]
vm-hub00# show run
Building configuration...
Current configuration:
!
frr version 8.3
frr defaults traditional
hostname vm-hub00
log syslog informational
no ipv6 forwarding
service integrated-vtysh-config
!
ip route 10.0.210.0/24 10.0.0.1
!
router bgp 65001
neighbor 10.0.210.4 remote-as 65515
neighbor 10.0.210.4 ebgp-multihop 255
neighbor 10.0.210.5 remote-as 65515
neighbor 10.0.210.5 ebgp-multihop 255
neighbor 169.254.0.2 remote-as 65001
!
address-family ipv4 unicast
neighbor 10.0.210.4 soft-reconfiguration inbound
neighbor 10.0.210.4 prefix-list rs-hub00 out
neighbor 10.0.210.4 route-map rmap-bogon-asns in
neighbor 10.0.210.4 route-map rmap-azure-asns out
neighbor 10.0.210.5 soft-reconfiguration inbound
neighbor 10.0.210.5 prefix-list rs-hub00 out
neighbor 10.0.210.5 route-map rmap-bogon-asns in
neighbor 10.0.210.5 route-map rmap-azure-asns out
neighbor 169.254.0.2 next-hop-self
neighbor 169.254.0.2 soft-reconfiguration inbound
neighbor 169.254.0.2 prefix-list vm-hub10 out
exit-address-family
exit
!
ip prefix-list vm-hub10 seq 5 deny 10.0.0.0/16 ge 16
ip prefix-list vm-hub10 seq 10 permit any
ip prefix-list rs-hub00 seq 5 deny 10.0.0.0/16
ip prefix-list rs-hub00 seq 10 deny 10.100.0.0/16
ip prefix-list rs-hub00 seq 15 permit any
!
bgp as-path access-list azure-asns seq 5 permit _65515_
bgp as-path access-list bogon-asns seq 5 permit _0_
bgp as-path access-list bogon-asns seq 10 permit _23456_
bgp as-path access-list bogon-asns seq 15 permit _1310[0-6][0-9]_|_13107[0-1]_
bgp as-path access-list bogon-asns seq 20 deny _65515_
bgp as-path access-list bogon-asns seq 25 permit ^65
!
route-map rmap-bogon-asns deny 5
match as-path bogon-asns
exit
!
route-map rmap-bogon-asns permit 10
exit
!
route-map rmap-azure-asns permit 5
match as-path azure-asns
set as-path replace any
exit
!
route-map rmap-azure-asns deny 10
exit
!
end
簡易的ですが説明を入れます。
-
ip route 10.0.210.0/24 10.0.0.1
この仮想マシンとしては 10.0.0.0/16 ではなく 10.0.0.0/24 として connected を認識しており、RouteServerSubnet が見えていないため static route を入れます。 -
neighbor 10.0.210.4 remote-as 65515
とneighbor 10.0.210.4 ebgp-multihop 255
BGP の peer の設定および、上記 static route で 1 hop 先の peer との接続となるためebgp-multihop
を入れておきます -
neighbor 169.254.0.2 remote-as 65001
こちらは VXLAN を使った connected となるためebgp-multihop
は不要です -
neighbor 10.0.210.4 soft-reconfiguration inbound
これを入れるとshow ip bgp nei x.x.x.x received-routes
が叩けるようになりトラブルシュートに便利です -
neighbor 10.0.210.4 prefix-list rs-hub00 out
Azure Route Server に広報する経路を絞るためのprefix-list
です
prefix をべた書きしているので BGP Community などを使って置き換えてもいいかなとは思っています -
neighbor 10.0.210.4 route-map rmap-bogon-asns in
Bogon な AS-PATH を含む経路を受け入れないためのroute-map
です
実際には Azure Route Server で使っている AS65515 は除外しています -
neighbor 10.0.210.4 route-map rmap-azure-asns out
AS65515 なものだけを経路広報する、かつ、AS_PATH
をすべて置き換えるroute-map
を適用しています -
neighbor 169.254.0.2 next-hop-self
169.254.0.2 との peer は iBGP になるのですが、connected を OSPF などで回しておらず next-hop が解決できないため、next-hop-self
で上書きしています。
受け取った経路の next-hop が VXLAN の IP アドレスとなるため、2 つの NVA の間の通信が VXLAN でトンネルされます。
参考までにもう片方の config も張り付けておきます。
こちらの NVA の IP アドレスは 10.10.0.4 (VNet は 10.10.0.0/16) です。
show running-config
vm-hub10# show run
Building configuration...
Current configuration:
!
frr version 8.3
frr defaults traditional
hostname vm-hub10
log syslog informational
no ipv6 forwarding
service integrated-vtysh-config
!
ip route 10.10.210.0/24 10.10.0.1
!
router bgp 65001
neighbor 10.10.210.4 remote-as 65515
neighbor 10.10.210.4 ebgp-multihop 255
neighbor 10.10.210.5 remote-as 65515
neighbor 10.10.210.5 ebgp-multihop 255
neighbor 169.254.0.1 remote-as 65001
!
address-family ipv4 unicast
neighbor 10.10.210.4 soft-reconfiguration inbound
neighbor 10.10.210.4 prefix-list rs-hub10 out
neighbor 10.10.210.4 route-map rmap-bogon-asns in
neighbor 10.10.210.4 route-map rmap-azure-asns out
neighbor 10.10.210.5 soft-reconfiguration inbound
neighbor 10.10.210.5 prefix-list rs-hub10 out
neighbor 10.10.210.5 route-map rmap-bogon-asns in
neighbor 10.10.210.5 route-map rmap-azure-asns out
neighbor 169.254.0.1 next-hop-self
neighbor 169.254.0.1 soft-reconfiguration inbound
neighbor 169.254.0.1 prefix-list vm-hub00 out
exit-address-family
exit
!
ip prefix-list vm-hub00 seq 5 deny 10.10.0.0/16
ip prefix-list vm-hub00 seq 10 permit any
ip prefix-list rs-hub10 seq 5 deny 10.10.0.0/16
ip prefix-list rs-hub10 seq 10 deny 10.110.0.0/16
ip prefix-list rs-hub10 seq 15 permit any
!
bgp as-path access-list azure-asns seq 5 permit _65515_
bgp as-path access-list bogon-asns seq 5 permit _0_
bgp as-path access-list bogon-asns seq 10 permit _23456_
bgp as-path access-list bogon-asns seq 15 permit _1310[0-6][0-9]_|_13107[0-1]_
bgp as-path access-list bogon-asns seq 20 deny _65515_
bgp as-path access-list bogon-asns seq 25 permit ^65
!
route-map rmap-bogon-asns deny 5
match as-path bogon-asns
exit
!
route-map rmap-bogon-asns permit 10
exit
!
route-map rmap-azure-asns permit 5
match as-path azure-asns
set as-path replace any
exit
!
route-map rmap-azure-asns deny 10
exit
!
end
動作確認 (microsoft/ethr)
以上の設定が完了すれば、左上と左下の VNet の間で通信が可能になっているはずです。
今回の main.bicep では 10.100.0.0/24 と 10.110.0.0/24 に該当します。
お気に入りの microsoft/ethr で TCP レベルの traceroute (宛先は SSH のポート = 22/tcp) を試します。
間に入っている ???
は Virtual network gateway とかだと思いますが、経路がないんだか ICMP Time Exceeded を送ってくれないんだかでとりあえず見えません。
ikko@vm-hub100:~$ sudo ./ethr -c 10.110.0.4 -t tcp --port 22 -t tr
Ethr: Comprehensive Network Performance Measurement Tool (Version: v1.0.0)
Maintainer: Pankaj Garg (ipankajg @ LinkedIn | GitHub | Gmail | Twitter)
Using destination: 10.110.0.4, ip: 10.110.0.4, port: 22
Tracing route to 10.110.0.4 over 30 hops:
1.|--???
2.|--10.0.0.4 [] 109.137ms
3.|--???
4.|--???
5.|--10.110.0.4 [] 218.825ms
Ethr done, measurement complete.
逆方向ももちろん通ります。
ikko@vm-hub110:~$ sudo ./ethr -c 10.100.0.4 -p tcp --port 22 -t tr
Ethr: Comprehensive Network Performance Measurement Tool (Version: v1.0.0)
Maintainer: Pankaj Garg (ipankajg @ LinkedIn | GitHub | Gmail | Twitter)
Using destination: 10.100.0.4, ip: 10.100.0.4, port: 22
Tracing route to 10.100.0.4 over 30 hops:
1.|--???
2.|--10.10.0.4 [] 110.862ms
3.|--???
4.|--???
5.|--10.100.0.4 [] 226.166ms
Ethr done, measurement complete.
tcpdump
)
動作確認 (NVA にあたる vm-hub00 (中央上の VNet にあたります) で tcpdump
を仕掛けてみます。
まずは port 22 and host 10.100.0.4
で見てみます。
root@vm-hub00:~# tcpdump -nni eth0 port 22 and host 10.100.0.4
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
16:52:53.056601 IP 10.100.0.4.8890 > 10.110.0.4.22: Flags [S], seq 2349978517, win 64240, options [mss 1376,sackOK,TS val 1386299511 ecr 0,nop,wscale 7], length 0
16:52:53.172351 IP 10.100.0.4.8891 > 10.110.0.4.22: Flags [S], seq 3804810079, win 64240, options [mss 1376,sackOK,TS val 1386299630 ecr 0,nop,wscale 7], length 0
16:52:55.177477 IP 10.100.0.4.8892 > 10.110.0.4.22: Flags [S], seq 892564222, win 64240, options [mss 1376,sackOK,TS val 1386301631 ecr 0,nop,wscale 7], length 0
16:52:57.174257 IP 10.100.0.4.8893 > 10.110.0.4.22: Flags [S], seq 365349981, win 64240, options [mss 1376,sackOK,TS val 1386303632 ecr 0,nop,wscale 7], length 0
16:52:57.286751 IP 10.110.0.4.22 > 10.100.0.4.8893: Flags [S.], seq 1119812311, ack 365349982, win 65160, options [mss 1376,sackOK,TS val 3924610454 ecr 1386303632,nop,wscale 7], length 0
16:52:57.392118 IP 10.100.0.4.8893 > 10.110.0.4.22: Flags [.], ack 1, win 502, options [nop,nop,TS val 1386303850 ecr 3924610454], length 0
16:52:57.392118 IP 10.100.0.4.8893 > 10.110.0.4.22: Flags [R.], seq 1, ack 1, win 502, options [nop,nop,TS val 1386303851 ecr 3924610454], length 0
port 4789
だと VXLAN のトンネルの内容が見れます。
ちょっと見づらいかもしれませんが、SSH とか ARP などの VXLAN の中でしゃべっている内容もちゃんと表示されますね、すごい。
VXLAN の世界では普通に 10.0.0.4 と 10.10.0.4 の間でパケットをやり取りしているだけ、というのも確認できます。
root@vm-hub00:~# tcpdump -nni eth0 port 4789
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
16:54:54.186454 IP 10.0.0.4.45068 > 10.10.0.4.4789: VXLAN, flags [I] (0x08), vni 77
IP 10.100.0.4.8891 > 10.110.0.4.22: Flags [S], seq 1400684226, win 64240, options [mss 1376,sackOK,TS val 1386420644 ecr 0,nop,wscale 7], length 0
16:54:54.187906 IP 10.10.0.4.49610 > 10.0.0.4.4789: VXLAN, flags [I] (0x08), vni 77
IP 169.254.0.2 > 10.100.0.4: ICMP time exceeded in-transit, length 68
16:54:56.191046 IP 10.0.0.4.53467 > 10.10.0.4.4789: VXLAN, flags [I] (0x08), vni 77
IP 10.100.0.4.8892 > 10.110.0.4.22: Flags [S], seq 2783408859, win 64240, options [mss 1376,sackOK,TS val 1386422645 ecr 0,nop,wscale 7], length 0
16:54:58.188230 IP 10.0.0.4.51090 > 10.10.0.4.4789: VXLAN, flags [I] (0x08), vni 77
IP 10.100.0.4.8893 > 10.110.0.4.22: Flags [S], seq 2256194720, win 64240, options [mss 1376,sackOK,TS val 1386424646 ecr 0,nop,wscale 7], length 0
16:54:58.300305 IP 10.10.0.4.47245 > 10.0.0.4.4789: VXLAN, flags [I] (0x08), vni 77
IP 10.110.0.4.22 > 10.100.0.4.8893: Flags [S.], seq 3010654816, ack 2256194721, win 65160, options [mss 1376,sackOK,TS val 3924731468 ecr 1386424646,nop,wscale 7], length 0
16:54:58.405096 IP 10.0.0.4.51090 > 10.10.0.4.4789: VXLAN, flags [I] (0x08), vni 77
IP 10.100.0.4.8893 > 10.110.0.4.22: Flags [.], ack 1, win 502, options [nop,nop,TS val 1386424864 ecr 3924731468], length 0
16:54:58.405120 IP 10.0.0.4.51090 > 10.10.0.4.4789: VXLAN, flags [I] (0x08), vni 77
IP 10.100.0.4.8893 > 10.110.0.4.22: Flags [R.], seq 1, ack 1, win 502, options [nop,nop,TS val 1386424864 ecr 3924731468], length 0
16:54:59.220729 IP 10.0.0.4.34769 > 10.10.0.4.4789: VXLAN, flags [I] (0x08), vni 77
ARP, Request who-has 169.254.0.2 tell 169.254.0.1, length 28
16:54:59.222175 IP 10.10.0.4.48365 > 10.0.0.4.4789: VXLAN, flags [I] (0x08), vni 77
ARP, Reply 169.254.0.2 is-at 7e:ce:db:b2:9f:00, length 28
16:54:59.285062 IP 10.10.0.4.48365 > 10.0.0.4.4789: VXLAN, flags [I] (0x08), vni 77
ARP, Request who-has 169.254.0.1 tell 169.254.0.2, length 28
16:54:59.285134 IP 10.0.0.4.34769 > 10.10.0.4.4789: VXLAN, flags [I] (0x08), vni 77
ARP, Reply 169.254.0.1 is-at 66:fb:f6:dc:2d:03, length 28
16:55:03.871583 IP 10.10.0.4.34442 > 10.0.0.4.4789: VXLAN, flags [I] (0x08), vni 77
IP 169.254.0.2.36366 > 169.254.0.1.179: Flags [P.], seq 1704704179:1704704198, ack 2112209324, win 507, options [nop,nop,TS val 3231400303 ecr 1129369912], length 19: BGP
16:55:03.871858 IP 10.0.0.4.42559 > 10.10.0.4.4789: VXLAN, flags [I] (0x08), vni 77
IP 169.254.0.1.179 > 169.254.0.2.36366: Flags [P.], seq 1:20, ack 19, win 502, options [nop,nop,TS val 1129429912 ecr 3231400303], length 19: BGP
16:55:03.872991 IP 10.10.0.4.34442 > 10.0.0.4.4789: VXLAN, flags [I] (0x08), vni 77
IP 169.254.0.2.36366 > 169.254.0.1.179: Flags [.], ack 20, win 507, options [nop,nop,TS val 3231400304 ecr 1129429912], length 0
動作確認 (Effective routes)
左上の Azure VM (10.100.0.0/16 にあたります) での Effective routes は以下のとおりです。
ExpressRoute 経由で 10.0.0.0/16 (中央上の VNet) と 10.110.0.0/16 (左下の VNet) のアドレス空間が聞こえてきています。
10.110.0.4 宛ては Next Hop が Virtual network gateway となっており、これは ExpressRoute 経由ということと考えられます。
Source | State | Address Prefixes | Next Hop Type | Next Hop IP Address | User Defined Route Name |
---|---|---|---|---|---|
Default | Active | 10.100.0.0/16 | Virtual network | - | - |
Virtual network gateway | Active | 10.0.0.0/16 | Virtual network gateway | 10.2.146.76 | - |
Virtual network gateway | Active | 10.0.0.0/16 | Virtual network gateway | 10.2.146.77 | - |
Virtual network gateway | Active | 10.110.0.0/16 | Virtual network gateway | 10.2.146.76 | - |
Virtual network gateway | Active | 10.110.0.0/16 | Virtual network gateway | 10.2.146.77 | - |
中央上の VNet (10.0.0.0/16) にある NVA における Effective routes は以下のとおりです。
ほんとにマジで大事なことなんですが、ここでは 10.100.0.0/16 (左下の VNet) の Next Hop IP Address は 10.0.0.4 (中央上の VNet) に向いています。
Source | State | Address Prefixes | Next Hop Type | Next Hop IP Address | User Defined Route Name |
---|---|---|---|---|---|
Default | Active | 10.0.0.0/16 | Virtual network | - | - |
Default | Active | 10.10.0.0/16 | VNet peering | - | - |
Virtual network gateway | Active | 10.100.0.0/16 | Virtual network gateway | 10.2.146.77 | - |
Virtual network gateway | Active | 10.100.0.0/16 | Virtual network gateway | 10.2.146.76 | - |
Virtual network gateway | Active | 10.110.0.0/16 | Virtual network gateway | 10.0.0.4 | - |
これだけをみるとパケットがループするように見えます。
- 左上 (10.100.0.4) から左下 (10.110.0.4) に向かってパケットを飛ばしたい
- 10.100.0.4 の Effective route を見ると、Virtual network gateway に送ればよさそう (ExpressRoute を経由して中央上の VNet にくる)
- 中央上の VNet にパケットが入ってきて、10.110.0.4 宛てのパケットは 10.0.0.4 (中央上の NVA) に送ればいい
- NVA の Effective routes を見るに、10.110.0.4 あてのパケットは 10.0.0.4 に再度送ることになる (ループする)
ここで重要なのが NVA で VXLAN でトンネルを張っていることです。
中央上の NVA の FRRouting での show ip route
の結果は以下のとおりです。
vm-hub00# show ip route
Codes: K - kernel route, C - connected, S - static, R - RIP,
O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP,
T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR,
f - OpenFabric,
> - selected route, * - FIB route, q - queued, r - rejected, b - backup
t - trapped, o - offload failure
K>* 0.0.0.0/0 [0/100] via 10.0.0.1, eth0, src 10.0.0.4, 00:36:35
B> 10.0.0.0/16 [20/0] via 10.0.210.4 (recursive), weight 1, 00:23:27
* via 10.0.0.1, eth0, weight 1, 00:23:27
via 10.0.210.5 (recursive), weight 1, 00:23:27
via 10.0.0.1, eth0, weight 1, 00:23:27
C>* 10.0.0.0/24 is directly connected, eth0, 00:36:35
S>* 10.0.210.0/24 [1/0] via 10.0.0.1, eth0, weight 1, 00:36:35
B> 10.100.0.0/16 [20/0] via 10.0.210.4 (recursive), weight 1, 00:08:26
* via 10.0.0.1, eth0, weight 1, 00:08:26
via 10.0.210.5 (recursive), weight 1, 00:08:26
via 10.0.0.1, eth0, weight 1, 00:08:26
B>* 10.110.0.0/16 [200/0] via 169.254.0.2, vxlan0, weight 1, 00:08:25
K>* 168.63.129.16/32 [0/100] via 10.0.0.1, eth0, src 10.0.0.4, 00:36:35
C>* 169.254.0.0/24 is directly connected, vxlan0, 00:36:35
K>* 169.254.169.254/32 [0/100] via 10.0.0.1, eth0, src 10.0.0.4, 00:36:35
OS 側に戻って ip route
を叩いても大体同じような結果が見えてきます。
# ip route
default via 10.0.0.1 dev eth0 proto dhcp src 10.0.0.4 metric 100
10.0.0.0/24 dev eth0 proto kernel scope link src 10.0.0.4
10.0.0.0/16 nhid 19 via 10.0.0.1 dev eth0 proto bgp metric 20
10.0.210.0/24 nhid 10 via 10.0.0.1 dev eth0 proto static metric 20
10.100.0.0/16 nhid 19 via 10.0.0.1 dev eth0 proto bgp metric 20
10.110.0.0/16 nhid 25 via 169.254.0.2 dev vxlan0 proto bgp metric 20
168.63.129.16 via 10.0.0.1 dev eth0 proto dhcp src 10.0.0.4 metric 100
169.254.0.0/24 dev vxlan0 proto kernel scope link src 169.254.0.1
169.254.169.254 via 10.0.0.1 dev eth0 proto dhcp src 10.0.0.4 metric 100
これを見ると、10.110.0.0/16 の next-hop は 169.254.0.2、つまり VXLAN になっています。
つまり、NVA に入ってきた 10.110.0.4 宛てのパケットは、VXLAN にトンネルされ、Azure 側ではいったん宛先 10.10.0.4 宛てのパケットして見えるようになります。
- 左上 (10.100.0.4) から左下 (10.110.0.4) に向かってパケットを飛ばしたい
- 10.100.0.4 の Effective route を見ると、Virtual network gateway に送ればよさそう (ExpressRoute を経由して中央上の VNet にくる)
- 中央上の VNet にパケットが入ってきて、10.110.0.4 宛てのパケットは 10.0.0.4 (中央上の NVA) に送ればいい
- NVA の内部で VXLAN にカプセル化され、Azure の世界上ではいったん 10.10.0.4 宛てのパケットに見える (VNet Peering で送れる)
- もう片方の NVA でカプセル化をほどき、そのあとは Azure 側に任せてパケットを転送する
中央下 (10.10.0.0/16) のほうの NVA での Effective routes は以下のとおりです。
2 行出ていないのがややおかしい気がしますが、10.110.0.0/16 は ExpressRoute 経由となっています。
これにより、結果として ExpressRoute 経由で中央下の VNet から左下の VNet へとパケットが運ばれていきます。
Source | State | Address Prefixes | Next Hop Type | Next Hop IP Address | User Defined Route Name |
---|---|---|---|---|---|
Default | Active | 10.10.0.0/16 | Virtual network | - | - |
Default | Active | 10.0.0.0/16 | VNet peering | - | - |
Virtual network gateway | Active | 10.110.0.0/16 | Virtual network gateway | 10.2.146.62 | - |
Virtual network gateway | Active | 10.100.0.0/16 | Virtual network gateway | 10.10.0.4 | - |
ぽすとふぇーす
ずーーーーーーーーっと VXLAN の検証をやりたかったんですがやっとできました。
Ubuntu Server でやる分にはかなりシンプルな設定でした。
ただ、それを永続化させる部分や FRRouting の設定にはかなりてこずりました。
あとはこれを Cisco でできないか考えたいところです。
また、本格的に考える場合には NVA の冗長化も考えるため、NVA を 2 台構成にして前に Load Balancer を置いて、、NEXT_HOP 属性を使いつつ、という感じになりそうですね。
参考
- そういえば Hub-Spoke が 2 つあるときの構成例も参考になるかも
Update log
- 全体を # (見出し1) から ## (見出し2) に変更 - 2023/12/18
- 参考リンクの追加 - 2023/12/18
-
今回の検証の中で今まで書いてた config あまりよくないのに気付いたので後で書きなおしたい ↩︎
Discussion