안녕하세요, PlayceCloud팀 윤지윤 입니다.
이번 글에서는 오픈스택 OVS 기반 환경에서 네트워크가 어떻게 연결되어 있는지, 그리고 네트워크 흐름 파악을 위해 테스트해 본 경험을 소개하고자 합니다.
해당 포스트는 기본적으로 오픈스택에 대한 기본 지식이 있는 분들을 대상으로 작성되었습니다.
오픈스택 기술 지원 시 많은 고객분들께서 OpenStack OVS 환경에서 네트워크 흐름을 확인할 수 있는 방법에 대해 질문해 주십니다. 이에 CLI 환경에서 간단한 시나리오를 기준으로 네트워크 흐름을 확인해 볼 수 있는 방법을 공유하고자 합니다.
기본적인 시나리오 자료는 OpenStack 공식 홈페이지(링크)의 East/West Network Traffic Flow 다이어그램을 기준으로 진행하였습니다.
이 시나리오는 오픈스택 클라우드 환경에서 서로 다른 물리적 위치에 배치된 가상 머신들이 어떻게 상호 통신하는지에 대한 이해를 돕기 위해 작성되었습니다.
주로 Open vSwitch East/West 네트워크 트래픽을 사용하는 패킷 흐름을 실제 CLI 환경의 명령어를 사용하여 확인하는 과정에 중점을 두고 설명 드리겠습니다.
OpenVSwitch ( OVS ) 기본 개념
OpenVSwitch(OVS)는 오픈소스 기반의 가상 멀티레이어 스위치로, 가상 머신 사이를 효과적으로 연결하고 네트워크 트래픽을 제어할 수 있습니다. OVS는 통합 브리지(br-int), 외부 브리지(br-ex) 등으로 구성되어 있습니다.
시나리오를 진행 하기 앞서 사전에 테스트에 사용될 두 개의 가상 머신(VM)의 정보를 확인해 보도록 하겠습니다.
# nova show test-vm-1 | egrep "hostname|hypervisor|instance"
| OS-EXT-SRV-ATTR:hostname | test-vm-1 |
| OS-EXT-SRV-ATTR:hypervisor_hostname | compute01 |
| OS-EXT-SRV-ATTR:instance_name | instance-0000085e |
# nova interface-list test-vm-1
+------------+--------------------------------------+--------------------------------------+--------------+-------------------+-----+
| Port State | Port ID | Net ID | IP addresses | MAC Addr | Tag |
+------------+--------------------------------------+--------------------------------------+--------------+-------------------+-----+
| ACTIVE | 3238a480-bafa-4363-94bb-28e2f0a8ed14 | 832053c3-b887-4dd8-891a-80fa7dc89e2c | 10.251.2.140 | fa:16:3e:11:ba:24 | - |
+------------+--------------------------------------+--------------------------------------+--------------+-------------------+-----+
# nova show test-vm-2 | egrep "hostname|hypervisor|instance"
| OS-EXT-SRV-ATTR:hostname | test-vm-2 |
| OS-EXT-SRV-ATTR:hypervisor_hostname | compute02 |
| OS-EXT-SRV-ATTR:instance_name | instance-0000085f |
# nova interface-list test-vm-2
+------------+--------------------------------------+--------------------------------------+--------------+-------------------+-----+
| Port State | Port ID | Net ID | IP addresses | MAC Addr | Tag |
+------------+--------------------------------------+--------------------------------------+--------------+-------------------+-----+
| ACTIVE | 7e00f86b-db3a-4407-83c7-7563cd7a8047 | 832053c3-b887-4dd8-891a-80fa7dc89e2c | 10.251.0.99 | fa:16:3e:53:45:40 | - |
+------------+--------------------------------------+--------------------------------------+--------------+-------------------+-----+
네트워크 패킷 흐름을 확인 해보기 전에 인스턴스 정보들을 간략히 정리하면 다음과 같습니다.
VM 1 | VM 2 | |
---|---|---|
호스트 이름 | test-vm-1 | test-vm-2 |
인스턴스 이름 | instance-0000085e | instance-0000085f |
하이퍼바이저 이름 | Compute01 | Compute02 |
네트워크 정보 | 10.251.2.140 | 10.251.0.99 |
맥 주소 | fa:16:3e:11:ba:24 | fa:16:3e:53;45;40 |
이제 인스턴스1(이하 VM) 에서 Linux Bridge 까지의 패킷 흐름을 정리해 보겠습니다.
먼저 VM이 있는 Compute Node에 SSH로 접속을 합니다.
# ssh compute01
VM에 연결된 Tap 인터페이스 정보를 확인해 보면,
# virsh domiflist instance-0000085e
Interface Type Source Model MAC
------------------------------------------------------------------------
tap3238a480-ba bridge qbr3238a480-ba virtio fa:16:3e:11:ba:24
tap3238a480-ba
가 qbr3238a480-ba
브리지에 연결되어 있는 것을 확인할 수 있습니다.
ip a
명령어로 해당 브릿지의 정보를 확인해 보면,
# ip a | grep -i "qbr3238a480-ba"
550: qbr3238a480-ba: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP group default qlen 1000
552: qvb3238a480-ba@qvo3238a480-ba: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue master qbr3238a480-ba state UP group default qlen 1000
553: tap3238a480-ba: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue master qbr3238a480-ba state UNKNOWN group default qlen 1000
Linux Bridge 내부에서 qbr3238a480-ba
브리지가 qvb3238a480-ba
와 tap3238a480-ba
에 연결되어 있고, qvb3238a480-ba
는 qvo3238a480-ba
와 페어로 연결되어 있음을 보여줍니다.
VM에서 나온 패킷이 tap3238a480-ba
에서 시작하여 qbr3238a480-ba
브리지를 거쳐 qvb3238a480-ba
로 이동한 후, 페어링된 qvo3238a480-ba
를 통해 OVS로 전달됩니다.
VM 의 네트워크 정보를 정리하자면 다음과 같습니다.
br-int(Integration Bridge)
: 가상 네트워크 트래픽을 처리하는 OVS의 가상 스위치br-ex(Provider Bridge)
: 물리 네트워크 인터페이스와 직접 연결되는 OVS의 가상 스위치qvo(Queue Virtual Open vSwitch)
: Linux 브리지와 OVS 간 패킷 전달을 위한 가상 인터페이스qvb(Queue Virtual Bridge)
: Linux 브리지 내부에서 qvo와 페어로 연결된 가상 인터페이스
이제 tcpdump를 이용해서 VM 에서 Linux Bridge 까지 패킷 흐름을 확인해 보겠습니다.
VM에서 ICMP(ping)을 수행합니다.
# ping 10.251.0.99
먼저 ICMP 에코 요청/응답 패킷을 보면,
# tcpdump -i tap3238a480-ba -n -e
09:07:56.162786 fa:16:3e:11:ba:24 > fa:16:3e:53:45:40, ethertype IPv4 (0x0800), length 98: 10.251.2.140 > 10.251.0.99: ICMP echo request, id 10304, seq 6, length 64
09:07:56.163371 fa:16:3e:53:45:40 > fa:16:3e:11:ba:24, ethertype IPv4 (0x0800), length 98: 10.251.0.99 > 10.251.2.140: ICMP echo reply, id 10304, seq 6, length 64
# tcpdump -i qbr3238a480-ba -n -e
09:12:34.058740 fa:16:3e:11:ba:24 > fa:16:3e:53:45:40, ethertype IPv4 (0x0800), length 98: 10.251.2.140 > 10.251.0.99: ICMP echo request, id 10306, seq 5, length 64
09:12:34.059153 fa:16:3e:53:45:40 > fa:16:3e:11:ba:24, ethertype IPv4 (0x0800), length 98: 10.251.0.99 > 10.251.2.140: ICMP echo reply, id 10306, seq 5, length 64
# tcpdump -i qvb3238a480-ba -n -e
09:12:43.062721 fa:16:3e:11:ba:24 > fa:16:3e:53:45:40, ethertype IPv4 (0x0800), length 98: 10.251.2.140 > 10.251.0.99: ICMP echo request, id 10306, seq 14, length 64
09:12:43.063080 fa:16:3e:53:45:40 > fa:16:3e:11:ba:24, ethertype IPv4 (0x0800), length 98: 10.251.0.99 > 10.251.2.140: ICMP echo reply, id 10306, seq 14, length 64
그리고 ARP 요청 패킷도 마찬가지로,
09:12:35.059737 fa:16:3e:11:ba:24 > fa:16:3e:53:45:40, ethertype ARP (0x0806), length 42: Request who-has 10.251.0.99 tell 10.251.2.140, length 28
09:12:35.059737 fa:16:3e:11:ba:24 > fa:16:3e:53:45:40, ethertype ARP (0x0806), length 42: Request who-has 10.251.0.99 tell 10.251.2.140, length 28
이렇게 tap3238a480-ba
에서 시작된 ICMP와 ARP 패킷들이 qbr3238a480-ba
와 qvb3238a480-ba
를 차례로 거쳐 qvo3238a480-ba
쪽으로 전달되고 있다는 걸 tcpdump
출력을 통해 명확하게 확인할 수 있습니다.
따라서 지금까지의 분석 결과를 종합해 보면 다음 순서로 연결되어 있는 것을 확인할 수 있습니다.
이제 패킷은 최종적으로 qvo3238a480-ba
를 통해 Open vSwitch의 br-int 브리지로 전송됩니다.
다음 단계에서는 qvb
에서 qvo
를 통해 OVS까지 어떻게 도달하는지 한번 살펴보겠습니다.
Open vSwitch의 내부 패킷 추적 도구인 ofproto/trace를 활용하여 네트워크 패킷이 어떤 경로를 거치며 어떻게 처리되는지 파악한 후, 실제 흐름을 확인해 보겠습니다.
Open vSwitch의 다른 도구 관련 설명은 여기 에서 확인할 수 있습니다.
# ovs-appctl ofproto/trace "in_port(qvo3238a480-ba)"
Flow: in_port=142,vlan_tci=0x0000,dl_src=00:00:00:00:00:00,dl_dst=00:00:00:00:00:00,dl_type=0x05ff
bridge("br-int")
----------------
0. in_port=142, priority 9, cookie 0x4cf12db93ccecf2c
goto_table:25
25. No match.
drop
Final flow: unchanged
Megaflow: recirc_id=0,eth,in_port=142,dl_src=00:00:00:00:00:00,dl_type=0x05ff
Datapath actions: drop
특정 조건을 가진 가상의 패킷을 br-int 브리지의 qvo3238a480-ba
포트(OpenFlow 포트 번호 142)로 입력했을 때, 해당 패킷이 어떻게 처리될 것인지를 보여줍니다.
따라서 이 trace 결과는 주어진 조건의 패킷이 qvo3238a480-ba
포트로 들어왔을 때, br-int 브리지의 플로우 테이블에 의해 최종적으로 삭제될 것임을 보여줍니다. 하지만 이는 실제 패킷이 아닌 가상의 패킷에 대한 추적 결과이므로, 실제 패킷 전송 시에는 결과가 달라질 수 있습니다.
이제 실제 흐름을 확인해 보도록 하겠습니다.
VM1 에서 ICMP(ping)을 수행
# ping 10.251.0.99
OVS의 connection tracking 사용해서 패킷 흐름 확인 해보면:
# ovs-appctl dpctl/dump-conntrack | grep "10.251.0.99"
icmp,orig=(src=10.251.2.140,dst=10.251.0.99,id=1374,type=8,code=0),reply=(src=10.251.0.99,dst=10.251.2.140,id=1374,type=0,code=0),zone=4201
icmp,orig=(src=10.251.2.140,dst=10.251.0.99,id=1374,type=8,code=0),reply=(src=10.251.0.99,dst=10.251.2.140,id=1374,type=0,code=0),zone=4195
VM1(10.251.2.140)에서 VM2(10.251.0.99)로 ICMP 요청(type=8, code=0)을 보내고, VM2에서 VM1로 ICMP 응답(type=0, code=0)을 보내는 것을 알 수 있습니다.
orig
는 원래 ICMP 요청을 나타내며, VM1(10.251.2.140)에서 VM2(10.251.0.99)로 type=8
(ICMP 요청)을 보낸 것을 의미합니다.reply
는 해당 ICMP 요청에 대한 응답을 나타내며, VM2에서 VM1로 type=0
(ICMP 응답)을 보낸 것을 의미합니다.zone
은 해당 트래픽이 속한 네트워크 격리 영역을 나타냅니다. OVS는 다른 가상 네트워크 간 트래픽을 격리하기 위해 zone을 사용할 수 있습니다.OVS 의 dump-flows 사용해서 br-int 브리지 플로우 정보를 qvo3238a480-ba
포트 기준으로 확인해 보면:
# ovs-ofctl dump-flows br-int in_port="qvo3238a480-ba"
cookie=0x6ce9ddb675fb53ab, duration=2739.747s, table=0, n_packets=0, n_bytes=0, priority=10,icmp6,in_port="qvo3238a480-ba",icmp_type=136 actions=resubmit(,24)
cookie=0x6ce9ddb675fb53ab, duration=2739.745s, table=0, n_packets=98, n_bytes=4116, priority=10,arp,in_port="qvo3238a480-ba" actions=resubmit(,24)
cookie=0x6ce9ddb675fb53ab, duration=2739.750s, table=0, n_packets=774, n_bytes=102391, priority=9,in_port="qvo3238a480-ba" actions=resubmit(,25)
cookie=0x6ce9ddb675fb53ab, duration=2739.748s, table=24, n_packets=0, n_bytes=0, priority=2,icmp6,in_port="qvo3238a480-ba",icmp_type=136,nd_target=fe80::f816:3eff:fe11:ba24 actions=resubmit(,59)
cookie=0x6ce9ddb675fb53ab, duration=2739.746s, table=24, n_packets=96, n_bytes=4032, priority=2,arp,in_port="qvo3238a480-ba",arp_spa=10.251.2.140 actions=resubmit(,25)
cookie=0x6ce9ddb675fb53ab, duration=2739.754s, table=25, n_packets=861, n_bytes=105793, priority=2,in_port="qvo3238a480-ba",dl_src=fa:16:3e:11:ba:24 actions=resubmit(,30)
이런 플로우 정보를 종합해보면, VM1에서 보낸 패킷이 qvo3238a480-ba
포트를 통해 br-int로 들어와서 매칭되는 플로우 엔트리에 따라 내부 파이프라인(resubmit)을 타고 최종적으로는 테이블 30 이후의 규칙에 의해 처리될 것으로 보입니다.
따라서 이전의 ofproto/trace 결과와는 달리, 실제 패킷은 drop되지 않고 추가 처리를 위해 다른 테이블로 전달되고 있음을 알 수 있습니다
Compute Node1 에서 전달받은 네트워크 패킷은 이제 물리 스위치를 통해 Compute Node2 로 전송 됩니다.
Compute Node2 의 네트워크 패킷 처리 흐름이 Compute Node1 의 진행 흐름의 역순으로 진행 되는 것을 알 수 있습니다.
패킷 흐름을 테스트 해보기 전에 VM1에서 수집했던 네트워크 정보 처럼 VM2 의(이하VM) 기본적인 네트워크 정보를 먼저 수집 하도록 하겠습니다.
VM에 연결된 Tap 인터페이스 정보를 확인해 보면,
# virsh domiflist instance-0000085f
Interface Type Source Model MAC
------------------------------------------------------------------------
tap7e00f86b-db bridge qbr7e00f86b-db virtio fa:16:3e:53:45:40
ip a
명령어로 해당 브릿지의 정보를 확인해 보면,
# ip a | grep -i "qbr7e00f86b-db"
620: qbr7e00f86b-db: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP group default qlen 1000
622: qvb7e00f86b-db@qvo7e00f86b-db: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue master qbr7e00f86b-db state UP group default qlen 1000
623: tap7e00f86b-db: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue master qbr7e00f86b-db state UNKNOWN group default qlen 1000
해당 작업으로 알아낸 VM 의 네트워크 정보를 정리하자면 다음과 같습니다.
다음 단계에서는 이 정보를 바탕으로 실제 패킷 흐름을 테스트하고 확인해 보겠습니다.
이제 물리스위치에서 전달 받은 네트워크 패킷을 OVS 에서 확인 해보겠습니다.
phy-br-ex
포트로 들어오는 패킷을 확인하기 위해 ovs-ofctl 명령어를 사용합니다.
# ovs-ofctl dump-ports br-ex
OFPST_PORT reply (xid=0x2): 3 ports
port ens2f0: rx pkts=779660469, bytes=204019064706, drop=13, errs=0, frame=0, over=0, crc=0
tx pkts=393012755, bytes=72170611443, drop=0, errs=0, coll=0
port LOCAL: rx pkts=0, bytes=0, drop=371572253, errs=0, frame=0, over=0, crc=0
tx pkts=0, bytes=0, drop=0, errs=0, coll=0
port "phy-br-ex": rx pkts=686453911, bytes=82621458335, drop=?, errs=?, frame=?, over=?, crc=?
tx pkts=753260802, bytes=199193981141, drop=?, errs=?, coll=?
출력 결과를 간략히 설명 하자면,
물리 네트워크에서 들어오는 패킷이 물리포트를 거쳐 phy-br-ex
로 수신된 것을 확인 할 수 있습니다.
OVS의 connection tracking을 사용하여 패킷 흐름을 확인해 보겠습니다.
# ovs-appctl dpctl/dump-conntrack | grep "10.251.0.99"
icmp,orig=(src=10.251.2.140,dst=10.251.0.99,id=11687,type=8,code=0),reply=(src=10.251.0.99,dst=10.251.2.140,id=11687,type=0,code=0),zone=4240
이 출력은 10.251.2.140에서 10.251.0.99로 전송된 ICMP 패킷과 그에 대한 응답 패킷을 보여줍니다.
qvo7e00f86b-db 포트에서 수신한 패킷 정보를 확인해 보겠습니다.
# ovs-ofctl dump-flows br-int in_port="qvo7e00f86b-db"
cookie=0xa9f9df3dd86e479b, duration=136223.963s, table=0, n_packets=0, n_bytes=0, priority=10,icmp6,in_port="qvo7e00f86b-db",icmp_type=136 actions=resubmit(,24)
cookie=0xa9f9df3dd86e479b, duration=136223.961s, table=0, n_packets=13160, n_bytes=552720, priority=10,arp,in_port="qvo7e00f86b-db" actions=resubmit(,24)
cookie=0xa9f9df3dd86e479b, duration=136223.966s, table=0, n_packets=24510, n_bytes=2349641, priority=9,in_port="qvo7e00f86b-db" actions=resubmit(,25)
cookie=0xa9f9df3dd86e479b, duration=136223.964s, table=24, n_packets=0, n_bytes=0, priority=2,icmp6,in_port="qvo7e00f86b-db",icmp_type=136,nd_target=fe80::f816:3eff:fe53:4540 actions=resubmit(,59)
cookie=0xa9f9df3dd86e479b, duration=136223.962s, table=24, n_packets=3885, n_bytes=163170, priority=2,arp,in_port="qvo7e00f86b-db",arp_spa=10.251.0.99 actions=resubmit(,25)
cookie=0xa9f9df3dd86e479b, duration=136223.973s, table=25, n_packets=37511, n_bytes=2891919, priority=2,in_port="qvo7e00f86b-db",dl_src=fa:16:3e:53:45:40 actions=resubmit(,30)
이 출력은 qvo7e00f86b-db
포트로 들어오는 패킷이 br-int 브리지의 OpenFlow 테이블에서 어떻게 처리되는지 보여줍니다. 각 플로우 엔트리는 패킷 유형과 조건에 따라 다른 테이블로 리서브밋(resubmit)하도록 설정되어 있습니다.
이를 통해 qvo7e00f86b-db
포트에서 수신한 패킷이 OVS Integration Bridge를 거쳐 최종적으로 Linux Bridge로 전달되는 과정을 확인할 수 있습니다.
먼저 ICMP 에코 요청/응답 패킷을 보면,
# tcpdump -i tap7e00f86b-db -n -e
fa:16:3e:11:ba:24 > fa:16:3e:53:45:40, ethertype IPv4 (0x0800), length 98: 10.251.2.140 > 10.251.0.99: ICMP echo request, id 11687, seq 716, length 64
fa:16:3e:53:45:40 > fa:16:3e:11:ba:24, ethertype IPv4 (0x0800), length 98: 10.251.0.99 > 10.251.2.140: ICMP echo reply, id 11687, seq 716, length 64
# tcpdump -i qbr7e00f86b-db -n -e
fa:16:3e:11:ba:24 > fa:16:3e:53:45:40, ethertype IPv4 (0x0800), length 98: 10.251.2.140 > 10.251.0.99: ICMP echo request, id 11687, seq 791, length 64
fa:16:3e:53:45:40 > fa:16:3e:11:ba:24, ethertype IPv4 (0x0800), length 98: 10.251.0.99 > 10.251.2.140: ICMP echo reply, id 11687, seq 791, length 64
# tcpdump -i qvo7e00f86b-db -n -e
fa:16:3e:11:ba:24 > fa:16:3e:53:45:40, ethertype IPv4 (0x0800), length 98: 10.251.2.140 > 10.251.0.99: ICMP echo request, id 11687, seq 858, length 64
fa:16:3e:53:45:40 > fa:16:3e:11:ba:24, ethertype IPv4 (0x0800), length 98: 10.251.0.99 > 10.251.2.140: ICMP echo reply, id 11687, seq 858, length 64
그리고 ARP 요청 패킷도 마찬가지로,
fa:16:3e:11:ba:24 > fa:16:3e:53:45:40, ethertype ARP (0x0806), length 42: Request who-has 10.251.0.99 tell 10.251.2.140, length 28
fa:16:3e:53:45:40 > fa:16:3e:11:ba:24, ethertype ARP (0x0806), length 42: Reply 10.251.0.99 is-at fa:16:3e:53:45:40, length 28
fa:16:3e:11:ba:24 > fa:16:3e:53:45:40, ethertype ARP (0x0806), length 42: Request who-has 10.251.0.99 tell 10.251.2.140, length 28
fa:16:3e:53:45:40 > fa:16:3e:11:ba:24, ethertype ARP (0x0806), length 42: Reply 10.251.0.99 is-at fa:16:3e:53:45:40, length 28
Linux Bridge 에서 VM2 까지 네트워크 패킷을 수신 하고 있음을 확인할 수 있습니다.
OpenStack OpenVSwitch(OVS) 환경에서 가상머신에서 나온 패킷은 다음과 같은 흐름으로 전달됩니다:
tap 인터페이스 → Linux 브리지(qbr) → qvb/qvo 인터페이스 → OVS 브리지(br-int 등)
패킷은 OVS의 플로우 테이블과 OpenFlow 규칙에 따라 경로가 결정됩니다. 반대로 외부에서 들어온 패킷은 OVS br-ex 브리지를 통해 qvo/qvb 인터페이스와 Linux 브리지를 거쳐 최종 목적지 VM에 전달됩니다. 이를 통해 OVS는 가상머신 간 네트워크 연결 및 트래픽 제어를 수행합니다.
이 과정을 통해 OpenStack의 서로 다른 컴퓨트 노드에 있는 인스턴스 간의 East/West 네트워크 트래픽 흐름을 확인할 수 있었습니다.
OVS에서 제공하는 다양한 도구를 활용하면 더욱 자세한 네트워크 흐름 분석이 가능할 것입니다.
더 궁금한 내용이 있다면 아래 글도 함께 확인해 보세요:)